{{- $tag := .Chart.AppVersion -}} {{- with .Values.image.variant }}{{ $tag = printf "%s-%s" $tag . }}{{ end -}} apiVersion: apps/v1 kind: Deployment metadata: name: {{ .Release.Name }} labels: app.kubernetes.io/name: {{ .Chart.Name }} app.kubernetes.io/instance: {{ .Release.Name }} app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} app.kubernetes.io/component: gateway annotations: version-source: {{ index .Chart.Annotations "version-source" }} spec: replicas: 1 strategy: type: Recreate selector: matchLabels: app: {{ .Release.Name }} template: metadata: labels: app: {{ .Release.Name }} annotations: checksum/seed: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} spec: automountServiceAccountToken: false {{- with .Values.securityContext }} securityContext: {{- toYaml . | nindent 8 }} {{- end }} {{- with .Values.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} {{- end }} {{- with .Values.tolerations }} tolerations: {{- toYaml . | nindent 8 }} {{- end }} {{- with .Values.affinity }} affinity: {{- toYaml . | nindent 8 }} {{- end }} initContainers: # Seed-if-missing: the PVC copy owns config after first boot - name: seed-config image: busybox:1.38 imagePullPolicy: IfNotPresent command: - sh - -c - | [ -f /home/node/.openclaw/openclaw.json ] || cp /seed/openclaw.json /home/node/.openclaw/openclaw.json mkdir -p /home/node/.openclaw/workspace [ -f /home/node/.openclaw/workspace/AGENTS.md ] || cp /seed/AGENTS.md /home/node/.openclaw/workspace/AGENTS.md {{- with .Values.containerSecurityContext }} securityContext: {{- toYaml . | nindent 12 }} {{- end }} resources: requests: cpu: 10m memory: 16Mi limits: cpu: 100m memory: 64Mi volumeMounts: - name: data mountPath: /home/node/.openclaw - name: seed mountPath: /seed containers: - name: {{ .Chart.Name }} image: "{{ .Values.image.repository }}:{{ $tag }}" imagePullPolicy: {{ .Values.image.pullPolicy }} command: - node - /app/dist/index.js - gateway - run {{- with .Values.containerSecurityContext }} securityContext: {{- toYaml . | nindent 12 }} {{- end }} ports: - containerPort: {{ .Values.httpPort }} name: http env: - name: TZ value: {{ .Values.timezone | quote }} - name: HOME value: /home/node - name: OPENCLAW_CONFIG_DIR value: /home/node/.openclaw - name: NODE_ENV value: production {{- range $key, $value := .Values.env }} - name: {{ $key }} value: {{ $value | quote }} {{- end }} {{- with .Values.existingSecret }} envFrom: - secretRef: name: {{ . }} {{- end }} resources: {{- toYaml .Values.resources | nindent 12 }} # Probes assert the JSON probe contract, not just the status code: the # Control UI answers unknown paths with a catch-all 200. /startupz # ignores channel health, so one failing channel account can't pull # the Gateway out of Service endpoints (/readyz is channel-aware). startupProbe: exec: command: - node - -e - "require('http').get('http://127.0.0.1:{{ .Values.httpPort }}/startupz', r => { let b = ''; r.on('data', d => b += d); r.on('end', () => { try { process.exit(r.statusCode < 400 && JSON.parse(b).status === 'started' ? 0 : 1); } catch { process.exit(1); } }); }).on('error', () => process.exit(1))" periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 30 readinessProbe: exec: command: - node - -e - "require('http').get('http://127.0.0.1:{{ .Values.httpPort }}/startupz', r => { let b = ''; r.on('data', d => b += d); r.on('end', () => { try { process.exit(r.statusCode < 400 && JSON.parse(b).status === 'started' ? 0 : 1); } catch { process.exit(1); } }); }).on('error', () => process.exit(1))" periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 3 livenessProbe: exec: command: - node - -e - "require('http').get('http://127.0.0.1:{{ .Values.httpPort }}/healthz', r => { let b = ''; r.on('data', d => b += d); r.on('end', () => { try { process.exit(r.statusCode < 400 && JSON.parse(b).ok === true ? 0 : 1); } catch { process.exit(1); } }); }).on('error', () => process.exit(1))" periodSeconds: 30 timeoutSeconds: 10 failureThreshold: 3 volumeMounts: - name: data mountPath: /home/node/.openclaw - name: tmp mountPath: /tmp - name: shm mountPath: /dev/shm volumes: - name: data {{- if .Values.persistence.enabled }} persistentVolumeClaim: claimName: {{ .Values.persistence.existingClaim | default (printf "%s-data" .Release.Name) }} {{- else }} emptyDir: {} {{- end }} - name: seed configMap: name: {{ .Release.Name }}-seed - name: tmp emptyDir: {} - name: shm emptyDir: medium: Memory sizeLimit: {{ .Values.shmSize }}