Aller au contenu principal

Velero (aperçu)

lionbackup devient une cible de stockage pour Velero, l'outil de sauvegarde pour Kubernetes. Il existe pour cela un plugin qui enregistre lionbackup comme fournisseur de BackupStorageLocation, et un petit contrôleur dans le cluster qui téléverse chaque sauvegarde terminée sous forme d'un seul fichier chiffré dans un projet lionbackup. Les deux sont disponibles en bêta 0.2.0-beta.1 : pour essayer dans un cluster de test, pas encore comme unique sauvegarde.

Aperçu : pas encore de données de volumes

Ce qui arrive chez lionbackup, c'est le spool : manifestes Kubernetes, métadonnées et journaux de la sauvegarde. Le contenu des volumes (PVC) n'est pas encore sauvegardé ; un PVC revient sous forme de définition, mais vide. Continuez à vous appuyer sur une autre voie pour les données de volumes.

Ce que fait l'aperçu aujourd'hui, et ce qu'il ne fait pas​

Fonctionne aujourd'huiManque encore
Velero fonctionne entièrement contre un spool dans le cluster : sauvegarde et restauration des manifestes, sync, GC, backup deleteDonnées de volumes : le contenu des PVC n'est pas capturé (le node-agent de Velero ne connaît que s3, azure, gcs et le système de fichiers)
URL signées : velero backup logs et describe --details fonctionnent, les sauvegardes se terminent CompletedImport de restauration : le paquet revient dans le spool depuis l'extérieur du cluster (client avec jeton de lecture)
Téléversement : le contrôleur regroupe backups/<nom>/ en un seul .lbk, le téléverse avec un jeton d'écriture et annote la sauvegarde avec le file_idJobs de capture et de restauration des volumes ; nouvelle tentative seulement « dans 10 minutes »

Une sauvegarde Failed signifie que rien n'a été écrit ; le plus souvent, le propriétaire du répertoire du spool est alors incorrect (voir l'étape 1). Un PartiallyFailed ne survient plus que si le contrôleur ou le secret d'URL partagé manque (étape 4).

L'essayer​

Il vous faut un cluster de test, kubectl, la CLI Velero (testée avec Velero 1.18.3), un projet lionbackup avec un jeton d'écriture et le client lionbackup sur votre poste de travail pour la paire de clés. L'image du plugin se télécharge sans identifiants.

1. Créer le répertoire du spool​

Velero écrit dans un répertoire du nœud, monté dans le pod Velero en hostPath (ou en PVC). L'image officielle de Velero s'exécute avec l'ID utilisateur 1002 ; fsGroup ne s'applique pas à un hostPath, le répertoire doit donc appartenir à cet ID. Sinon chaque sauvegarde échoue avec permission denied tout en signalant tous les objets comme sauvegardés ; l'erreur n'apparaît que dans status.failureReason.

mkdir -p /var/lib/lionbackup/spool
chown -R 1002:1002 /var/lib/lionbackup/spool
chmod 775 /var/lib/lionbackup/spool

2. Installer Velero avec le plugin​

velero install \
--provider lionbackup.cloud/lionbackup \
--plugins git.prod.lionbackup.cloud/lionbackup/velero-plugin-lionbackup:0.2.0-beta.1 \
--bucket spool \
--no-secret \
--use-volume-snapshots=false \
--backup-location-config spoolPath=/var/lib/lionbackup/spool \
--wait

--no-secret est correct : le plugin lui-même n'a pas besoin d'identifiants. Le jeton d'écriture va dans le Secret du contrôleur (étape 4), jamais sur la BackupStorageLocation.

3. Monter le spool dans le pod Velero​

