# A StatefulSet rather than a Deployment: one identity, one volume, and no # window where two pods hold the same data directory. The volumeClaimTemplate # also means the claim is not deleted with the workload — losing the workflows # to a `kubectl delete deploy` would be an avoidable way to lose them. apiVersion: apps/v1 kind: StatefulSet metadata: name: n8n-postgres namespace: n8n spec: serviceName: n8n-postgres replicas: 1 selector: matchLabels: app: n8n-postgres template: metadata: labels: app: n8n-postgres spec: securityContext: fsGroup: 999 containers: - name: postgres image: postgres:16.10-alpine ports: - name: postgres containerPort: 5432 env: - name: POSTGRES_USER value: n8n - name: POSTGRES_DB value: n8n - name: POSTGRES_PASSWORD valueFrom: secretKeyRef: name: n8n-secrets key: DB_PASSWORD # The image initialises into this directory. Naming a subdirectory # of the mount rather than the mount itself keeps initdb away from # the lost+found some volume types leave at the root. - name: PGDATA value: /var/lib/postgresql/data/pgdata volumeMounts: - name: data mountPath: /var/lib/postgresql/data readinessProbe: exec: command: ["pg_isready", "-U", "n8n", "-d", "n8n"] initialDelaySeconds: 5 periodSeconds: 10 livenessProbe: exec: command: ["pg_isready", "-U", "n8n", "-d", "n8n"] initialDelaySeconds: 30 periodSeconds: 20 resources: requests: cpu: 50m memory: 256Mi limits: cpu: "1" memory: 1Gi volumeClaimTemplates: - metadata: name: data spec: accessModes: ["ReadWriteOnce"] resources: requests: storage: 5Gi