feat(backup): skip-if-unchanged + scheduled CronJob in the chart
Builds on the dedicated backup (erp#31).
Skip-if-unchanged: each half (DB / documents) carries a content fingerprint at
erp/<env>/.fp-{db,docs} and is dumped+uploaded only if it differs from the last
run — a quiet ERP day re-uploads nothing. Fingerprint = durable BUSINESS content
only: DB = count+max(tms) over tms tables EXCEPT volatile churn (llx_const,
llx_user, session/cron); docs EXCLUDE */temp/* (Dolibarr stats cache) — from both
the fingerprint and the tar. Proven live: 1st run uploads both, immediate 2nd run
skips both (uploaded=0).
Automation: the in-container logic moves to chart/files/backup-job.sh (single
source of truth, read by the orchestrator AND the chart). New
chart/templates/backup-cronjob.yaml renders a daily CronJob + ConfigMap +
VaultStaticSecret, gated by backup.enabled (default false). Helm-verified: off by
default (0 CronJobs), on renders correctly, env-aware (PREFIX erp/prod vs
erp/sandbox), script embedded.
Activation (documented): store GCS HMAC creds at kvv2/<backup.vaultS3Path>
(default erp/backup), grant the erp `auth` Vault role read on it (tools change),
set backup.enabled=true. Until then the orchestrator runs on demand.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
77
chart/templates/backup-cronjob.yaml
Normal file
77
chart/templates/backup-cronjob.yaml
Normal file
@@ -0,0 +1,77 @@
|
||||
{{- if .Values.backup.enabled }}
|
||||
# Dedicated Dolibarr backup (ops/backup/README.md): DB + documents -> offsite GCS,
|
||||
# tiered retention, skip-if-unchanged. Disabled by default — enable once the S3
|
||||
# creds VaultStaticSecret below resolves (the `auth` Vault role must be allowed to
|
||||
# read kvv2/{{ .Values.backup.vaultS3Path }}).
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: {{ include "erp.fullname" . }}-backup-job
|
||||
labels:
|
||||
{{- include "erp.labels" . | nindent 4 }}
|
||||
data:
|
||||
backup-job.sh: |
|
||||
{{- .Files.Get "files/backup-job.sh" | nindent 4 }}
|
||||
---
|
||||
apiVersion: secrets.hashicorp.com/v1beta1
|
||||
kind: VaultStaticSecret
|
||||
metadata:
|
||||
name: {{ include "erp.fullname" . }}-backup-s3
|
||||
namespace: {{ .Release.Namespace }}
|
||||
spec:
|
||||
type: kv-v2
|
||||
mount: kvv2
|
||||
# kvv2/<path> must hold AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY / AWS_ENDPOINTS
|
||||
# (the GCS HMAC creds — same shape as longhorn-gcs-backup-credentials).
|
||||
path: {{ .Values.backup.vaultS3Path }}
|
||||
destination:
|
||||
name: dolibarr-backup-s3
|
||||
create: true
|
||||
refreshAfter: 24h
|
||||
vaultAuthRef: auth
|
||||
---
|
||||
apiVersion: batch/v1
|
||||
kind: CronJob
|
||||
metadata:
|
||||
name: {{ include "erp.fullname" . }}-backup
|
||||
labels:
|
||||
{{- include "erp.labels" . | nindent 4 }}
|
||||
spec:
|
||||
schedule: {{ .Values.backup.schedule | quote }}
|
||||
concurrencyPolicy: Forbid
|
||||
successfulJobsHistoryLimit: 3
|
||||
failedJobsHistoryLimit: 3
|
||||
jobTemplate:
|
||||
spec:
|
||||
backoffLimit: 1
|
||||
template:
|
||||
spec:
|
||||
restartPolicy: Never
|
||||
volumes:
|
||||
- name: docs
|
||||
persistentVolumeClaim:
|
||||
claimName: {{ include "erp.fullname" . }}
|
||||
readOnly: true
|
||||
- name: job
|
||||
configMap:
|
||||
name: {{ include "erp.fullname" . }}-backup-job
|
||||
containers:
|
||||
- name: backup
|
||||
image: {{ .Values.backup.image | quote }}
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: dolibarr-backup-s3
|
||||
env:
|
||||
- { name: BUCKET, value: {{ .Values.backup.bucket | quote }} }
|
||||
- { name: PREFIX, value: {{ printf "erp/%s" .Values.env | quote }} }
|
||||
- { name: DB, value: {{ .Values.db.name | quote }} }
|
||||
- { name: PGHOST, value: {{ .Values.backup.pgHost | quote }} }
|
||||
- name: PGUSER
|
||||
valueFrom: { secretKeyRef: { name: vso-db-credentials, key: username } }
|
||||
- name: PGPASSWORD
|
||||
valueFrom: { secretKeyRef: { name: vso-db-credentials, key: password } }
|
||||
volumeMounts:
|
||||
- { name: docs, mountPath: /docs, readOnly: true }
|
||||
- { name: job, mountPath: /job }
|
||||
command: ["/bin/sh", "/job/backup-job.sh"]
|
||||
{{- end }}
|
||||
Reference in New Issue
Block a user