feat: Add automated backups for Forgejo (Postgres + git repos)
- CNPG Barman backup to Hetzner S3 (s3://k8s-and-chill-backups/forgejo/cnpg/) - ScheduledBackup CR: daily at 2 AM, 30d retention, prefer-standby - Git repo rclone sync to S3 (s3://k8s-and-chill-backups/forgejo/git/) via CronJob at 3 AM - Requires secrets: forgejo-backup-s3 (S3 creds), hcloud-token (not used but created) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
25714eeef6
commit
167fc62b92
|
|
@ -4,8 +4,12 @@
|
||||||
---
|
---
|
||||||
#@overlay/match-child-defaults missing_ok=True
|
#@overlay/match-child-defaults missing_ok=True
|
||||||
spec:
|
spec:
|
||||||
|
ignoreDifferences:
|
||||||
|
- group: ""
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
jsonPointers:
|
||||||
|
- /spec/volumeName
|
||||||
syncPolicy:
|
syncPolicy:
|
||||||
#@overlay/match missing_ok=True
|
|
||||||
syncOptions:
|
syncOptions:
|
||||||
#@overlay/append
|
#@overlay/append
|
||||||
- Replace=true
|
- RespectIgnoreDifferences=true
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,24 @@ spec:
|
||||||
limits:
|
limits:
|
||||||
memory: 512Mi
|
memory: 512Mi
|
||||||
|
|
||||||
|
backup:
|
||||||
|
barmanObjectStore:
|
||||||
|
endpointURL: https://fsn1.your-objectstorage.com
|
||||||
|
destinationPath: s3://k8s-and-chill-backups/forgejo/cnpg
|
||||||
|
s3Credentials:
|
||||||
|
accessKeyId:
|
||||||
|
name: forgejo-backup-s3
|
||||||
|
key: ACCESS_KEY_ID
|
||||||
|
secretAccessKey:
|
||||||
|
name: forgejo-backup-s3
|
||||||
|
key: SECRET_ACCESS_KEY
|
||||||
|
wal:
|
||||||
|
compression: gzip
|
||||||
|
data:
|
||||||
|
compression: gzip
|
||||||
|
retentionPolicy: "30d"
|
||||||
|
target: prefer-standby
|
||||||
|
|
||||||
postgresql:
|
postgresql:
|
||||||
parameters:
|
parameters:
|
||||||
shared_buffers: "64MB"
|
shared_buffers: "64MB"
|
||||||
|
|
|
||||||
17
prototypes/forgejo/ytt/cnpg-scheduled-backup.ytt.yaml
Normal file
17
prototypes/forgejo/ytt/cnpg-scheduled-backup.ytt.yaml
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
#@ load("@ytt:data", "data")
|
||||||
|
|
||||||
|
#@ ns = data.values.application.namespace
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: postgresql.cnpg.io/v1
|
||||||
|
kind: ScheduledBackup
|
||||||
|
metadata:
|
||||||
|
name: forgejo-daily-backup
|
||||||
|
namespace: #@ ns
|
||||||
|
spec:
|
||||||
|
cluster:
|
||||||
|
name: forgejo-cnpg
|
||||||
|
schedule: "0 0 2 * * *"
|
||||||
|
method: barmanObjectStore
|
||||||
|
backupOwnerReference: cluster
|
||||||
|
target: prefer-standby
|
||||||
87
prototypes/forgejo/ytt/git-snapshot-cronjob.ytt.yaml
Normal file
87
prototypes/forgejo/ytt/git-snapshot-cronjob.ytt.yaml
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
#@ load("@ytt:data", "data")
|
||||||
|
|
||||||
|
#@ ns = data.values.application.namespace
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: forgejo-git-backup
|
||||||
|
namespace: #@ ns
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: batch/v1
|
||||||
|
kind: CronJob
|
||||||
|
metadata:
|
||||||
|
name: forgejo-git-backup
|
||||||
|
namespace: #@ ns
|
||||||
|
spec:
|
||||||
|
schedule: "0 3 * * *"
|
||||||
|
concurrencyPolicy: Forbid
|
||||||
|
successfulJobsHistoryLimit: 3
|
||||||
|
failedJobsHistoryLimit: 3
|
||||||
|
jobTemplate:
|
||||||
|
spec:
|
||||||
|
ttlSecondsAfterFinished: 86400
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
restartPolicy: OnFailure
|
||||||
|
serviceAccountName: forgejo-git-backup
|
||||||
|
nodeSelector:
|
||||||
|
kubernetes.io/hostname: ubuntu-4gb-nbg1-3
|
||||||
|
containers:
|
||||||
|
- name: backup
|
||||||
|
image: alpine:3.20
|
||||||
|
command:
|
||||||
|
- sh
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
set -e
|
||||||
|
apk add --no-cache rclone > /dev/null 2>&1
|
||||||
|
|
||||||
|
mkdir -p /tmp/rclone
|
||||||
|
cat > /tmp/rclone/rclone.conf <<CONF
|
||||||
|
[s3]
|
||||||
|
type = s3
|
||||||
|
provider = Other
|
||||||
|
access_key_id = ${ACCESS_KEY_ID}
|
||||||
|
secret_access_key = ${SECRET_ACCESS_KEY}
|
||||||
|
endpoint = https://fsn1.your-objectstorage.com
|
||||||
|
acl = private
|
||||||
|
CONF
|
||||||
|
|
||||||
|
echo "Syncing git repositories to S3..."
|
||||||
|
rclone sync /data/git/ s3:k8s-and-chill-backups/forgejo/git/ \
|
||||||
|
--config /tmp/rclone/rclone.conf \
|
||||||
|
--transfers 4 \
|
||||||
|
-v
|
||||||
|
|
||||||
|
echo "Syncing gitea data (avatars, attachments, keys)..."
|
||||||
|
rclone sync /data/gitea/ s3:k8s-and-chill-backups/forgejo/gitea/ \
|
||||||
|
--config /tmp/rclone/rclone.conf \
|
||||||
|
--exclude 'conf/**' \
|
||||||
|
--exclude 'queues/**' \
|
||||||
|
--transfers 4 \
|
||||||
|
-v
|
||||||
|
|
||||||
|
rm -rf /tmp/rclone
|
||||||
|
echo "Backup complete."
|
||||||
|
env:
|
||||||
|
- name: ACCESS_KEY_ID
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: forgejo-backup-s3
|
||||||
|
key: ACCESS_KEY_ID
|
||||||
|
- name: SECRET_ACCESS_KEY
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: forgejo-backup-s3
|
||||||
|
key: SECRET_ACCESS_KEY
|
||||||
|
volumeMounts:
|
||||||
|
- name: data
|
||||||
|
mountPath: /data
|
||||||
|
readOnly: true
|
||||||
|
volumes:
|
||||||
|
- name: data
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: forgejo-git-storage
|
||||||
|
|
@ -11,6 +11,11 @@ spec:
|
||||||
destination:
|
destination:
|
||||||
namespace: forgejo
|
namespace: forgejo
|
||||||
server: https://kubernetes.default.svc
|
server: https://kubernetes.default.svc
|
||||||
|
ignoreDifferences:
|
||||||
|
- group: ""
|
||||||
|
jsonPointers:
|
||||||
|
- /spec/volumeName
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
project: env-production
|
project: env-production
|
||||||
source:
|
source:
|
||||||
path: rendered/envs/production/forgejo
|
path: rendered/envs/production/forgejo
|
||||||
|
|
@ -23,4 +28,4 @@ spec:
|
||||||
syncOptions:
|
syncOptions:
|
||||||
- CreateNamespace=true
|
- CreateNamespace=true
|
||||||
- ServerSideApply=true
|
- ServerSideApply=true
|
||||||
- Replace=true
|
- RespectIgnoreDifferences=true
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,23 @@ metadata:
|
||||||
name: forgejo-cnpg
|
name: forgejo-cnpg
|
||||||
namespace: forgejo
|
namespace: forgejo
|
||||||
spec:
|
spec:
|
||||||
|
backup:
|
||||||
|
barmanObjectStore:
|
||||||
|
data:
|
||||||
|
compression: gzip
|
||||||
|
destinationPath: s3://k8s-and-chill-backups/forgejo/cnpg
|
||||||
|
endpointURL: https://fsn1.your-objectstorage.com
|
||||||
|
s3Credentials:
|
||||||
|
accessKeyId:
|
||||||
|
key: ACCESS_KEY_ID
|
||||||
|
name: forgejo-backup-s3
|
||||||
|
secretAccessKey:
|
||||||
|
key: SECRET_ACCESS_KEY
|
||||||
|
name: forgejo-backup-s3
|
||||||
|
wal:
|
||||||
|
compression: gzip
|
||||||
|
retentionPolicy: 30d
|
||||||
|
target: prefer-standby
|
||||||
bootstrap:
|
bootstrap:
|
||||||
initdb:
|
initdb:
|
||||||
database: forgejo
|
database: forgejo
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,77 @@
|
||||||
|
apiVersion: batch/v1
|
||||||
|
kind: CronJob
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
a8r.io/repository: ssh://git@git.tr1ceracop.de:222/gitea_admin/k8s-and-chill.git
|
||||||
|
name: forgejo-git-backup
|
||||||
|
namespace: forgejo
|
||||||
|
spec:
|
||||||
|
concurrencyPolicy: Forbid
|
||||||
|
failedJobsHistoryLimit: 3
|
||||||
|
jobTemplate:
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- command:
|
||||||
|
- sh
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
set -e
|
||||||
|
apk add --no-cache rclone > /dev/null 2>&1
|
||||||
|
|
||||||
|
mkdir -p /tmp/rclone
|
||||||
|
cat > /tmp/rclone/rclone.conf <<CONF
|
||||||
|
[s3]
|
||||||
|
type = s3
|
||||||
|
provider = Other
|
||||||
|
access_key_id = ${ACCESS_KEY_ID}
|
||||||
|
secret_access_key = ${SECRET_ACCESS_KEY}
|
||||||
|
endpoint = https://fsn1.your-objectstorage.com
|
||||||
|
acl = private
|
||||||
|
CONF
|
||||||
|
|
||||||
|
echo "Syncing git repositories to S3..."
|
||||||
|
rclone sync /data/git/ s3:k8s-and-chill-backups/forgejo/git/ \
|
||||||
|
--config /tmp/rclone/rclone.conf \
|
||||||
|
--transfers 4 \
|
||||||
|
-v
|
||||||
|
|
||||||
|
echo "Syncing gitea data (avatars, attachments, keys)..."
|
||||||
|
rclone sync /data/gitea/ s3:k8s-and-chill-backups/forgejo/gitea/ \
|
||||||
|
--config /tmp/rclone/rclone.conf \
|
||||||
|
--exclude 'conf/**' \
|
||||||
|
--exclude 'queues/**' \
|
||||||
|
--transfers 4 \
|
||||||
|
-v
|
||||||
|
|
||||||
|
rm -rf /tmp/rclone
|
||||||
|
echo "Backup complete."
|
||||||
|
env:
|
||||||
|
- name: ACCESS_KEY_ID
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
key: ACCESS_KEY_ID
|
||||||
|
name: forgejo-backup-s3
|
||||||
|
- name: SECRET_ACCESS_KEY
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
key: SECRET_ACCESS_KEY
|
||||||
|
name: forgejo-backup-s3
|
||||||
|
image: alpine:3.20
|
||||||
|
name: backup
|
||||||
|
volumeMounts:
|
||||||
|
- mountPath: /data
|
||||||
|
name: data
|
||||||
|
readOnly: true
|
||||||
|
nodeSelector:
|
||||||
|
kubernetes.io/hostname: ubuntu-4gb-nbg1-3
|
||||||
|
restartPolicy: OnFailure
|
||||||
|
serviceAccountName: forgejo-git-backup
|
||||||
|
volumes:
|
||||||
|
- name: data
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: forgejo-git-storage
|
||||||
|
ttlSecondsAfterFinished: 86400
|
||||||
|
schedule: 0 3 * * *
|
||||||
|
successfulJobsHistoryLimit: 3
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
apiVersion: postgresql.cnpg.io/v1
|
||||||
|
kind: ScheduledBackup
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
a8r.io/repository: ssh://git@git.tr1ceracop.de:222/gitea_admin/k8s-and-chill.git
|
||||||
|
name: forgejo-daily-backup
|
||||||
|
namespace: forgejo
|
||||||
|
spec:
|
||||||
|
backupOwnerReference: cluster
|
||||||
|
cluster:
|
||||||
|
name: forgejo-cnpg
|
||||||
|
method: barmanObjectStore
|
||||||
|
schedule: 0 0 2 * * *
|
||||||
|
target: prefer-standby
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
a8r.io/repository: ssh://git@git.tr1ceracop.de:222/gitea_admin/k8s-and-chill.git
|
||||||
|
name: forgejo-git-backup
|
||||||
|
namespace: forgejo
|
||||||
Loading…
Reference in a new issue