apiVersion: apps/v1 kind: Deployment metadata: name: {{ include "zddc-server.fullname" . }} labels: {{- include "zddc-server.labels" . | nindent 4 }} spec: replicas: {{ .Values.replicaCount }} selector: matchLabels: {{- include "zddc-server.selectorLabels" . | nindent 6 }} template: metadata: labels: {{- include "zddc-server.selectorLabels" . | nindent 8 }} spec: {{- with .Values.imagePullSecrets }} imagePullSecrets: {{- toYaml . | nindent 8 }} {{- end }} volumes: - name: zddc-bin emptyDir: {} - name: data persistentVolumeClaim: claimName: {{ .Values.data.pvcName }} initContainers: # Build zddc-server from the pinned git ref. The static binary # lands in the shared zddc-bin volume that the main container # mounts. No image pull from a custom registry — the build # image is golang upstream + the runtime image is alpine. - name: build-zddc-server image: {{ printf "%s:%s" .Values.buildImage.repository .Values.buildImage.tag | quote }} imagePullPolicy: IfNotPresent command: ["/bin/sh", "-c"] args: - | set -eu apk add --no-cache git git clone --depth 1 --branch "$GIT_REF" "$GIT_REPO" /workspace cd /workspace/zddc CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \ go build -trimpath \ -ldflags="-s -w -X main.version=$GIT_REF" \ -o /out/zddc-server \ ./cmd/zddc-server echo "built /out/zddc-server from $GIT_REF" env: - name: GIT_REPO value: {{ .Values.zddc.gitRepo | quote }} - name: GIT_REF value: {{ .Values.zddc.gitRef | quote }} volumeMounts: - name: zddc-bin mountPath: /out resources: requests: cpu: 200m memory: 256Mi limits: cpu: 1000m memory: 512Mi containers: - name: zddc-server image: {{ printf "%s:%s" .Values.runtimeImage.repository .Values.runtimeImage.tag | quote }} imagePullPolicy: IfNotPresent # zddc-cgroup-init prepares cgroup v2 subtree_control then # exec's zddc-server. Required because cgroup v2 forbids # processes in a cgroup that has child cgroups; the per- # conversion wrapper (zddc-sandbox-exec) creates child # cgroups for resource caps, so the init script has to # move zddc-server itself out of the root cgroup first. # See zddc/runtime/zddc-cgroup-init in the source repo. command: ["/usr/local/libexec/zddc-cgroup-init", "/zddc/zddc-server"] # The conversion sandbox (bwrap, invoked per-call by # /usr/local/bin/{pandoc,chromium-browser}) needs to create # user + mount namespaces inside the container. Pod Security # Standards default policies forbid this; the chart sets the # minimum securityContext that lets bwrap function. If your # cluster's admission controller rejects these settings, you # have two choices: ask the platform team to allow this pod, # or accept that /.convert serves 503 (the rest of zddc- # server still works fine without conversion). securityContext: capabilities: add: ["SYS_ADMIN"] # cap-add SYS_ADMIN alone isn't enough — see the # zddc/runtime/zddc-sandbox-exec docstring for the full # set of LSM relaxations required. K8s 1.30+ supports # specifying seccompProfile + appArmorProfile fields; # if your cluster is older, you'll need annotations: # container.apparmor.security.beta.kubernetes.io/zddc-server: unconfined seccompProfile: type: Unconfined appArmorProfile: type: Unconfined ports: - name: http containerPort: 8080 protocol: TCP env: - name: ZDDC_ROOT value: {{ .Values.zddc.env.rootPath | quote }} - name: ZDDC_ADDR value: {{ .Values.zddc.env.addr | quote }} - name: ZDDC_TLS_CERT value: "none" - name: ZDDC_INSECURE_DIRECT value: "1" - name: ZDDC_EMAIL_HEADER value: {{ .Values.zddc.env.emailHeader | quote }} - name: ZDDC_CORS_ORIGIN value: {{ .Values.zddc.env.corsOrigin | quote }} - name: ZDDC_LOG_LEVEL value: {{ .Values.zddc.env.logLevel | quote }} - name: ZDDC_INDEX_PATH value: {{ .Values.zddc.env.indexPath | quote }} {{- if .Values.zddc.env.noAuth }} - name: ZDDC_NO_AUTH value: "1" {{- end }} volumeMounts: - name: zddc-bin mountPath: /zddc - name: data mountPath: {{ .Values.zddc.env.rootPath }} {{- with .Values.data.subPath }} subPath: {{ . | quote }} {{- end }} resources: {{- toYaml .Values.resources | nindent 12 }} livenessProbe: httpGet: path: / port: http initialDelaySeconds: 5 periodSeconds: 30 timeoutSeconds: 5 readinessProbe: httpGet: path: / port: http initialDelaySeconds: 2 periodSeconds: 10 timeoutSeconds: 3