Blogartikel

17.02.2023

Technologien

Cluster Backups mit Velero & Longhorn

Aktuell arbeiten wir daran, das Cloudogu EcoSystem auf Kubernetes zu migrieren. Da das bisherige Cloudogu EcoSystem Backups und Restores unterstützt, soll dies auch nach der Umstellung auf Kubernetes möglich sein. Velero ist dafür praktisch alternativlos. In diesem Post werden wir Velero und Longhorn installieren und Backups und Restores einrichten.

Warum Velero

Aktuell arbeiten wir daran, das Cloudogu EcoSystem auf Kubernetes zu migrieren. Da das bisherige Cloudogu EcoSystem Backups und Restores unterstützt, soll dies auch nach der Umstellung auf Kubernetes möglich sein.

Für unsere Zwecke ist Velero praktisch alternativlos. Es kann alle K8s-Ressourcen, aber auch Volume-Daten sichern. Backups lassen sich mit Schedules automatisch ausführen. Erweiterbar ist es durch Plugins: So lässt sich zum Beispiel auch ein S3 Bucket anbinden. Wer wie wir mit Longhorn einen anderen Storage-Provider als den Cluster-Internen benutzt, der kann diesen ganz einfach mit einem Plugin für das Container-Storage-Interface (CSI) anbinden.

Im Folgenden werden wir genau dies tun: Wir installieren Longhorn und Velero. Beides konfigurieren wir so, dass wir Backups von Teilen unseres Clusters inklusive Volume-Daten auf ein S3 (in unserem Fall MinIO) schreiben können.

Funktionsweise von Backup & Restore

Bei Velero handelt es sich um einen Kubernetes-Operator. Ein Operator hört auf das Erstellen, Ändern und Löschen bestimmter Kubernetes-Ressourcen, und verarbeitet diese. Velero hört beispielsweise auf Ressourcen vom Typ velero.io/v1/Backup und velero.io/v1/Restore.

Damit diese Ressourcen nicht manuell angelegt werden müssen, kommt Velero mit einem kleinen CLI-Tool, welches diese Aufgabe übernimmt.

Backup

Der Befehl velero backup create <backup-name> legt eine neue Backup-Ressource mit dem angegebenen Namen an. Der Velero-Server erkennt die angelegte Ressource und startet den Backup-Prozess, der alle im Backup angegebenen Ressourcen sammelt und speichert. Zur Speicherung des Backups außerhalb des Clusters können wir ein Object-Store-Plugin einbinden. In unserem Fall ist es das Velero-Plugin-for-AWS, welches die Daten auf ein S3-Bucket schreibt.

Doch was passiert mit den Volume-Daten?

Verwendet man ganz normale Kubernetes-Volumes, schreibt Velero diese zusammen mit den anderen Ressourcen in das MinIO-Bucket. Da wir jedoch Longhorn verwenden, ist dies nicht möglich. Allerdings unterstützt Longhorn das Container-Storage-Interface, über welches Velero Longhorn mitteilen kann, dass es ein Backup erstellen soll. Hier kommt das Velero-Plugin-for-CSI ins Spiel: Es erstellt einen VolumeSnapshot, was Longhorn dazu veranlasst, ein Backup zu erstellen. Wenn Longhorn nun richtig konfiguriert ist, schreibt es dieses Backup in ein S3-Bucket.

Restore

Der Befehl velero restore create --from-backup <backup-name> legt eine neue Restore-Ressource vom angegebenen Backup an. Velero erkennt die Ressource und wendet das entsprechende Backup aus dem S3-Bucket auf das Cluster an.

Um das Backup der Volumes einzuspielen, muss die dataSource des PersistentVolumeClaims auf den entsprechenden VolumeSnapshot zeigen, anstatt auf ein PersistentVolume. Auch das übernimmt das Velero-CSI-Plugin.

Anleitung für Backup & Restore mit Velero und Longhorn

Alle Dateien und Beispiele sind verfügbar auf GitHub.

Voraussetzungen

Repository klonen

git clone git@github.com:cloudogu/velero-longhorn-demo.git && cd velero-longhorn-demo

Cluster aufsetzen

Für unser Beispiel verwenden wir ein K3s-Cluster, dieses wird folgendermaßen gestartet:

vagrant up

Nun verbinden wir uns per SSH mit dem Cluster:

vagrant ssh

Natürlich ist es auch möglich, ein eigenes Cluster zu verwenden.

