Installation
Kube Workspaces can be deployed to any Kubernetes cluster using four supported methods: a local kind cluster for development, and Kustomize, Helm, or ArgoCD for production. Every method deploys the same published images and CRDs — pick the one that matches how you manage the rest of your cluster.
All installs below deploy without authentication (it is opt-in and off by
default). See Authentication to enable OIDC or local auth
after deploying. Before going to production, set your own hostnames — the
manifests use the placeholder domain workspaces.example.com, which is not
issued by real ACME providers; see Customizing your domain.
Prerequisites
-
kubectlwith access to your target cluster -
kind— only for the local cluster method -
helm3.8+ — only for the Helm method
No images need to be built: the manifests reference the published
ghcr.io/kube-workspaces/* images.
Optional — VM workspaces. spec.type: vm requires
KubeVirt to be installed in the cluster first (it is not
bundled). On a local/kind cluster without nested virtualization, enable
software emulation in the KubeVirt CR (spec.configuration.developerConfiguration.useEmulation: true).
The controller detects the KubeVirt CRDs and reports a KubeVirtNotInstalled
status condition on any vm workspace created without them; container and
scratch workspaces work regardless.
CRDs must use server-side apply. The
WorkspaceCRD embeds a full KubernetesPodSpecand is ~658 KiB, far over the 256 KiBlast-applied-configurationannotation limit. Plainkubectl apply -ffails on it — every method below applies the CRDs with--server-side(or its ArgoCD equivalent).
Local cluster (kind)
Deploy to a throwaway local cluster for development:
kind create cluster
make install-crd # CRDs (server-side apply)
make deploy-kustomize # components
make install-images # workspace image catalog
make port-forward-frontend # UI on localhost:3000
Open http://localhost:3000. No login is required.
The Ingress in kustomize/base hardcodes ingressClassName: traefik and a
placeholder hostname, so it is inert on a default kind cluster —
port-forwarding is the only way in.
To tear everything down:
kind delete cluster
Kustomize
Apply the CRDs first, then the components. Both must use server-side apply:
kubectl apply --server-side -k kustomize/crds/
kubectl apply --server-side -k kustomize/base/
kustomize/base does not create any Image CRs — without the catalog the
UI is empty. Install it separately:
kubectl apply --server-side -f images.yaml # or: make install-images
Set your own hostnames with a kustomize overlay before going to production — see Customizing your domain.
Helm
The chart ships the CRDs and, by default, a curated catalog of example images
(including Alpine and Debian VM images for spec.type: vm).
From the published chart, without cloning this repository:
helm install kube-workspaces \
oci://ghcr.io/kube-workspaces/charts/kube-workspaces \
--namespace kube-workspaces-system --create-namespace
From this repository:
helm install kube-workspaces helm/kube-workspaces/ \
--namespace kube-workspaces-system --create-namespace
Workspace images
| Setting | Default | Effect |
|---|---|---|
installExampleImages |
true |
Curated set of example images (incl. Alpine + Debian VMs) |
installCatalogImages |
false |
Install the full vendored catalog instead |
images |
[] |
Add your own Image CRs regardless of the catalog setting |
For example, to install the full catalog:
helm install kube-workspaces oci://ghcr.io/kube-workspaces/charts/kube-workspaces \
--namespace kube-workspaces-system --create-namespace \
--set installCatalogImages=true
Installing into an existing namespace
Installing into a namespace managed elsewhere requires disabling release namespace creation — Helm cannot adopt a namespace it did not create:
helm install kube-workspaces oci://ghcr.io/kube-workspaces/charts/kube-workspaces \
--namespace my-shared-namespace \
--set namespaces.createReleaseNamespace=false
Without this, the install fails with invalid ownership metadata. The
workspace namespace is still created; control it with
namespaces.createWorkspaceNamespace.
ArgoCD
Argo CD deploys from the git remote, so it syncs the last pushed commit rather than your local working tree.
Apply the CRDs Application first — the components Application will not sync cleanly against missing CRDs:
kubectl apply -f argocd/application-crds.yaml
kubectl apply -f argocd/application.yaml
The CRDs Application syncs with Replace=true and the components Application
with ServerSideApply=true, matching the kustomize requirements above.
Neither Application creates Image CRs (they point at kustomize/crds and
kustomize/base). To populate the UI catalog, apply images.yaml with
kubectl or via a third Application pointing at
https://github.com/kube-workspaces/deploy with images.yaml as a file source.
Verify the deployment
Every method lands in the kube-workspaces-system namespace. Confirm the CRDs
are established and all four deployments are available:
kubectl wait --for=condition=Established \
crd/workspaces.kubeworkspaces.io crd/images.kubeworkspaces.io \
crd/users.kubeworkspaces.io crd/authconfigs.kubeworkspaces.io \
crd/platformconfigs.kubeworkspaces.io crd/poddefaults.kubeworkspaces.io \
--timeout=60s
kubectl wait --for=condition=Available deployment --all \
-n kube-workspaces-system --timeout=300s
Then access the UI:
kubectl port-forward -n kube-workspaces-system svc/kube-workspaces-frontend 3000:80
Open http://localhost:3000.
Next steps
- Authentication — enable OIDC or local auth
- Customizing your domain — set your hostname and ingress before production
- Proxy — how workspace traffic is routed
- Security — what is hardened by default