tool-containers
Menu
GitHub (opens in new tab)

Run devbox with Helm

The chart runs devbox as a one-replica StatefulSet whose volume claim keeps /workspace across restarts and upgrades.

Images
  • GHCRghcr.io/hambn/devbox
  • Docker Hubdocker.io/hambn/devbox
Use case
Long-running cluster pod with a persistent workspace
Source
tools/base/devbox/docs/helm (opens in new tab)
On this page

Prerequisites

  • A Kubernetes cluster with a default StorageClass, or set workspace.storageClassName.
  • Helm 3 or later.

Open a shell

Shell
helm install devbox ./chart
kubectl exec -it devbox-0 -- zsh -l

To use a larger workspace, set its size when you install:

Shell
helm install devbox ./chart --set workspace.size=20Gi

Kubernetes does not let an upgrade change a StatefulSet's volume claim template, so change only the image on an existing release:

Shell
helm upgrade devbox ./chart --reuse-values --set image.tag=alpine-full

Values

Value Default Purpose
image.tag ubuntu-full Any variant.
workspace.size 10Gi Size of the /workspace claim.
workspace.storageClassName cluster default StorageClass for the claim.
resources 250m and 512Mi requested, 2 CPUs and 4Gi limit Container resources.

Workspace

The pod runs as UID 1000 with every capability dropped and allowPrivilegeEscalation: false, so sudo and ping fail. It runs no Docker daemon.

Files

Cleanup

Uninstalling leaves the volume claim. Delete it to remove the workspace:

Shell
helm uninstall devbox
kubectl delete pvc workspace-devbox-0

File contents

chart/Chart.yaml6 lines
apiVersion: v2
name: devbox
description: Long-running devbox development pod
type: application
version: 0.2.0
appVersion: "ubuntu-full"
chart/values.yaml16 lines
image:
  repository: ghcr.io/hambn/devbox
  tag: ubuntu-full
  pullPolicy: Always

workspace:
  size: 10Gi
  storageClassName: ""

resources:
  requests:
    cpu: 250m
    memory: 512Mi
  limits:
    cpu: "2"
    memory: 4Gi
chart/templates/statefulset.yaml53 lines
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: {{ .Release.Name }}
  labels:
    app.kubernetes.io/name: devbox
    app.kubernetes.io/instance: {{ .Release.Name }}
spec:
  replicas: 1
  serviceName: {{ .Release.Name }}
  selector:
    matchLabels:
      app.kubernetes.io/name: devbox
      app.kubernetes.io/instance: {{ .Release.Name }}
  template:
    metadata:
      labels:
        app.kubernetes.io/name: devbox
        app.kubernetes.io/instance: {{ .Release.Name }}
    spec:
      securityContext:
        runAsNonRoot: true
        runAsUser: 1000
        runAsGroup: 1000
        fsGroup: 1000
        seccompProfile:
          type: RuntimeDefault
      containers:
        - name: devbox
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          command: ["sleep", "infinity"]
          workingDir: /workspace
          securityContext:
            allowPrivilegeEscalation: false
            capabilities:
              drop: ["ALL"]
          resources:
            {{- toYaml .Values.resources | nindent 12 }}
          volumeMounts:
            - name: workspace
              mountPath: /workspace
  volumeClaimTemplates:
    - metadata:
        name: workspace
      spec:
        accessModes: ["ReadWriteOnce"]
        {{- with .Values.workspace.storageClassName }}
        storageClassName: {{ . }}
        {{- end }}
        resources:
          requests:
            storage: {{ .Values.workspace.size }}

Topics