Notiz: Longhorn funktioniert nicht mit K3d oder KIND Ich habe sowohl K3d (K3s in Docker) als auch KIND (Kubernetes in Docker) ausprobiert. Jedoch funktioniert iscsi nicht in Containern, weswegen Longhorn dort nicht funktioniert.

MinIO einrichten

Ein lokales MinIO lässt sich mit folgendem Befehl starten:

docker run -d --name minio \
	-p 9000:9000 -p 9090:9090 \
	-e "MINIO_ROOT_USER=MINIOADMIN" \
	-e "MINIO_ROOT_PASSWORD=MINIOADMINPW" \
	quay.io/minio/minio \
	server /data --console-address ":9090"

Jetzt können wir die MinIO-Administration unter http://localhost:9000 öffnen. Anmelden können wir uns mit den in den obigen Umgebungsvariablen angegebenen Credentials.

Wir legen zwei Buckets an: longhorn und velero. Außerdem erstellen wir einen Access-Key:

  • Key ID: test-key
  • Secret Key: test-secret-key.

Longhorn

Longhorn installieren

Longhorn installieren wir nach der offiziellen Installationsanweisung:

helm repo add longhorn https://charts.longhorn.io
helm repo update
helm install longhorn \
	longhorn/longhorn \
	--namespace longhorn-system \
	--create-namespace \
	--values /vagrant/src/longhorn-values.yaml \
	--version 1.4.0

In der longhorn-values.yaml konfigurieren wir auch das Backup-Target von Longhorn, sodass Longhorn die Volume Backups auf das S3 schreibt. In der Praxis können wir dies aber auch im Nachhinein z.B. über die Longhorn-UI konfigurieren.

Nun sollten nach und nach die Pods im longhorn-system Namespace starten. Um das Cluster zu beobachten, ist das Tool k9s sehr praktisch, welches auf der VM schon vorinstalliert ist.

Longhorn konfigurieren

Bei der Installation haben wir Longhorn schon so konfiguriert, dass es die Zugangsdaten für den Ablageort des Backups aus dem minio-secret liest. Dieses Secret müssen wir nun noch anwenden:

kubectl apply -f /vagrant/src/longhorn-minio-secret.yaml

Notiz: Im Secret benutzen wir die IP 172.17.0.1, um den Host zu erreichen. Ob dies möglich ist, hängt von der Container-Runtime und Netzwerk-Konfiguration ab. In einem echten Szenario würde dieses Backup aber sowieso an einem anderen Ort liegen.

Snapshot-Controller und CSI-Snapshot-CRDs

Um CSI-Snapshots zu erstellen, benötigen wir einen Snapshot-Controller und die CSI-Snapshot-CRDs. Da diese auf K3s standardmäßig nicht installiert sind, müssen wir sie manuell installieren:

kubectl -n kube-system create -k "github.com/kubernetes-csi/external-snapshotter/client/config/crd?ref=release-5.0"

kubectl -n kube-system create -k "github.com/kubernetes-csi/external-snapshotter/deploy/kubernetes/snapshot-controller?ref=release-5.0"

Notiz: Longhorn unterstützt bisher keine Versionen des Snapshot-Controllers neuer als 5.0.

Damit der Snapshot-Controller Longhorn für die Snapshots verwendet, müssen wir eine VolumeSnapshotClass anlegen:

kubectl apply -f /vagrant/src/default-volumesnapshotclass.yaml

Diese sieht folgendermaßen aus:

kind: VolumeSnapshotClass
  apiVersion: snapshot.storage.k8s.io/v1
  metadata:
  name: longhorn-snapshot-vsc
  labels:
    velero.io/csi-volumesnapshot-class: "true"
driver: driver.longhorn.io
deletionPolicy: Delete
parameters:
  type: bak

Damit Velero die VolumeSnapshots mit unserer VolumeSnapshotClass erstellt, benötigen wir das Label velero.io/csi-volumesnapshot-class: "true".

Unter parameters geben wir type: bak an, was Longhorn sagt, dass wir ein Longhorn-Backup machen möchten. Eine Alternative wäre type: snap für Longhorn-Snapshots (inkrementelle Backups, nicht zu verwechseln mit den VolumeSnapshots). Diese haben jedoch bisher noch keine CSI-Unterstützung, können also hier nicht verwendet werden.

Velero

Velero-CLI

