Ein Backup-System, das nur funktioniert, wenn man Zugangsdaten quer durch die Konfiguration verteilt, hat schon verloren. In meinem Lab sichern die Anwendungen ihre Daten mit VolSync nach restic — und das Schöne daran: Weder die Adresse des Remote-Repos noch sein Passwort stehen jemals im Git, und der eigentliche Anwendungs-Pod bekommt sie nie zu Gesicht.
Ein Template, viele Anwendungen
Backup soll kein Sonderfall pro App sein, sondern ein Schalter, den man umlegt. Deshalb liegt die gesamte Mechanik in einem geteilten Template unter k8s/templates/volsync/ und besteht aus vier Bausteinen:
- einer
ReplicationSource— der geplante Backup-Job, - einer
ReplicationDestination— der Restore-Pfad, - einem
PersistentVolumeClaim, der sich aus genau dieser Destination speist, - und einem
ExternalSecret, das die restic-Zugangsdaten aus Vault holt.
Eine Anwendung „abonniert“ Backups, indem sie das Template in ihre Kustomization aufnimmt und eine Handvoll Variablen stempelt. Mehr nicht.
Das Geheimnis bleibt im Tresor
Hier liegt der Kern. Das ExternalSecret zieht Repo-Adresse und Passwort aus
Vault
und baut daraus erst zur Laufzeit das Secret zusammen, das der VolSync-Mover nutzt:
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: "${APP}-volsync"
spec:
secretStoreRef:
kind: ClusterSecretStore
name: vault-backend
target:
name: "${APP}-volsync-secret"
template:
data:
RESTIC_REPOSITORY: "{{ .RESTIC_REPOSITORY }}/${APP}"
RESTIC_PASSWORD: "{{ .RESTIC_PASSWORD }}"
data:
- secretKey: RESTIC_REPOSITORY
remoteRef:
key: "${CLUSTER_NAME}/volsync/restic/borgbase"
property: repo
- secretKey: RESTIC_PASSWORD
remoteRef:
key: "${CLUSTER_NAME}/volsync/restic/borgbase"
property: key
Drei Dinge fallen auf:
- Im Git steht nichts Sensibles — nur Pfadangaben nach Vault. Repo und Passwort leben ausschließlich im Tresor.
- Pro App ein eigener Repo-Unterpfad (
{{ .RESTIC_REPOSITORY }}/${APP}). Alle teilen sich dasselbe restic-Remote bei BorgBase , aber jede App sichert in ihre eigene Ecke. - Der App-Pod sieht die Credentials nie. Nur der kurzlebige VolSync-Mover-Pod bekommt das
${APP}-volsync-secretgemountet — die Anwendung selbst hat damit nichts zu tun.
Sichern und Wiederherstellen
Die ReplicationSource ist der eigentliche Backup-Job. Sie zieht per CSI einen konsistenten Snapshot des PVCs (copyMethod: Snapshot), übergibt ihn an restic und hält eine gestaffelte Aufbewahrung vor:
spec:
sourcePVC: "${APP}"
trigger:
schedule: "${VOLSYNC_SCHEDULE}" # Standard: "0 3 * * 0" — sonntags 03:00
restic:
copyMethod: Snapshot
pruneIntervalDays: 7
repository: "${APP}-volsync-secret"
retain:
hourly: 24
daily: 7
weekly: 5
Der Restore-Pfad ist der elegante Teil: Der PVC der Anwendung wird nicht leer angelegt, sondern referenziert über dataSourceRef die ReplicationDestination. Beim ersten Anlegen kann VolSync den PVC damit direkt aus dem letzten restic-Snapshot befüllen — genau das, was man bei einem Cluster-Neuaufbau braucht:
spec:
dataSourceRef:
kind: ReplicationDestination
apiGroup: volsync.backube
name: "${APP}-dst"
Das Zusammenspiel im Überblick:
Ein handfestes Beispiel: snac
Meine snac-Instanz hält ihren gesamten Zustand in einem Verzeichnisbaum auf einem einzigen PVC — ein idealer Kandidat. Das Abonnement besteht aus zwei winzigen Stellen. In der App-Kustomization wird das Template eingebunden:
resources:
- ../../../../../../templates/volsync
- deployment.yaml
- service.yaml
- httproute.yaml
Und in der Flux-Kustomization werden die Variablen gestempelt — inklusive dependsOn: volsync, damit der Operator vorher steht:
dependsOn:
- name: volsync
postBuild:
substitute:
APP: snac
VOLSYNC_CAPACITY: 5Gi
VOLSYNC_CACHE_CAPACITY: 5Gi
VOLSYNC_STORAGECLASS: "ceph-block"
VOLSYNC_SNAPSHOTCLASS: "ceph-block"
VOLSYNC_CACHE_SNAPSHOTCLASS: "ceph-block"
Im Deployment mountet snac dann einfach den PVC namens snac, den VolSync bereitstellt — fertig. Ab da sichert sich snac jeden Sonntag um drei selbst.
Die Bedienung läuft über ein paar Tasks, die Repo-Pfad und Schlüssel im Hintergrund aus Vault ziehen:
task backup:list NS=fediverse-system APP=snac # Snapshots auflisten
task backup:snapshot NS=fediverse-system APP=snac # sofort sichern
task backup:restore NS=fediverse-system APP=snac # neuesten Stand zurückspielen
Fazit
VolSync verlagert Backups dorthin, wo sie hingehören: in die Plattform, deklarativ, pro Anwendung mit einem Dreizeiler aktivierbar. Die wirklich wichtige Eigenschaft ist aber die Trennung der Geheimnisse — Repo-Adresse und Passwort wohnen im Vault, materialisieren sich nur im flüchtigen Mover-Pod und tauchen weder im Repository noch in der Anwendung auf. So fühlt sich ein Backup-System an, dem man auch im Ernstfall vertraut.
