Run devbox with Helm
The chart runs devbox as a one-replica StatefulSet whose volume
claim keeps /workspace across restarts and upgrades.
- Images
- GHCR
ghcr.io/hambn/devbox - Docker Hub
docker.io/hambn/devbox
- GHCR
- Use case
- Long-running cluster pod with a persistent workspace
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 -lTo use a larger workspace, set its size when you install:
Shell
helm install devbox ./chart --set workspace.size=20GiKubernetes 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-fullValues
| 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
chart/Chart.yamlholds the chart metadata.chart/values.yamlholds the defaults above.chart/templates/statefulset.yamldefines the StatefulSet and its volume claim.
Cleanup
Uninstalling leaves the volume claim. Delete it to remove the workspace:
Shell
helm uninstall devbox
kubectl delete pvc workspace-devbox-0File 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: 4Gichart/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 }}