OBLETHdocs

Enable workspaces

Workspaces and each person's browser come with Chat's Kubernetes manifest. Choose who gets them, add gVisor and previews, and set the limits.

4 min readUpdated for Chat 0.5.2Edit on GitHub

You needKubernetes
Chat's accessPods, exec and volumes in its namespace
Default accessAdministrators only
RecommendedgVisor

Chat starts each person's workspace as a pod and a volume, runs commands in it through the Kubernetes API and proxies its preview. With deploy/k8s.yaml from the Kubernetes install, there is nothing more to set up. The manifest gives Chat a ServiceAccount and a Role for pods, exec and volumes in its own namespace, plus NetworkPolicies so that only Chat reaches those pods and they reach only DNS and public HTTP and HTTPS addresses. The namespace enforces Pod Security restricted, so the API server refuses privileged, root or host-network pods there.

NetworkPolicies only take effect if your cluster's network plugin enforces them. Calico, Cilium and k3s's built-in policy controller do; Flannel on its own doesn't, and some managed clusters need policy enforcement turned on. Without it, workspace pods can reach anything the cluster network can.

Administrators see Compute › Workspaces, a chat can get a workspace, and projects get a Research tab. Chat checks its permissions when it starts; Settings › Administration › System shows whether workspaces are on and, if they are off, why.

To leave workspaces out, set OBLETH_CHAT_WORKSPACES=off. Outside a cluster, Chat reaches the API server with OBLETH_CHAT_KUBE_API, OBLETH_CHAT_KUBE_TOKEN_FILE and OBLETH_CHAT_KUBE_CA_FILE and a namespace from OBLETH_CHAT_SANDBOX_NAMESPACE, for local development.

Run workspaces under gVisor

gVisor runs each pod against its own user-space kernel, so code in a workspace never talks to the node's kernel directly. It is set up per node.

  1. 1

    Install gVisor on the nodes for workspaces

    Install runsc and containerd-shim-runsc-v1 and add the runsc runtime to containerd, as in gVisor's containerd guide. Label those nodes, for example gvisor=installed.

  2. 2

    Add a RuntimeClass

    apiVersion: node.k8s.io/v1
    kind: RuntimeClass
    metadata:
      name: gvisor
    handler: runsc
    scheduling:
      nodeSelector:
        gvisor: installed
    
  3. 3

    Point Chat at it

    Set OBLETH_CHAT_SANDBOX_RUNTIME_CLASS=gvisor and restart Chat. Workspace and browser pods then start only on the labelled nodes. Their volumes must be able to attach there, so pick a StorageClass that reaches those nodes (OBLETH_CHAT_SANDBOX_STORAGE_CLASS).

Add previews

A workspace's apps open in its Preview tab, served at <id>.<domain>. Without a preview domain everything else works: workspaces, the terminal, files, code and the browser.

Create a wildcard DNS record and a wildcard certificate for the domain, route it to Chat through your ingress, and set OBLETH_CHAT_PREVIEW_DOMAIN. The domain must not contain Chat's own origin.

Only Chat's own page can open a preview, and preview access lasts as long as the sign-in it came from: signing out, a revoked session, a disabled account or lost workspace access ends it within seconds. The preview cookie lasts an hour, renewed while the person is signed in.

OBLETH_CHAT_PREVIEW_DOMAIN=sbx.example.edu

Keep workspaces in their own namespace

deploy/k8s-workspaces.yaml creates an obleth-sandboxes namespace with the same Role for Chat's ServiceAccount, a ResourceQuota and default-deny NetworkPolicies. Apply it after deploy/k8s.yaml, then set OBLETH_CHAT_SANDBOX_NAMESPACE=obleth-sandboxes.

Settings

VariableDefaultMeaning
OBLETH_CHAT_WORKSPACESautooff turns workspaces and the browser off
OBLETH_CHAT_SANDBOX_ACCESSadminsadmins or everyone
OBLETH_CHAT_SANDBOX_NAMESPACEChat's namespaceWhere workspace and browser pods run
OBLETH_CHAT_SANDBOX_IMAGEthis release's workspace imageThe workspace image; pin it by digest in production
OBLETH_CHAT_SANDBOX_SLOTS8Most workspace and browser pods running at once
OBLETH_CHAT_SANDBOX_RUNTIME_CLASSunsetRuntimeClass for workspace and browser pods, such as gvisor
OBLETH_CHAT_SANDBOX_STORAGE_CLASScluster defaultStorageClass for each person's volume
OBLETH_CHAT_SANDBOX_STORAGE10GiVolume size, and the disk cap Chat enforces
OBLETH_CHAT_SANDBOX_CPU2CPU limit per pod
OBLETH_CHAT_SANDBOX_MEMORY4GiMemory limit per pod
OBLETH_CHAT_SANDBOX_IDLE_MINUTES60Stop an idle pod; its files are kept
OBLETH_CHAT_SANDBOX_RETENTION_MINUTES10080Delete a volume this long after its last use (7 days)
OBLETH_CHAT_PREVIEW_DOMAINunsetWildcard domain for previews; unset, workspaces run without previews
How workspaces use the cluster

Each person has one pod and one volume. Each chat with a workspace is a folder /workspace/<preview id> in it, with its own dev server port from 3000 up. Each running workspace or browser takes one of OBLETH_CHAT_SANDBOX_SLOTS; when all are in use, new ones report that slots are busy. A ResourceQuota in the namespace limits them too.

Some volume types, such as local-path, don't enforce their size. Chat measures each running workspace every five minutes and refuses file writes from the model above the volume size. Commands still run, so files can be deleted.

Chat's pods and volumes carry the label app.kubernetes.io/managed-by=obleth-chat. Those without a matching record in Chat's database are deleted within a minute; nothing else in the namespace is touched.

Each release publishes the workspace image as ghcr.io/thediymaker/obleth-chat/workspace and the browser as ghcr.io/thediymaker/obleth-chat/browser, for amd64 and arm64. The workspace image, deploy/sandbox/Dockerfile, has Node.js, Python with numpy, pandas, matplotlib, scipy, scikit-learn, pytest, JupyterLab, Flask, FastAPI and uv, Rust, Go, gcc, git, and Vite and Next.js starters. Build your own from it and set OBLETH_CHAT_SANDBOX_IMAGE to add tools.

If your cluster limits Chat's own egress, allow it to reach the Kubernetes API and the workspace and browser pods.

The browser

With workspaces on, each person also gets a browser: a headless Chromium in a second pod with a small volume for its profile, in the same namespace and under the same access rule (OBLETH_CHAT_SANDBOX_ACCESS). Browser pods carry the workspace labels, so the same NetworkPolicies apply: only Chat connects (to DevTools on port 9222), and they reach only public HTTP and HTTPS addresses.

VariableDefaultMeaning
OBLETH_CHAT_BROWSERonoff leaves the browser out
OBLETH_CHAT_BROWSER_IMAGEthis release's browser imageThe browser image, from deploy/browser/Dockerfile; pin it by digest in production
OBLETH_CHAT_BROWSER_MEMORY1GiMemory limit per browser
OBLETH_CHAT_BROWSER_CPU1CPU limit per browser
OBLETH_CHAT_BROWSER_STORAGE1GiProfile volume size
OBLETH_CHAT_BROWSER_IDLE_MINUTES15Stop an idle browser; its sign-ins are kept

A browser's profile volume is deleted after the workspace retention (OBLETH_CHAT_SANDBOX_RETENTION_MINUTES) without use.