apiVersion: apps/v1 kind: Deployment metadata: name: web namespace: honeydue labels: app.kubernetes.io/name: web app.kubernetes.io/part-of: honeydue spec: replicas: 3 strategy: type: RollingUpdate rollingUpdate: maxUnavailable: 0 maxSurge: 1 selector: matchLabels: app.kubernetes.io/name: web template: metadata: labels: app.kubernetes.io/name: web app.kubernetes.io/part-of: honeydue spec: serviceAccountName: web # Explicit pod-level opt-out (audit F11) — defense-in-depth on top of # the ServiceAccount-level setting in rbac.yaml. automountServiceAccountToken: false imagePullSecrets: - name: gitea-credentials securityContext: runAsNonRoot: true runAsUser: 1001 runAsGroup: 1001 fsGroup: 1001 seccompProfile: type: RuntimeDefault # Spread pods across nodes so one node loss drops at most one replica. topologySpreadConstraints: - maxSkew: 1 topologyKey: kubernetes.io/hostname whenUnsatisfiable: ScheduleAnyway labelSelector: matchLabels: app.kubernetes.io/name: web containers: - name: web image: IMAGE_PLACEHOLDER # Replaced by 03-deploy.sh or manual sed imagePullPolicy: IfNotPresent # audit CODE-L4 — explicit; images are SHA/digest-pinned ports: - containerPort: 3000 protocol: TCP securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true capabilities: drop: ["ALL"] env: - name: PORT value: "3000" - name: HOSTNAME value: "0.0.0.0" # Server-side proxy target (src/app/api/proxy/[...path]/route.ts, # src/app/api/auth/*/route.ts). Browser never sees this URL. - name: API_URL valueFrom: configMapKeyRef: name: honeydue-config key: API_URL volumeMounts: # Next.js writes its build cache here; readOnlyRootFilesystem blocks # writing to /app/.next/cache otherwise. - name: nextjs-cache mountPath: /app/.next/cache - name: tmp mountPath: /tmp resources: requests: cpu: 50m memory: 64Mi limits: cpu: 500m memory: 256Mi # Next.js standalone serves at `/`. `/login` also 200s pre-auth. startupProbe: httpGet: path: / port: 3000 failureThreshold: 24 periodSeconds: 5 readinessProbe: httpGet: path: / port: 3000 initialDelaySeconds: 5 periodSeconds: 10 timeoutSeconds: 5 livenessProbe: httpGet: path: / port: 3000 initialDelaySeconds: 30 periodSeconds: 30 timeoutSeconds: 10 volumes: - name: nextjs-cache emptyDir: sizeLimit: 256Mi - name: tmp emptyDir: sizeLimit: 64Mi