Skip to main content
Version: 1.0

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:

PhaseMeaning
PendingReconciliation hasn't started yet
ProvisioningRunning the vCluster Helm install
InstallingFluxvCluster is up; Flux is being installed/verified healthy inside it
ReadyvCluster (and Flux, once that's wired into every environment) is healthy
FailedProvisioning hit an error
DeletingTeardown 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 Tenant CR quota field)
  • 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.

NamespaceCloudSpace
Kubernetes APIShared with hostIndependent
API serverSameSeparate pod
etcdSharedSeparate
RBAC isolationPartial (cluster-wide resources are shared)Complete
Use caseResource grouping within a clusterFull tenant isolation