CloudSpaces
A CloudSpace is an isolated Kubernetes environment — specifically a vCluster — provisioned inside the KubeOpera host cluster. Each customer gets one default CloudSpace created automatically during onboarding, and can create additional CloudSpaces for separate environments (staging, production, team sandboxes).
What lives in a CloudSpace
Every app a customer creates in KubeOpera is deployed inside their CloudSpace. The CloudSpace provides:
- A full Kubernetes API server, scheduler, and etcd — completely separate from the host cluster and from other CloudSpaces.
- Standard Kubernetes resources: Deployments, Services, Ingresses, HPAs, ConfigMaps, Secrets, PVCs.
- An isolated DNS namespace — services are reachable within the CloudSpace but not outside unless explicitly exposed.
The host cluster provides compute (worker nodes are shared), networking infrastructure, and the control plane for the CloudSpace itself.
One thing worth being explicit about: advisor-controller and its AdvisorAgent CRD exist specifically to deploy a dedicated, per-tenant app-advisor-srv instance inside each CloudSpace's own vCluster — but nothing in the platform actually creates an AdvisorAgent CR yet, so this hasn't shipped. Today there's a single, shared app-advisor-srv instance running in the host cluster, serving every tenant. See App Advisor for the current isolation model and its known limitations.
CloudSpace states
A CloudSpace's underlying Tenant custom resource moves through these phases as tenant-controller reconciles it:
| Phase | Meaning |
|---|---|
Pending | Reconciliation hasn't started yet |
Provisioning | Running the vCluster Helm install |
InstallingFlux | vCluster is up; Flux is being installed/verified healthy inside it |
Ready | vCluster (and Flux, once that's wired into every environment) is healthy |
Failed | Provisioning hit an error |
Deleting | Teardown is in progress — see below |
Default CloudSpace
On signup, KubeOpera automatically creates one CloudSpace named space-{userId[:8]} and marks it is_default = true. This is the CloudSpace that the JWT tenant_id claim points to after the first login post-provisioning.
Managing CloudSpaces
View CloudSpaces
Customers access their CloudSpaces at /cloudspaces. Each card shows:
- Space name and UUID
- Provisioning status with a spinner if still in progress
- CPU and memory quota (configurable via
TenantCRquotafield) - Link to the app list for that CloudSpace
Create an additional CloudSpace
POST /cloudspaces
{
"space_name": "prod-eu",
"cpu": 4,
"memory": 8192
}
This is a normal, tenant-scoped self-service call — any authenticated Customer user can create a CloudSpace for their own tenant, it isn't restricted to SuperAdmins. From the UI: CloudSpaces → New Space.
Delete a CloudSpace
Deleting a CloudSpace stops the vCluster and removes all workloads running inside it. This is a destructive operation with no recovery path.
DELETE /api/v1/cloudspaces/{id}
tenant-controller fully implements the teardown as a finalizer-driven reconcile, not a manual cleanup step: deleting the Tenant CR triggers reconcileDelete, which uninstalls the vCluster's Helm release, confirms the vcluster-{tenantName} host-cluster namespace is actually gone (not just that deletion was requested), then removes the kubeconfig Secret and the CR's own finalizer. Because this is asynchronous, the delete call itself returns before cleanup finishes — the CloudSpace moves through the Deleting phase in the meantime. If namespace deletion gets stuck (for example, on a PVC finalizer), tenant-controller gives up after 15 minutes and surfaces a status that needs manual investigation — a real but uncommon edge case, not the normal path.
Kubeconfig access
The kubeconfig for each CloudSpace's vCluster is stored in the host cluster:
kubectl get secret tenant-{cloudSpaceID}-kubeconfig \
-n kubeopera-system \
-o jsonpath='{.data.kubeconfig}' | base64 -d > ./my-cloudspace.kubeconfig
kubectl --kubeconfig ./my-cloudspace.kubeconfig get pods -A
It can be downloaded via GET /api/v1/cloudspaces/{cloudSpaceId}/vclusters/{name}/kubeconfig — note this route needs both the CloudSpace ID and the specific vCluster's name, since a CloudSpace can own more than one vCluster. Access is gated by ownership verification (the caller must be able to access that CloudSpace), not restricted to a SuperAdmin role specifically.
Resource quotas
Each CloudSpace's vCluster control-plane pod has configurable CPU and memory limits set via the Tenant CR quota field:
spec:
quota:
cpu: "2" # default
memory: "4Gi" # default
These limits apply to the vCluster control-plane container. Application workloads running inside the vCluster are subject to the host cluster's node capacity. To enforce per-tenant workload limits, configure a ResourceQuota inside the vCluster namespace.
CloudSpace vs namespace
KubeOpera CloudSpaces are not Kubernetes namespaces. A namespace is a logical grouping within a single control plane. A CloudSpace is a fully independent Kubernetes control plane running inside the host cluster.
| Namespace | CloudSpace | |
|---|---|---|
| Kubernetes API | Shared with host | Independent |
| API server | Same | Separate pod |
| etcd | Shared | Separate |
| RBAC isolation | Partial (cluster-wide resources are shared) | Complete |
| Use case | Resource grouping within a cluster | Full tenant isolation |