Phase 2 of the Stalwart RocksDB -> PostgreSQL migration (DEV-467). Purely additive - does not touch the running stalwart-0 pod, its ConfigMap, PVC, or bootstrap-config. - stalwart-postgres.yaml: single-replica StatefulSet with a 10Gi hcloud-volumes-encrypted PVC (subPath pgdata), ClusterIP Service on 5432, nodeAffinity csi.hetzner.cloud/location=fsn1 so the DB co-locates with stalwart-0 (which is fsn1-pinned by its PVC). Resources match forgejo-postgres (250m/512Mi req, 500m/1Gi lim). - stalwart-postgres-credentials-sealed.yaml: sealed secret with POSTGRES_USER=stalwart, POSTGRES_DB=stalwart, POSTGRES_PASSWORD, plus a copy of the password under stalwart-db-password for Stalwart's [store.postgres] config in the Phase 4 cutover. - stalwart-postgres-backup.yaml: daily CronJob at 02:30 UTC that streams pg_dump | gzip into the existing stalwart-s3-backup restic repo tagged stalwart-postgres, with independent retention keys (14d/8w/6m) so it doesn't collide with the RocksDB snapshots. activeDeadlineSeconds=1800 mirrors the DEV-464 sibling fix. Co-Authored-By: Paperclip <noreply@paperclip.ing>
120 lines
4 KiB
YAML
120 lines
4 KiB
YAML
---
|
|
apiVersion: batch/v1
|
|
kind: CronJob
|
|
metadata:
|
|
name: stalwart-postgres-backup
|
|
namespace: stalwart
|
|
labels:
|
|
app: stalwart-postgres-backup
|
|
spec:
|
|
schedule: "30 2 * * *"
|
|
concurrencyPolicy: Forbid
|
|
successfulJobsHistoryLimit: 3
|
|
failedJobsHistoryLimit: 3
|
|
jobTemplate:
|
|
spec:
|
|
backoffLimit: 2
|
|
activeDeadlineSeconds: 1800
|
|
template:
|
|
metadata:
|
|
labels:
|
|
app: stalwart-postgres-backup
|
|
spec:
|
|
restartPolicy: OnFailure
|
|
containers:
|
|
- name: backup
|
|
image: postgres:16-alpine
|
|
imagePullPolicy: IfNotPresent
|
|
command:
|
|
- /bin/sh
|
|
- -c
|
|
- |
|
|
set -euo pipefail
|
|
BACKUP_START=$(date +%s)
|
|
echo "=== Starting Stalwart Postgres backup at $(date -u) ==="
|
|
|
|
# pg_dump already in image; restic is small and only needed here.
|
|
apk add --no-cache restic
|
|
|
|
export RESTIC_REPOSITORY="s3:${S3_ENDPOINT}/${S3_BUCKET}/stalwart"
|
|
echo "Repository: ${RESTIC_REPOSITORY}"
|
|
|
|
# Repo is shared with the RocksDB backup, so it already exists;
|
|
# init only if the RocksDB side has not created it yet.
|
|
restic snapshots > /dev/null 2>&1 || restic init
|
|
|
|
echo "Streaming pg_dump | gzip -> restic (tag stalwart-postgres)..."
|
|
PGPASSWORD="${POSTGRES_PASSWORD}" pg_dump \
|
|
-h stalwart-postgres.stalwart.svc.cluster.local \
|
|
-U "${POSTGRES_USER}" \
|
|
-d "${POSTGRES_DB}" \
|
|
--no-owner --no-acl \
|
|
| gzip -c \
|
|
| restic backup \
|
|
--stdin \
|
|
--stdin-filename stalwart-postgres.sql.gz \
|
|
--tag stalwart-postgres \
|
|
--tag daily \
|
|
--host stalwart-postgres-k8s
|
|
|
|
echo "Forget/prune (tag=stalwart-postgres, independent retention)..."
|
|
restic forget \
|
|
--tag stalwart-postgres \
|
|
--keep-daily 14 \
|
|
--keep-weekly 8 \
|
|
--keep-monthly 6 \
|
|
--prune
|
|
|
|
echo "Latest stalwart-postgres snapshots:"
|
|
restic snapshots --tag stalwart-postgres --compact || true
|
|
|
|
BACKUP_END=$(date +%s)
|
|
echo "=== Postgres backup complete in $((BACKUP_END - BACKUP_START))s at $(date -u) ==="
|
|
env:
|
|
- name: POSTGRES_USER
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: stalwart-postgres-credentials
|
|
key: POSTGRES_USER
|
|
- name: POSTGRES_DB
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: stalwart-postgres-credentials
|
|
key: POSTGRES_DB
|
|
- name: POSTGRES_PASSWORD
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: stalwart-postgres-credentials
|
|
key: POSTGRES_PASSWORD
|
|
- name: RESTIC_PASSWORD
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: stalwart-s3-backup
|
|
key: restic-password
|
|
- name: AWS_ACCESS_KEY_ID
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: stalwart-s3-backup
|
|
key: access-key
|
|
- name: AWS_SECRET_ACCESS_KEY
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: stalwart-s3-backup
|
|
key: secret-key
|
|
- name: S3_ENDPOINT
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: stalwart-s3-backup
|
|
key: endpoint
|
|
- name: S3_BUCKET
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: stalwart-s3-backup
|
|
key: bucket
|
|
resources:
|
|
requests:
|
|
cpu: 100m
|
|
memory: 128Mi
|
|
limits:
|
|
cpu: 500m
|
|
memory: 512Mi
|