Das Velero-CLI installieren wir wie in der offiziellen Dokumentation angegeben über das GitHub Release:

VELERO_VERSION=v1.10.0; \
  wget -c https://github.com/vmware-tanzu/velero/releases/download/${VELERO_VERSION}/velero-${VELERO_VERSION}-linux-amd64.tar.gz -O - \
  | tar -xz -C /tmp/ \
  && sudo mv /tmp/velero-${VELERO_VERSION}-linux-amd64/velero /usr/local/bin

Velero-Server

Velero installieren wir mit Helm:

	helm repo add vmware-tanzu https://vmware-tanzu.github.io/helm-charts
	helm repo update
	helm install velero \    	
	--namespace=velero \
	--create-namespace \
	--set-file credentials.secretContents.cloud=/vagrant/src/credentials-velero \
	--set configuration.provider=aws \
	--set configuration.backupStorageLocation.name=default \
	--set configuration.backupStorageLocation.bucket=velero \
	--set configuration.backupStorageLocation.config.region=minio-default \
	--set configuration.backupStorageLocation.config.s3ForcePathStyle=true \
	--set configuration.backupStorageLocation.config.s3Url=http://172.17.0.1:9000 \
	--set configuration.backupStorageLocation.config.publicUrl=http://localhost:9000 \
	--set snapshotsEnabled=true \
	--set configuration.volumeSnapshotLocation.name=default \
	--set configuration.volumeSnapshotLocation.config.region=minio-default \
	--set "initContainers[0].name=velero-plugin-for-aws" \
	--set "initContainers[0].image=velero/velero-plugin-for-aws:v1.6.0" \
 	--set "initContainers[0].volumeMounts[0].mountPath=/target" \
 	--set "initContainers[0].volumeMounts[0].name=plugins" \
  	--set configuration.features=EnableCSI \
  	--set "initContainers[1].name=velero-plugin-for-csi" \
  	--set "initContainers[1].image=velero/velero-plugin-for-csi:v0.4.0" \
  	--set "initContainers[1].volumeMounts[0].mountPath=/target" \
  	--set "initContainers[1].volumeMounts[0].name=plugins" \
  	vmware-tanzu/velero

Wir konfigurieren hier auch schon die Plugins für S3 und CSI. Die MinIO-Credentials werden dabei direkt aus der Datei src/credentials-velero ausgelesen. snapshotEnabled=true und configuration.features=EnableCSI sind beide nötig um die CSI VolumeSnapshot Unterstützung zu aktivieren.

Testen von Backup und Restore

Um Backup und Restore zu testen, installieren wir eine kleine Testanwendung. Diese besteht aus einem simplen Pod, der ein Longhorn-Volume aus einem PVC mountet.

kubectl apply -f /vagrant/src/example-app.yaml

Nun schreiben wir Hello from Velero! in eine Datei im Volume:

kubectl -n csi-app exec -ti csi-nginx -- bash -c 'echo -n "Hello from Velero!" >> /mnt/longhorndisk/hello'

Dann machen wir ein Backup:

velero backup create csi-b1 --include-namespaces csi-app --wait

Desaster! Aus Versehen wurde der csi-app Namespace gelöscht!

kubectl delete ns csi-app

Puh! Gut, dass wir ein Backup haben! Dieses wollen wir nun wieder einspielen:

velero restore create --from-backup csi-b1 --wait

Wenn alles funktioniert hat, sollte folgender Befehl uns nun Hello from Velero! aus der zuvor erstellten Datei ausgeben:

kubectl -n csi-app exec -ti csi-nginx -- bash -c 'cat /mnt/longhorndisk/hello'

Fazit

Velero ist ein gutes und ausgereiftes Tool um Cluster Backups zu erstellen. Durch das Container-Storage-Interface ist es unabhängig vom Storage-Provider, solange dieser CSI unterstützt.

Ein Feature, welches Velero noch nicht unterstützt, sind Backups mit Ende-zu-Ende-Verschlüsselung. Da Velero Open-Source ist, ist eine Erweiterung in diese Richtung jedoch nicht ausgeschlossen. Falls dies passiert, könnt ihr euch auf einen weiteren Blog-Post freuen!

Dank asynchroner Funktionsweise sowie der Operator-Architektur integriert sich Velero hervorragend in andere Produkte. Deswegen glauben wir von Cloudogu, dass Velero die beste Backup-Lösung für das Cloudogu K8s-EcoSystem ist.

Tags