ZDDC/helm/zddc-server-dev/templates/deployment.yaml
2026-06-11 13:32:31 -05:00

179 lines
6.9 KiB
YAML

apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "zddc-server.fullname" . }}
labels:
{{- include "zddc-server.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
# Dev: always re-pull the build image and re-clone source, so a kubectl
# rollout restart picks up new commits on the tracked ref.
strategy:
type: Recreate
selector:
matchLabels:
{{- include "zddc-server.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "zddc-server.selectorLabels" . | nindent 8 }}
annotations:
# Forces pod recreation on every helm upgrade, ensuring the init
# container re-clones the tracked ref. Useful in dev where you
# want `helm upgrade` to pick up new main HEAD without changing
# values.
zddc.varasys.io/build-time: {{ now | quote }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
volumes:
- name: zddc-bin
emptyDir: {}
# Production data volume — mounted READ-ONLY so the dev pod
# cannot corrupt prod even with a bug. Becomes the lowerdir of
# the OverlayFS mount below.
- name: data-readonly
persistentVolumeClaim:
claimName: {{ .Values.data.pvcName }}
readOnly: true
# Writable scratch for OverlayFS upperdir + workdir. emptyDir
# is ephemeral by default — dev tweaks evaporate on pod restart,
# which is usually right for a dev replica. Replace with a
# small PVC if persistence across restarts matters.
- name: overlay-scratch
emptyDir: {}
# The composed read-write view zddc-server reads from. Populated
# by the setup-overlay init container; passed through to the main
# container as ZDDC_ROOT.
- name: data
emptyDir: {}
initContainers:
# OverlayFS sandwich:
# lowerdir = /mnt/data-readonly (prod data, RO)
# upperdir = /mnt/overlay-scratch/upper
# workdir = /mnt/overlay-scratch/work
# merged = /mnt/data (what main container sees)
#
# Why this exists: dev runs against the same on-disk dataset as
# prod, but its writes (anything zddc-server writes — index
# state, form submissions during testing, .zddc edits via the
# admin page, etc.) MUST NOT mutate prod data. OverlayFS solves
# this at the filesystem layer: prod data is RO, dev's writes
# land in upperdir, the dev container sees the merged view. No
# zddc-server code change required.
#
# Requires CAP_SYS_ADMIN (the overlay mount syscall is
# privileged). Stays scoped to this one init container; the main
# container runs without elevated privs.
- name: setup-overlay
image: {{ printf "%s:%s" .Values.runtimeImage.repository .Values.runtimeImage.tag | quote }}
securityContext:
privileged: true
command: ["/bin/sh", "-c"]
args:
- |
set -eu
mkdir -p /mnt/overlay-scratch/upper /mnt/overlay-scratch/work
mount -t overlay overlay \
-o lowerdir=/mnt/data-readonly,upperdir=/mnt/overlay-scratch/upper,workdir=/mnt/overlay-scratch/work \
/mnt/data
echo "OverlayFS mounted: /mnt/data-readonly (RO) + /mnt/overlay-scratch (RW) -> /mnt/data"
ls -la /mnt/data | head -10
volumeMounts:
- name: data-readonly
mountPath: /mnt/data-readonly
readOnly: true
- name: overlay-scratch
mountPath: /mnt/overlay-scratch
- name: data
mountPath: /mnt/data
mountPropagation: Bidirectional
- name: build-zddc-server
image: {{ printf "%s:%s" .Values.buildImage.repository .Values.buildImage.tag | quote }}
imagePullPolicy: Always
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 ($(git -C /workspace rev-parse --short HEAD))"
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: 100m
memory: 128Mi
limits:
cpu: 1000m
memory: 512Mi
containers:
- name: zddc-server
image: {{ printf "%s:%s" .Values.runtimeImage.repository .Values.runtimeImage.tag | quote }}
imagePullPolicy: IfNotPresent
command: ["/zddc/zddc-server"]
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 }}
# Tighter probe cadence than prod — fail fast in dev so issues
# surface immediately during testing.
livenessProbe:
httpGet:
path: /
port: http
initialDelaySeconds: 3
periodSeconds: 10
timeoutSeconds: 3
readinessProbe:
httpGet:
path: /
port: http
initialDelaySeconds: 1
periodSeconds: 5
timeoutSeconds: 2