Skip to content
KubeCell logoKubeCell

Getting started

Create your first VirtualCluster

This guide assumes a Ready Cell and an existing quota tier. If you have not onboarded a host yet, start with host onboarding.

Before you start

  • The target Cell is Ready: OCM Joined=True, a fresh managed-cluster-lease, and fresh inventory.
  • The quota tier (VirtualNodeClass) you intend to use already exists.
  • You are applying into kubecell-system on the management cluster, where the controller lives.

1. Inspect the Cell before requesting anything

Feasibility conclusions are only as good as the inventory they read. Check freshness first, then look at headroom.

inspect.sh
kubectl-n kubecell-system get cell cell1 -o yaml | less# Things to look at in status:#   conditions        -> InventoryFresh must be true#   nodes[]           -> per-node capacity, allocatable, active/pending requests#   inventory         -> aggregated available estimates per resource#   storageInventory  -> freeCapacityKnown and freshness

Stop if inventory is stale

If InventoryFresh is false or key inventory is unknown, do not create anything. Contact operations; no feasibility conclusion is trustworthy at that point.

2. Preflight with a Plan

Write a VirtualClusterPlan with exactly the content you intend to create. Wait for status.decision and read checks when it is rejected.

plan.yaml
apiVersion: kubecell.io/v1alpha1kind: VirtualClusterPlanmetadata:  name: child-dev-plan  namespace: kubecell-systemspec:  cellRef: {name: cell1}  classRef: {name: ascend-910b-small}
decision.sh
kubectl apply-f plan.yamlkubectl-n kubecell-system get vcp child-dev-plan \  -o jsonpath='{.status.decision}{"\n"}'# Rejected? Read the failed items and adjust the request or the Cell.kubectl-n kubecell-system get vcp child-dev-plan \  -o jsonpath='{range .status.checks[*]}{.resource}{"\t"}{.result}{"\n"}{end}'

Accepted means buildable under the current snapshot; Rejected means a specific resource is missing; Unknown means the inventory was insufficient to decide. Remember that acceptance is not reservation: the controller rechecks at creation time.

3. Create the VirtualCluster

The Plan and the VirtualCluster are isomorphic — the same file with a different kind. The webhook validates that references exist and quota keys are legal.

virtualcluster.yaml
apiVersion: kubecell.io/v1alpha1kind: VirtualClustermetadata:  name: child-dev  namespace: kubecell-systemspec:  cellRef: {name: cell1}  classRef: {name: ascend-910b-small}
wait.sh
kubectl apply-f virtualcluster.yaml# The first Ready transition typically takes 10-20 minutes (image pulls).kubectl-n kubecell-system wait --for=condition=Ready vc/child-dev --timeout=25mkubectl-n kubecell-system get vc child-dev -o wide

4. Fetch the admin kubeconfig

The controller reads the K3k-generated kubeconfig through the OCM proxy, rewrites the server address to the discovered host address and NodePort, and publishes it as a Secret in the management plane. The Secret is always published; treat it as a credential.

kubeconfig.sh
VC=child-dev# The Secret name embeds the VirtualCluster UIDSECRET=$(kubectl-n kubecell-system get vc $VC \  -o jsonpath='{.status.credential.secretName}')kubectl-n kubecell-system get secret "$SECRET" \  -o jsonpath='{.data.kubeconfig\.yaml}' | base64 -d > $VC.yamlchmod600 $VC.yamlkubectl--kubeconfig $VC.yaml get nodeskubectl--kubeconfig $VC.yaml get ns

5. Verify workloads, storage, and ingress

workload.sh
cat<<'EOF' | kubectl --kubeconfig child-dev.yaml apply -f -apiVersion: v1kind: Podmetadata:    name: cpu-smokespec:    containers:    - name: app        image: registry.k8s.io/pause:3.10        resources:            requests: {cpu: 100m, memory: 128Mi}            limits: {cpu: 200m, memory: 256Mi}EOF# Confirm the reflected host Pod and quota accountingkubectl-n kubecell-system get vc child-dev \  -o jsonpath='{.status.host.quotaUsed}{"\n"}'
  • The child cluster has exactly one node named kubelet.
  • A child PVC becomes a host PVC backed by TopoLVM; check that it binds, not just that it is created.
  • hostPath volumes are rejected at admission with a replacement hint — this is expected behavior, not a bug.
  • Ingress: create a standard Ingress with class kubecell in the child cluster, then reach it at http://<ingress>.<vc>.apps.example.com.

6. Delete it cleanly

delete.sh
kubectl-n kubecell-system delete vc child-dev# The finalizer removes both ManifestWorks by UID, which removes the host# namespace, quota, policy, and the K3k cluster. Under Retain, PVs become# Released and data is preserved.

Next: day-2 operations, or jump to the troubleshooting guide if something is not Ready.