Your first tenant¶
Three doors into the same room: the portal, the CLI and kubectl all create
the same Tenant custom resource, and the operator does the same work
regardless of which one you used.
kubespaces login --server https://kubespaces.example.com
# opens the OIDC device flow in your browser
kubespaces tenant create team-atlas --cpu 8 --memory 16Gi
kubespaces tenant get team-atlas --wait
# NAME PHASE API
# team-atlas Ready https://team-atlas.api.example.com:443
kubespaces tenant kubeconfig team-atlas --merge
kubectl config use-context team-atlas
kubectl get nodes
Log in, hit New tenant, pick a name and quota, watch the status go
Pending → Provisioning → Ready, then download the kubeconfig from the
tenant page.
apiVersion: kubespaces.io/v1alpha1
kind: Tenant
metadata:
name: team-atlas
spec:
owner: alice@example.com
resources:
cpu: "8"
memory: 16Gi
storage: 50Gi
Apply it, commit it to your Flux/Argo repository, template it per team — the CR is the source of truth, so GitOps is not a workaround, it is the design. Field reference: Tenant CRD.
What just happened¶
For every Tenant the operator created, on the host cluster:
- a namespace (
kubespaces-tenant-<name>) labeled with the tenant name - a ResourceQuota from
spec.resourcesand a LimitRange with sane container defaults (so pods without explicit limits still schedule) - a vCluster — the tenant's own control plane — installed from the pinned KubeSpaces chart mirror
- with exposure configured: a TLSRoute for the API server, an apps listener + certificate, and public URLs in the Tenant status
Inside the tenant you are cluster-admin. On the host you own exactly one namespace, capped by the quota — that asymmetry is the entire point.
Day-2¶
kubespaces tenant list # everything you own
kubectl get tenant team-atlas -o yaml # status: phase, endpoints, conditions
kubespaces tenant delete team-atlas # full teardown via finalizer
Deletion removes the vCluster, routes, certificates and namespace — nothing orphaned, verified by the E2E suite.
Next¶
- Exposing apps — from
kubectl applyinside your tenant to a public HTTPS URL - Tenant lifecycle — phases, conditions and what the operator reconciles