apiVersion: v1 kind: PersistentVolumeClaim metadata: name: user-engine-backups namespace: user-engine labels: app.kubernetes.io/name: user-engine-backup app.kubernetes.io/part-of: user-engine spec: accessModes: [ReadWriteOnce] resources: requests: {storage: 1Gi} --- apiVersion: batch/v1 kind: CronJob metadata: name: user-engine-backup namespace: user-engine labels: app.kubernetes.io/name: user-engine-backup app.kubernetes.io/part-of: user-engine spec: schedule: "0 4 * * *" concurrencyPolicy: Forbid successfulJobsHistoryLimit: 3 failedJobsHistoryLimit: 3 jobTemplate: spec: backoffLimit: 2 template: metadata: labels: app.kubernetes.io/name: user-engine-backup app.kubernetes.io/part-of: user-engine spec: restartPolicy: Never automountServiceAccountToken: false securityContext: runAsNonRoot: true runAsUser: 26 runAsGroup: 26 fsGroup: 26 seccompProfile: {type: RuntimeDefault} containers: - name: backup image: ghcr.io/cloudnative-pg/postgresql:17.5 imagePullPolicy: IfNotPresent env: - name: DATABASE_URL valueFrom: secretKeyRef: {name: user-engine-pg-app, key: uri} command: - /bin/bash - -ec - | umask 077 stamp="$(date -u +%Y%m%dT%H%M%SZ)" target="/backup/user-engine-${stamp}.dump" for attempt in $(seq 1 30); do if pg_isready --dbname="${DATABASE_URL}" >/dev/null 2>&1; then break fi test "${attempt}" -lt 30 sleep 2 done pg_dump --format=custom --no-owner --no-acl \ --file="${target}.partial" "${DATABASE_URL}" pg_restore --list "${target}.partial" >/dev/null mv "${target}.partial" "${target}" sha256sum "${target}" >"${target}.sha256" find /backup -type f -name 'user-engine-*.dump*' -mtime +7 -delete echo "backup_complete file=$(basename "${target}")" volumeMounts: - {name: backup, mountPath: /backup} securityContext: allowPrivilegeEscalation: false capabilities: {drop: ["ALL"]} resources: requests: {cpu: 25m, memory: 64Mi} limits: {cpu: 500m, memory: 256Mi} volumes: - name: backup persistentVolumeClaim: {claimName: user-engine-backups} --- apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: user-engine-backup namespace: user-engine spec: podSelector: matchLabels: app.kubernetes.io/name: user-engine-backup app.kubernetes.io/part-of: user-engine policyTypes: [Egress] egress: - to: - podSelector: matchLabels: {cnpg.io/cluster: user-engine-pg} ports: [{protocol: TCP, port: 5432}] - to: - namespaceSelector: matchLabels: {kubernetes.io/metadata.name: kube-system} ports: [{protocol: UDP, port: 53}, {protocol: TCP, port: 53}] --- apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: user-engine-postgres-backup-ingress namespace: user-engine spec: podSelector: matchLabels: {cnpg.io/cluster: user-engine-pg} policyTypes: [Ingress] ingress: - from: - podSelector: matchLabels: app.kubernetes.io/name: user-engine-backup app.kubernetes.io/part-of: user-engine ports: [{protocol: TCP, port: 5432}]