feat(helm): add API deployment and service templates

Includes two init containers (VPN route setup, Alembic migrations),
secret refs for JWT/encryption/OpenBao/SMTP, and PVC mounts for
git-store, firmware-cache, and wireguard config.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jason Staack
2026-03-17 18:45:45 -05:00
parent d2b75bdae8
commit 04f6d46082
2 changed files with 167 additions and 0 deletions

View File

@@ -0,0 +1,152 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "tod.fullname" . }}-api
labels:
{{- include "tod.componentLabels" (dict "context" . "component" "api") | nindent 4 }}
spec:
replicas: {{ .Values.api.replicaCount }}
selector:
matchLabels:
{{- include "tod.componentSelectorLabels" (dict "context" . "component" "api") | nindent 6 }}
template:
metadata:
labels:
{{- include "tod.componentSelectorLabels" (dict "context" . "component" "api") | nindent 8 }}
spec:
initContainers:
# Init 1: Set up VPN route (only if WireGuard enabled)
{{- if .Values.wireguard.enabled }}
- name: route-setup
image: "{{ .Values.api.image.repository }}:{{ .Values.api.image.tag }}"
imagePullPolicy: {{ .Values.api.image.pullPolicy }}
command:
- sh
- -c
- |
apt-get update -qq && apt-get install -y -qq iproute2 >/dev/null 2>&1 || true
GW_IP=$(getent hosts ${WIREGUARD_GATEWAY} 2>/dev/null | awk '{print $1}')
[ -z "$GW_IP" ] && GW_IP=${WIREGUARD_GATEWAY}
ip route add 10.10.0.0/16 via $GW_IP 2>/dev/null || true
echo "VPN route: 10.10.0.0/16 via $GW_IP"
env:
- name: WIREGUARD_GATEWAY
valueFrom:
configMapKeyRef:
name: {{ include "tod.fullname" . }}
key: WIREGUARD_GATEWAY
securityContext:
runAsUser: 0
capabilities:
add: ["NET_ADMIN"]
{{- end }}
# Init 2: Run database migrations
- name: migrations
image: "{{ .Values.api.image.repository }}:{{ .Values.api.image.tag }}"
imagePullPolicy: {{ .Values.api.image.pullPolicy }}
command: ["python", "-m", "alembic", "upgrade", "head"]
env:
- name: DATABASE_URL
valueFrom:
configMapKeyRef:
name: {{ include "tod.fullname" . }}
key: DATABASE_URL
- name: SYNC_DATABASE_URL
valueFrom:
configMapKeyRef:
name: {{ include "tod.fullname" . }}
key: SYNC_DATABASE_URL
securityContext:
runAsUser: 1001
runAsNonRoot: true
containers:
- name: api
image: "{{ .Values.api.image.repository }}:{{ .Values.api.image.tag }}"
imagePullPolicy: {{ .Values.api.image.pullPolicy }}
ports:
- name: http
containerPort: 8000
protocol: TCP
envFrom:
- configMapRef:
name: {{ include "tod.fullname" . }}
env:
- name: JWT_SECRET_KEY
valueFrom:
secretKeyRef:
name: {{ include "tod.fullname" . }}-secrets
key: JWT_SECRET_KEY
- name: CREDENTIAL_ENCRYPTION_KEY
valueFrom:
secretKeyRef:
name: {{ include "tod.fullname" . }}-secrets
key: CREDENTIAL_ENCRYPTION_KEY
- name: OPENBAO_TOKEN
valueFrom:
secretKeyRef:
name: {{ include "tod.fullname" . }}-secrets
key: OPENBAO_TOKEN
- name: FIRST_ADMIN_EMAIL
valueFrom:
secretKeyRef:
name: {{ include "tod.fullname" . }}-secrets
key: FIRST_ADMIN_EMAIL
- name: FIRST_ADMIN_PASSWORD
valueFrom:
secretKeyRef:
name: {{ include "tod.fullname" . }}-secrets
key: FIRST_ADMIN_PASSWORD
- name: SMTP_USER
valueFrom:
secretKeyRef:
name: {{ include "tod.fullname" . }}-secrets
key: SMTP_USER
- name: SMTP_PASSWORD
valueFrom:
secretKeyRef:
name: {{ include "tod.fullname" . }}-secrets
key: SMTP_PASSWORD
volumeMounts:
- name: git-store
mountPath: /data/git-store
- name: firmware-cache
mountPath: /data/firmware-cache
{{- if .Values.wireguard.enabled }}
- name: wireguard-config
mountPath: /data/wireguard
{{- end }}
livenessProbe:
httpGet:
path: {{ .Values.api.probes.liveness.path }}
port: http
initialDelaySeconds: {{ .Values.api.probes.liveness.initialDelaySeconds }}
periodSeconds: {{ .Values.api.probes.liveness.periodSeconds }}
failureThreshold: {{ .Values.api.probes.liveness.failureThreshold }}
readinessProbe:
httpGet:
path: {{ .Values.api.probes.readiness.path }}
port: http
initialDelaySeconds: {{ .Values.api.probes.readiness.initialDelaySeconds }}
periodSeconds: {{ .Values.api.probes.readiness.periodSeconds }}
failureThreshold: {{ .Values.api.probes.readiness.failureThreshold }}
resources:
{{- toYaml .Values.api.resources | nindent 12 }}
securityContext:
runAsUser: 1001
runAsNonRoot: true
allowPrivilegeEscalation: false
readOnlyRootFilesystem: false
capabilities:
drop: ["ALL"]
volumes:
- name: git-store
persistentVolumeClaim:
claimName: {{ include "tod.fullname" . }}-git-store
- name: firmware-cache
persistentVolumeClaim:
claimName: {{ include "tod.fullname" . }}-firmware-cache
{{- if .Values.wireguard.enabled }}
- name: wireguard-config
persistentVolumeClaim:
claimName: {{ include "tod.fullname" . }}-wireguard-config
{{- end }}

View File

@@ -0,0 +1,15 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "tod.fullname" . }}-api
labels:
{{- include "tod.componentLabels" (dict "context" . "component" "api") | nindent 4 }}
spec:
type: ClusterIP
ports:
- name: http
port: {{ .Values.api.service.port }}
targetPort: http
protocol: TCP
selector:
{{- include "tod.componentSelectorLabels" (dict "context" . "component" "api") | nindent 4 }}