From a27c238c76f80c0b9c2b52fb6eb4567af5d3591c Mon Sep 17 00:00:00 2001 From: Ronni Baslund Date: Mon, 8 Jun 2026 21:55:14 +0200 Subject: [PATCH] feat(infra): nightly DB-dump CronJobs feeding the Restic backup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pg_dumpall (all Postgres DBs + roles) and mongodump (all Mongo DBs) write gzipped dumps to the hostPath /opt/dezky-backup/dumps at 02:50/02:52 UTC, which the host Restic job (03:20) ships to the Storage Box. Each keeps the last 7 local dumps; Restic holds the real off-box retention. - pods run as root (hostPath dir is root-owned, as is the host Restic reader) - mongo job uses bash (mongo:7 /bin/sh is dash → no pipefail) - creds from postgres-secret / mongo-secret via secretKeyRef Verified: both jobs Complete, dumps present on the host (postgres-all ~2.2MB w/ Authentik data, mongo archive). --- .../production/fleet/data/db-backup.yaml | 106 ++++++++++++++++++ .../production/fleet/data/kustomization.yaml | 1 + 2 files changed, 107 insertions(+) create mode 100644 infrastructure/production/fleet/data/db-backup.yaml diff --git a/infrastructure/production/fleet/data/db-backup.yaml b/infrastructure/production/fleet/data/db-backup.yaml new file mode 100644 index 0000000..9b691c3 --- /dev/null +++ b/infrastructure/production/fleet/data/db-backup.yaml @@ -0,0 +1,106 @@ +# Nightly logical DB dumps -> hostPath /opt/dezky-backup/dumps, where the host +# Restic job (03:20 UTC) picks them up and ships them to the Storage Box. These +# run at 02:50/02:52 UTC so the dumps are fresh when Restic runs. Each keeps the +# last 7 dumps locally (Restic keeps the real retention off-box). +# +# Pods run as root because the hostPath dir is root-owned (so the host Restic, +# also root, can read the dumps). Single-node cluster; trusted backup job. +--- +apiVersion: batch/v1 +kind: CronJob +metadata: + name: postgres-backup + namespace: dezky-data +spec: + schedule: "50 2 * * *" + concurrencyPolicy: Forbid + successfulJobsHistoryLimit: 3 + failedJobsHistoryLimit: 3 + jobTemplate: + spec: + backoffLimit: 1 + template: + spec: + restartPolicy: Never + securityContext: + runAsUser: 0 + containers: + - name: pgdump + image: postgres:16-alpine + command: ["/bin/sh", "-c"] + args: + - | + set -euo pipefail + ts=$(date +%Y%m%d-%H%M%S) + out=/dump/postgres-all-$ts.sql.gz + echo "pg_dumpall (all DBs + roles) -> $out" + PGPASSWORD="$POSTGRES_PASSWORD" pg_dumpall -h postgres.dezky-data -U postgres | gzip > "$out" + ls -1t /dump/postgres-all-*.sql.gz | tail -n +8 | xargs -r rm -f + ls -la /dump/postgres-all-*.sql.gz | tail -3 + env: + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: postgres-secret + key: POSTGRES_PASSWORD + volumeMounts: + - name: dumps + mountPath: /dump + volumes: + - name: dumps + hostPath: + path: /opt/dezky-backup/dumps + type: DirectoryOrCreate +--- +apiVersion: batch/v1 +kind: CronJob +metadata: + name: mongo-backup + namespace: dezky-data +spec: + schedule: "52 2 * * *" + concurrencyPolicy: Forbid + successfulJobsHistoryLimit: 3 + failedJobsHistoryLimit: 3 + jobTemplate: + spec: + backoffLimit: 1 + template: + spec: + restartPolicy: Never + securityContext: + runAsUser: 0 + containers: + - name: mongodump + image: mongo:7 + command: ["/bin/bash", "-c"] + args: + - | + set -euo pipefail + ts=$(date +%Y%m%d-%H%M%S) + out=/dump/mongo-$ts.archive.gz + echo "mongodump (all DBs) -> $out" + mongodump --host mongo.dezky-data \ + --username "$MONGO_USER" --password "$MONGO_PASS" \ + --authenticationDatabase admin --archive --gzip > "$out" + ls -1t /dump/mongo-*.archive.gz | tail -n +8 | xargs -r rm -f + ls -la /dump/mongo-*.archive.gz | tail -3 + env: + - name: MONGO_USER + valueFrom: + secretKeyRef: + name: mongo-secret + key: root-username + - name: MONGO_PASS + valueFrom: + secretKeyRef: + name: mongo-secret + key: root-password + volumeMounts: + - name: dumps + mountPath: /dump + volumes: + - name: dumps + hostPath: + path: /opt/dezky-backup/dumps + type: DirectoryOrCreate diff --git a/infrastructure/production/fleet/data/kustomization.yaml b/infrastructure/production/fleet/data/kustomization.yaml index 423a32a..e7b8ac1 100644 --- a/infrastructure/production/fleet/data/kustomization.yaml +++ b/infrastructure/production/fleet/data/kustomization.yaml @@ -10,3 +10,4 @@ resources: - postgres.yaml - mongodb.yaml - redis.yaml + - db-backup.yaml