124 lines
5.1 KiB
YAML
124 lines
5.1 KiB
YAML
{{- if .Values.backups.enabled -}}
|
|
# Daily dump → S3.
|
|
#
|
|
# Architecture: pg_dump in postgres:alpine, pipe through gzip, then
|
|
# `aws s3 cp -` to push the stream straight to MEGA S4. We use a
|
|
# single multi-stage shell command (no init container) so the dump
|
|
# never lands on the customer-server's local disk — the instance
|
|
# data and the backup destination are deliberately separated.
|
|
#
|
|
# AWS credentials come from a K8s Secret (default `s3-backup-creds`)
|
|
# provisioned out-of-band by Tower's bootstrap. Endpoint + bucket +
|
|
# prefix are committed in this file's values; only the access/secret
|
|
# pair lives in the Secret.
|
|
apiVersion: batch/v1
|
|
kind: CronJob
|
|
metadata:
|
|
name: {{ include "instance.fullname" . }}-backup
|
|
labels:
|
|
{{- include "instance.labels" . | nindent 4 }}
|
|
odoosky.io/role: backup
|
|
spec:
|
|
schedule: {{ .Values.backups.schedule | quote }}
|
|
concurrencyPolicy: Forbid
|
|
successfulJobsHistoryLimit: 5
|
|
failedJobsHistoryLimit: 3
|
|
jobTemplate:
|
|
metadata:
|
|
labels:
|
|
{{- include "instance.labels" . | nindent 8 }}
|
|
odoosky.io/role: backup
|
|
spec:
|
|
backoffLimit: 1
|
|
template:
|
|
metadata:
|
|
labels:
|
|
{{- include "instance.labels" . | nindent 12 }}
|
|
odoosky.io/role: backup
|
|
spec:
|
|
restartPolicy: Never
|
|
containers:
|
|
- name: pgdump-s3
|
|
# postgres:16-alpine + `apk add aws-cli` — alpine's
|
|
# aws-cli package is ~30 MB and adds ~5 s to the first
|
|
# job run on each node. Subsequent runs reuse the
|
|
# already-installed binary because we keep the same
|
|
# image (containerd's layer cache covers the apk index
|
|
# download). This matches the postgres version of the
|
|
# cluster's actual database container, so pg_dump's
|
|
# client/server protocol always lines up.
|
|
image: "{{ .Values.postgres.image }}:{{ .Values.postgres.tag }}"
|
|
imagePullPolicy: IfNotPresent
|
|
env:
|
|
- name: PGHOST
|
|
value: {{ include "instance.fullname" . }}-pg
|
|
- name: PGUSER
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: {{ include "instance.fullname" . }}-pg
|
|
key: POSTGRES_USER
|
|
- name: PGPASSWORD
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: {{ include "instance.fullname" . }}-pg
|
|
key: POSTGRES_PASSWORD
|
|
- name: PGDATABASE
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: {{ include "instance.fullname" . }}-pg
|
|
key: POSTGRES_DB
|
|
- name: AWS_ACCESS_KEY_ID
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: {{ .Values.backups.credentialsSecret }}
|
|
key: AWS_ACCESS_KEY_ID
|
|
- name: AWS_SECRET_ACCESS_KEY
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: {{ .Values.backups.credentialsSecret }}
|
|
key: AWS_SECRET_ACCESS_KEY
|
|
- name: S3_ENDPOINT
|
|
value: {{ .Values.backups.s3.endpoint | quote }}
|
|
- name: AWS_DEFAULT_REGION
|
|
value: {{ .Values.backups.s3.region | quote }}
|
|
- name: S3_BUCKET
|
|
value: {{ .Values.backups.s3.bucket | quote }}
|
|
- name: S3_PREFIX
|
|
value: {{ .Values.instance.code | quote }}
|
|
- name: RETAIN
|
|
value: {{ .Values.backups.retain | quote }}
|
|
command:
|
|
- /bin/sh
|
|
- -c
|
|
- |
|
|
set -eu
|
|
TS=$(date -u +%Y%m%dT%H%M%SZ)
|
|
KEY="${S3_PREFIX}/${TS}.sql.gz"
|
|
echo ">>> dumping to s3://${S3_BUCKET}/${KEY}"
|
|
if ! command -v aws >/dev/null 2>&1; then
|
|
apk add --no-cache aws-cli >/dev/null
|
|
fi
|
|
pg_dump --format=plain --clean --if-exists --no-owner --no-acl \
|
|
| gzip -9 \
|
|
| aws --endpoint-url "$S3_ENDPOINT" s3 cp - "s3://${S3_BUCKET}/${KEY}"
|
|
echo ">>> uploaded"
|
|
echo ">>> rotating: keep last $RETAIN under ${S3_PREFIX}/"
|
|
aws --endpoint-url "$S3_ENDPOINT" s3api list-objects-v2 \
|
|
--bucket "$S3_BUCKET" --prefix "${S3_PREFIX}/" \
|
|
--query 'Contents[].Key' --output text 2>/dev/null \
|
|
| tr '\t' '\n' | sort -r | tail -n +$((RETAIN + 1)) \
|
|
| while read OLDKEY; do
|
|
[ -n "$OLDKEY" ] || continue
|
|
echo ">>> deleting old: $OLDKEY"
|
|
aws --endpoint-url "$S3_ENDPOINT" s3 rm "s3://${S3_BUCKET}/${OLDKEY}"
|
|
done
|
|
echo ">>> done"
|
|
resources:
|
|
requests:
|
|
cpu: 100m
|
|
memory: 256Mi
|
|
limits:
|
|
cpu: "1"
|
|
memory: 1Gi
|
|
{{- end }}
|