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.
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'hui | Manque encore |
|---|---|
Velero fonctionne entièrement contre un spool dans le cluster : sauvegarde et restauration des manifestes, sync, GC, backup delete | Donné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 Completed | Import 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_id | Jobs 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.