diff --git a/researchowl/backup-cronjob.yaml b/researchowl/backup-cronjob.yaml new file mode 100644 index 0000000..64abac7 --- /dev/null +++ b/researchowl/backup-cronjob.yaml @@ -0,0 +1,90 @@ +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + annotations: + # Never let ArgoCD prune this PVC: it holds the DB backups. + argocd.argoproj.io/sync-options: Prune=false + name: researchowl-backups + namespace: researchowl +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + # DB is ~220MB and growing; 7 daily copies ≈ 1.6Gi, so 2Gi would fill up. + storage: 5Gi + +--- +apiVersion: batch/v1 +kind: CronJob +metadata: + name: researchowl-db-backup + namespace: researchowl + labels: + app: researchowl +spec: + schedule: "0 3 * * *" + timeZone: "Europe/Madrid" + concurrencyPolicy: Forbid + successfulJobsHistoryLimit: 3 + failedJobsHistoryLimit: 3 + jobTemplate: + spec: + backoffLimit: 2 + activeDeadlineSeconds: 600 + template: + metadata: + labels: + app: researchowl-db-backup + spec: + restartPolicy: Never + containers: + - name: backup + image: keinos/sqlite3:latest + command: + - /bin/sh + - -c + - | + set -eu + STAMP=$(date +%Y%m%d) + DEST="/backups/researchowl-${STAMP}.db" + echo "Backing up /data/researchowl.db -> ${DEST}" + sqlite3 -cmd ".timeout 30000" /data/researchowl.db ".backup '${DEST}'" + RESULT=$(sqlite3 "${DEST}" "PRAGMA integrity_check;") + if [ "${RESULT}" != "ok" ]; then + echo "Integrity check FAILED: ${RESULT}" + rm -f "${DEST}" + exit 1 + fi + echo "Integrity check ok" + # Retention: keep the 7 most recent backups + for f in $(ls -1t /backups/researchowl-*.db | tail -n +8); do + echo "Pruning old backup ${f}" + rm -f "${f}" + done + ls -lh /backups/ + volumeMounts: + # NOT readOnly: the source DB runs in WAL mode and sqlite readers + # must be able to touch the -shm/-wal sidecar files. The job only + # ever reads the DB (.backup); it never modifies application data. + - name: data + mountPath: /data + - name: backups + mountPath: /backups + resources: + requests: + memory: "64Mi" + cpu: "50m" + limits: + memory: "256Mi" + cpu: "500m" + volumes: + # Same RWO local-path PVC as the bot: the PV's node affinity pins this + # pod to the node where the data lives, so co-mounting is safe. + - name: data + persistentVolumeClaim: + claimName: researchowl-data + - name: backups + persistentVolumeClaim: + claimName: researchowl-backups