Files
felhom.eu/documentation/audits/dooplex-alarms-2026-10-24/postgresql-backup.yaml.before
T
admin 44d1904286
gates / gates (push) Successful in 12m24s
DooPlex backup alarms: one cause (the dump job's password after the reboot), fixed; alarm mail quieter; R-1250 proven
R-232 dated note + a dated check for tonight's sweep; R-934 closed (the disk was pulled
2026-10-23); R-1250 fixed on main, live proof on demo-hp with a real seed; 08 §9 item 5.
Evidence audits/dooplex-alarms-2026-10-24/.
2026-10-24 13:53:57 +02:00

152 lines
5.4 KiB
Plaintext

# ============================================================================
# postgresql-1 logical backup — 6-hourly pg_dump to HDD5 (rides Restic)
# ----------------------------------------------------------------------------
# The shared CNPG cluster `postgresql` (database-system, single instance) had no
# backup. This CronJob does a LOGICAL backup every 6h:
# - pg_dumpall --globals-only -> globals.sql (roles/grants; needed for restore)
# - pg_dump -Fc per database -> <db>.dump (custom format; selective restore)
# written to hostPath /mnt/5_hdd/backup/postgresql/dumps/<timestamp>/ (HDD5, OFF
# the DB's own HDD4 disk). The host backup flow (/opt/backup, backup-postgresql.sh)
# then restic-backs-up that dir in its daily run (7d/4w/6m retention). Local
# retention here = 3 days. RPO <=6h, no PITR (accepted).
#
# Auth: connects to postgresql-rw as the CNPG-managed superuser (secret
# `postgres-superuser`, keys username/password). Requires enableSuperuserAccess:
# true on the Cluster (set in postgresql-cluster.yaml). The superuser is the only
# role that can read every DB + dump globals; per-app roles cannot.
#
# Freshness alert: kube_cronjob_status_last_successful_time (KSM) — see
# mon-system/prometheus-rules.yaml (PostgresqlDumpStale, >12h).
# ============================================================================
---
apiVersion: v1
kind: ConfigMap
metadata:
name: postgresql-backup-script
namespace: database-system
labels:
app.kubernetes.io/name: postgresql-backup
app.kubernetes.io/instance: postgresql-backup
data:
pg-backup.sh: |
#!/usr/bin/env bash
set -euo pipefail
export PGHOST="${PGHOST:-postgresql-rw}" PGPORT="${PGPORT:-5432}"
TS="$(date +%Y%m%d-%H%M%S)"
OUT="/backup/dumps/${TS}"
mkdir -p "${OUT}"
echo "[pgbackup] ${TS} -> ${OUT}"
echo "[pgbackup] globals (roles/grants)"
pg_dumpall --globals-only > "${OUT}/globals.sql"
mapfile -t DBS < <(psql -tAc \
"SELECT datname FROM pg_database WHERE NOT datistemplate AND datallowconn ORDER BY 1;")
echo "[pgbackup] databases: ${DBS[*]}"
for db in "${DBS[@]}"; do
echo "[pgbackup] pg_dump -Fc ${db}"
pg_dump -Fc -d "${db}" -f "${OUT}/${db}.dump"
done
touch "${OUT}/SUCCESS"
echo "[pgbackup] pruning local dumps older than 3 days"
find /backup/dumps -mindepth 1 -maxdepth 1 -type d -mtime +3 -exec rm -rf {} + || true
echo "[pgbackup] done"
ls -lh "${OUT}"
---
apiVersion: batch/v1
kind: CronJob
metadata:
name: postgresql-backup
namespace: database-system
labels:
app.kubernetes.io/name: postgresql-backup
app.kubernetes.io/instance: postgresql-backup
spec:
schedule: "0 */6 * * *"
timeZone: "Europe/Budapest"
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 3
startingDeadlineSeconds: 600
jobTemplate:
metadata:
labels:
app.kubernetes.io/name: postgresql-backup
app.kubernetes.io/instance: postgresql-backup
spec:
backoffLimit: 2
activeDeadlineSeconds: 1800
template:
metadata:
labels:
app.kubernetes.io/name: postgresql-backup
app.kubernetes.io/instance: postgresql-backup
annotations:
# postgres image is pinned to the CNPG cluster's version (X.Y)
match-regex.version-checker.io/pgbackup: '^\d+\.\d+$'
spec:
enableServiceLinks: false
restartPolicy: OnFailure
securityContext:
runAsNonRoot: true
runAsUser: 26
runAsGroup: 26
fsGroup: 26
containers:
- name: pgbackup
# MUST match the CNPG cluster's Postgres version (pg_dump >= server).
image: ghcr.io/cloudnative-pg/postgresql:17.2
imagePullPolicy: IfNotPresent
command: ["/bin/bash", "/scripts/pg-backup.sh"]
env:
- name: PGHOST
value: postgresql-rw
- name: PGPORT
value: "5432"
- name: PGUSER
valueFrom:
secretKeyRef:
name: postgresql-superuser
key: username
- name: PGPASSWORD
valueFrom:
secretKeyRef:
name: postgresql-superuser
key: password
- name: HOME
value: /tmp
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: "1"
memory: 512Mi
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
volumeMounts:
- name: script
mountPath: /scripts
readOnly: true
- name: backup
mountPath: /backup
- name: tmp
mountPath: /tmp
volumes:
- name: script
configMap:
name: postgresql-backup-script
defaultMode: 0755
- name: backup
hostPath:
path: /mnt/5_hdd/backup/postgresql
type: Directory
- name: tmp
emptyDir:
sizeLimit: 256Mi