kubectl -n velero patch deployment velero --type=json -p '[
{"op":"add","path":"/spec/template/spec/volumes/-","value":{"name":"lionbackup-spool","hostPath":{"path":"/var/lib/lionbackup/spool","type":"DirectoryOrCreate"}}},
{"op":"add","path":"/spec/template/spec/containers/0/volumeMounts/-","value":{"name":"lionbackup-spool","mountPath":"/var/lib/lionbackup/spool"}}
]'
kubectl -n velero rollout status deploy/velero --timeout=180s
kubectl -n velero get backupstoragelocation default

Sans cette étape, le spool vit dans le système de fichiers du pod et disparaît au prochain redémarrage. La BackupStorageLocation devrait ensuite indiquer Available.

4. Contrôleur et Secret​

Le contrôleur s'exécute dans la même image, en tant qu'utilisateur 1002, avec le spool monté en lecture seule et le Secret sous /etc/lionbackup. Il lui faut trois choses : le jeton d'écriture du projet, un secret d'URL aléatoire qu'il partage avec le pod Velero, et la clé publique pour le chiffrement. Générez la paire de clés sur votre poste de travail ; la clé privée n'entre jamais dans le cluster, et sans elle il n'y a pas de restauration.

lionbackup --generate-key --key-name ./velero
kubectl -n velero create secret generic lionbackup-velero \
--from-literal=token=<WRITE-TOKEN> \
--from-literal=url-secret="$(head -c 32 /dev/urandom | base64)" \
--from-file=key.pub=./velero.pub

Enregistrez le manifeste suivant sous controller.yaml. Il contient ServiceAccount, Role, RoleBinding, Service et Deployment ; le répertoire de travail /work doit pouvoir accueillir le plus grand répertoire de sauvegarde du spool.

