mirror of
https://gitlab.kube.huskypup.net/Scooby/Homelabv4.git
synced 2026-08-20 23:16:49 +00:00
Add VPS warm-standby/backup site (Phase 0-1b)
Foundation for a DR/backup path using an always-on VPS as a second ArgoCD-managed cluster, plus DB/backup standardization work that fell out of it: - vps-standby ArgoCD cluster destination + AppProject, MinIO backup receiver, VPS bootstrap script (k3s, Netbird, cert-manager) - Dual-site DNS failover watcher + home-IP DDNS CronJob, Cloudflare token moved out of git into Vault+ExternalSecret - Nextcloud migrated from ad-hoc MariaDB to CNPG + redis-operator (matches n8n/Authentik/GitLab's backup-native pattern) - Authentik's CNPG manifests moved into the actual ArgoCD-synced manifests/ path (were present but never wired into the sync path) - Vault raft-snapshot CronJob, CNPG barmanObjectStore backups (Authentik/n8n/Nextcloud), Nextcloud file-PVC restic sync - all targeting the new VPS MinIO receiver See VPS Warm-Standby plan doc for full design rationale.
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
---
|
||||
# Syncs Nextcloud's file PVC content (nextcloud-nextcloud, 200Gi) to the VPS
|
||||
# MinIO backup receiver via restic. The one piece of the Nextcloud backup story
|
||||
# no operator covers - actual file blobs, not database rows (DB is handled by
|
||||
# CNPG's barmanObjectStore in cnpg-cluster.yaml).
|
||||
#
|
||||
# Caveat: this backs up the live-mounted volume with no application-level
|
||||
# quiesce (no Nextcloud maintenance-mode pause around the snapshot). Acceptable
|
||||
# for a no-real-data test environment; for anything with real user data, pair
|
||||
# this with `occ maintenance:mode --on` before / `--off` after.
|
||||
#
|
||||
# Uses podAffinity to land on the same node as a running Nextcloud pod, since
|
||||
# the PVC is RWO (Ceph RBD) - RWO allows multiple pods to mount it concurrently
|
||||
# only when co-located on the same node. Verify the label selector below
|
||||
# matches the actual Nextcloud chart's pod labels before relying on this.
|
||||
apiVersion: generators.external-secrets.io/v1alpha1
|
||||
kind: Password
|
||||
metadata:
|
||||
name: nextcloud-restic-password
|
||||
namespace: nextcloud
|
||||
spec:
|
||||
length: 48
|
||||
digits: 5
|
||||
symbols: 5
|
||||
symbolCharacters: "-_$@"
|
||||
noUpper: false
|
||||
allowRepeat: true
|
||||
---
|
||||
apiVersion: external-secrets.io/v1
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
name: nextcloud-restic-password
|
||||
namespace: nextcloud
|
||||
spec:
|
||||
refreshInterval: "0" # generate once - changing this after the repo is initialized would lock you out of existing backups
|
||||
target:
|
||||
name: nextcloud-restic-password
|
||||
creationPolicy: Owner
|
||||
data: []
|
||||
dataFrom:
|
||||
- sourceRef:
|
||||
generatorRef:
|
||||
apiVersion: generators.external-secrets.io/v1alpha1
|
||||
kind: Password
|
||||
name: nextcloud-restic-password
|
||||
---
|
||||
apiVersion: batch/v1
|
||||
kind: CronJob
|
||||
metadata:
|
||||
name: nextcloud-pvc-sync
|
||||
namespace: nextcloud
|
||||
spec:
|
||||
schedule: "0 2 * * *" # daily at 02:00 - bulky, don't run it as often as the DB backups
|
||||
concurrencyPolicy: Forbid
|
||||
successfulJobsHistoryLimit: 3
|
||||
failedJobsHistoryLimit: 3
|
||||
jobTemplate:
|
||||
spec:
|
||||
backoffLimit: 2
|
||||
template:
|
||||
spec:
|
||||
restartPolicy: Never
|
||||
affinity:
|
||||
podAffinity:
|
||||
requiredDuringSchedulingIgnoredDuringExecution:
|
||||
- labelSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: nextcloud
|
||||
topologyKey: kubernetes.io/hostname
|
||||
containers:
|
||||
- name: restic-backup
|
||||
image: restic/restic:0.16.4
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- |
|
||||
set -eu
|
||||
export RESTIC_REPOSITORY="s3:http://${VPS_MINIO_ENDPOINT}/nextcloud-files/restic-repo"
|
||||
export RESTIC_PASSWORD_FILE=/restic-secret/password
|
||||
export AWS_ACCESS_KEY_ID="${MINIO_ACCESS_KEY}"
|
||||
export AWS_SECRET_ACCESS_KEY="${MINIO_SECRET_KEY}"
|
||||
|
||||
restic snapshots >/dev/null 2>&1 || restic init
|
||||
|
||||
echo "==> Backing up /data..."
|
||||
restic backup /data --tag nextcloud --host nextcloud-k8s
|
||||
|
||||
echo "==> Pruning: keep 7 daily, 4 weekly, 6 monthly..."
|
||||
restic forget --tag nextcloud --host nextcloud-k8s \
|
||||
--keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune
|
||||
|
||||
echo "==> Done."
|
||||
env:
|
||||
# VPS's Netbird address - replace once bootstrapped, matches
|
||||
# infrastructure/vault/manifests/raft-snapshot-cronjob.yaml
|
||||
- name: VPS_MINIO_ENDPOINT
|
||||
value: "vps-minio.netbird.internal:30900"
|
||||
- name: MINIO_ACCESS_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: vps-minio-secret
|
||||
key: accesskey
|
||||
- name: MINIO_SECRET_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: vps-minio-secret
|
||||
key: secretkey
|
||||
volumeMounts:
|
||||
- name: nextcloud-data
|
||||
mountPath: /data
|
||||
readOnly: true
|
||||
- name: restic-secret
|
||||
mountPath: /restic-secret
|
||||
readOnly: true
|
||||
volumes:
|
||||
- name: nextcloud-data
|
||||
persistentVolumeClaim:
|
||||
claimName: nextcloud-nextcloud
|
||||
- name: restic-secret
|
||||
secret:
|
||||
secretName: nextcloud-restic-password
|
||||
items:
|
||||
- key: password
|
||||
path: password
|
||||
Reference in New Issue
Block a user