Run Claude Code with Helm
The chart/ installs Claude Code as a Job that runs
claude once with the arguments in args and exits.
- Images
- GHCR
ghcr.io/hambn/claude-code - Docker Hub
docker.io/hambn/claude-code
- GHCR
- Use case
- One-shot review in a cluster from a Helm chart
On this page
Prerequisites
- Helm 3.10 or later, for
--set-json, and a Kubernetes cluster. - An Anthropic API key.
Install
Shell
kubectl create secret generic claude-code --from-literal=ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY"
helm install claude-code ./chart
kubectl logs -f job/claude-code-claude-codeSet a different prompt at install time:
Shell
helm install claude-code ./chart --set-json 'args=["-p","list the failing tests"]'Values
| Value | Default | Purpose |
|---|---|---|
image.repository |
ghcr.io/hambn/claude-code |
Image repository. |
image.tag |
ubuntu-browser |
Image tag. Use ubuntu-browser@sha256:<digest> to pin one build. |
image.pullPolicy |
Always |
Pull policy. |
args |
["-p", "review the workspace"] |
Arguments passed to claude. |
apiKeySecret |
claude-code |
Secret that holds the ANTHROPIC_API_KEY key. |
resources |
100m CPU and 256Mi requested, 1 CPU and 1Gi limit | Container resources. |
Workspace
/workspace is an empty emptyDir that is deleted with the pod. Mount your code into
it by editing the volume in chart/templates/job.yaml,
for example with a PersistentVolumeClaim or a cloning init container.
Files
chart/Chart.yamlholds the chart metadata.chart/values.yamlholds the defaults above.chart/templates/job.yamlis the non-root Job withbackoffLimit: 0.
Cleanup
Shell
helm uninstall claude-code
kubectl delete secret claude-codeA Job's pod template cannot change, so uninstall the release before installing a new run.
File contents
chart/Chart.yaml6 lines
apiVersion: v2
name: claude-code
description: Claude Code CLI as a one-shot Job
type: application
version: 0.2.0
appVersion: "2.1.282"chart/values.yaml18 lines
image:
repository: ghcr.io/hambn/claude-code
tag: ubuntu-browser
pullPolicy: Always
# Claude Code args.
args: ["-p", "review the workspace"]
# Name of an existing Secret holding key ANTHROPIC_API_KEY.
apiKeySecret: claude-code
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: "1"
memory: 1Gichart/templates/job.yaml39 lines
apiVersion: batch/v1
kind: Job
metadata:
name: {{ .Release.Name }}-claude-code
spec:
backoffLimit: 0
template:
spec:
restartPolicy: Never
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
seccompProfile:
type: RuntimeDefault
containers:
- name: claude
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
args: {{ toJson .Values.args }}
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
resources:
{{- toYaml .Values.resources | nindent 12 }}
env:
- name: ANTHROPIC_API_KEY
valueFrom:
secretKeyRef:
name: {{ .Values.apiKeySecret }}
key: ANTHROPIC_API_KEY
volumeMounts:
- name: workspace
mountPath: /workspace
volumes:
- name: workspace
emptyDir: {}