---
apiVersion: v1
kind: ServiceAccount
metadata:
name: lionbackup-velero-controller
namespace: velero
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: lionbackup-velero-controller
namespace: velero
rules:
- apiGroups: ["velero.io"]
resources: ["backups"]
verbs: ["get", "list", "watch", "patch"]
- apiGroups: ["velero.io"]
resources: ["backupstoragelocations"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: lionbackup-velero-controller
namespace: velero
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: lionbackup-velero-controller
subjects:
- kind: ServiceAccount
name: lionbackup-velero-controller
namespace: velero
---
apiVersion: v1
kind: Service
metadata:
name: lionbackup-velero-controller
namespace: velero
spec:
selector:
app.kubernetes.io/name: lionbackup-velero-controller
ports:
- name: http
port: 8080
targetPort: http
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: lionbackup-velero-controller
namespace: velero
labels:
app.kubernetes.io/name: lionbackup-velero-controller
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app.kubernetes.io/name: lionbackup-velero-controller
template:
metadata:
labels:
app.kubernetes.io/name: lionbackup-velero-controller
spec:
serviceAccountName: lionbackup-velero-controller
securityContext:
runAsUser: 1002
runAsGroup: 1002
runAsNonRoot: true
containers:
- name: controller
image: git.prod.lionbackup.cloud/lionbackup/velero-plugin-lionbackup:0.2.0-beta.1
command: ["/plugins/velero-plugin-lionbackup"]
args: ["controller"]
ports:
- name: http
containerPort: 8080
env:
- name: VELERO_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: LIONBACKUP_SPOOL_PATH
value: /var/lib/lionbackup/spool
- name: LIONBACKUP_KEYFILE
value: /etc/lionbackup/key.pub
- name: LIONBACKUP_WORKDIR
value: /work
- name: LIONBACKUP_TOKEN
valueFrom:
secretKeyRef:
name: lionbackup-velero
key: token
- name: LIONBACKUP_VELERO_URL_SECRET
valueFrom:
secretKeyRef:
name: lionbackup-velero
key: url-secret
readinessProbe:
httpGet:
path: /healthz
port: http
initialDelaySeconds: 3
resources:
requests:
cpu: 50m
memory: 128Mi
limits:
cpu: "2"
memory: 1Gi
volumeMounts:
- name: lionbackup-spool
mountPath: /var/lib/lionbackup/spool
readOnly: true
- name: lionbackup-secret
mountPath: /etc/lionbackup
readOnly: true
- name: work
mountPath: /work
volumes:
- name: lionbackup-spool
hostPath:
path: /var/lib/lionbackup/spool
type: Directory
- name: lionbackup-secret
secret:
secretName: lionbackup-velero
items:
- key: key.pub
path: key.pub
- name: work
emptyDir:
sizeLimit: 10Gi

Appliquez-le ensuite, transmettez aussi le secret d'URL au déploiement Velero et renseignez projet et zone sur la BackupStorageLocation :

kubectl apply -f controller.yaml
kubectl -n velero set env deployment/velero \
LIONBACKUP_VELERO_URL_SECRET="$(kubectl -n velero get secret lionbackup-velero -o jsonpath='{.data.url-secret}' | base64 -d)"
kubectl -n velero patch backupstoragelocation default --type=merge -p \
'{"spec":{"config":{"lbProject":"<PROJECT-UUID>","lbZone":"de01-1","lbEnvironment":"prod"}}}'
kubectl -n velero rollout status deploy/velero --timeout=180s
kubectl -n velero rollout status deploy/lionbackup-velero-controller --timeout=180s

Sans jeton ni clé, le contrôleur ne fait que journaliser ce qu'il téléverserait (observe-only). Autres clés config de la BackupStorageLocation : lbCompressionMethod (ZSTD), lbCompressionLevel (5), lbChunksizeMb (64), lbUploadRateLimitMbit (0 = illimité).

Les URL signées pointent vers le Service du contrôleur dans le cluster ; velero backup logs et describe --details fonctionnent donc là où ce Service est joignable. Si la CLI Velero s'exécute hors du cluster, redirigez le port (kubectl -n velero port-forward svc/lionbackup-velero-controller 8080:8080) et réglez controllerURL sur la BackupStorageLocation à http://localhost:8080 ; la signature ne couvre que le chemin et l'expiration, pas l'hôte.

5. Sauvegarde​

velero backup create demo-1 --include-namespaces demo-app --wait
velero backup logs demo-1 | tail -n 3
kubectl -n velero get backup demo-1 \
-o jsonpath='{.status.phase} {.metadata.annotations.lionbackup\.cloud/file-id}{"\n"}'

Attendez-vous à Completed, et velero backup logs renvoie le journal via l'URL signée du contrôleur. Peu après, l'objet Backup porte l'annotation lionbackup.cloud/file-id : l'identifiant du fichier téléversé dans le projet, le même que montre le --list du client. Si le téléversement échoue, la raison figure dans le journal du contrôleur, qui réessaie au bout de dix minutes.

6. Restauration depuis lionbackup​

Le chemin du retour commence hors du cluster, avec un jeton de lecture et la clé privée ; les deux restent ainsi à l'écart du cluster. Le client récupère le paquet, vous copiez le répertoire de sauvegarde dans le spool du cluster cible, et Velero le reprend à la prochaine synchronisation de la BackupStorageLocation :

lionbackup --config read.yaml --list
lionbackup --config read.yaml --restore <FILE-ID> --identity ./velero.key --target ./restored
# ./restored/…/backups/demo-1/ -> <spoolPath>/spool/backups/demo-1/ des Zielclusters
velero restore create demo-restore --from-backup demo-1 --wait

Les manifestes, déploiements, ConfigMaps et définitions de PVC reviennent. Les données des volumes, non ; c'est la limite documentée de l'aperçu.

La suite​

L'étape suivante sauvegarde le contenu des volumes : un job par PVC sur le nœud du pod transmet le volume en archive dans le spool, un job de restauration correspondant le remplit à nouveau, et un init container retient l'application jusqu'au retour du volume. S'y ajoute un point de terminaison du contrôleur qui ramène un paquet par file_id directement dans le spool. D'ici là, la remarque en haut de cette page s'applique.