Previous slide Next slide Toggle fullscreen Open presenter view 
Velero: sauvegardez et restaurez (proprement) vos applications Kubernetes 
Rémi Verchère @ Accenture 
 
Qui suis-je ? 
Rémi Verchère 
 
DevOps, Cloud, Kubernetes, Backup ? 
 
La hype du backup 
 
Backup & Kubernetes 
Pourquoi ? 
Conteneurs Stateless 
Manifest YAML facilement redéployables 
CI/CD 
GitOps 
Boucle de réconciliation 
kubectl apply || crictl run et c'est réglé ^^Plein d'autres raisons approximatives... 
 
 
Backup & Kubernetes 
Parce que, dans la vraie vie... 
Conteneurs Statefull 
Migration & Protection des données 
Reprise après sinistre 
Ressources en prod pas "exactement" les mêmes  
L'erreur est humaine  
 
$ kubectl delete namespace la-prod
 
 
Velero - Généralités 
Un peu d'histoire 
Heptio Ark, "open-sourcé" mi 2017 
Racheté par VMware fin 2018 
Intégré à l'offre Tanzu (TMC) 
Actuellement en version 1.9 
 
$ git log --reverse
commit 2fe501f527a88ea292ca3dde80992ec60b388dda
Author: Andy Goldstein <andy.goldstein@gmail.com>
Date:   Wed Aug 2 13:27:17 2017 -0400
 
Velero - Généralités 
Fonctionnalités principales 
Sauvegarde  des ressources d'un cluster et les restaure  en cas de perte.Migration  des ressources d'un cluster à un autre.Réplication  d'un cluster de production vers des clusters de dev et test.Custom Ressources  qui définissent quoi sauvegarder, comment et quand (selector, schedule) 
Composants 
Serveur qui tourne sur votre cluster 
Client en ligne de commande qui s'exécute localement 
 
 
 
Velero - Installation 
Cluster: Chart Helm 
$ helm repo add vmware-tanzu https://vmware-tanzu.github.io/helm-charts && helm repo update
$ helm install velero vmware-tanzu/velero --create-namespace -n velero
Release "velero"  has been installed. Happy Helming!
Poste client: CLI 
$ asdf plugin add velero && asdf install velero 1.9.1 && asdf global velero 1.9.1
$ velero version
Client:
        Version: v1.9.1
        Git commit: e4c84b7b3d603ba646364d5571c69a6443719bf2
Server:
        Version: v1.9.1
 
Aurélie Vache - Understanding Kubernetes in a visual way 
Aurélie Vache - Understanding Kubernetes in a visual way 
Mise en situation : la prod 
 
Il était une fois la prod "de confiance" 
Contexte  
Plusieurs clusters Kubernetes managés OVHcloud  & Scaleway 
OVHcloud: Storage object Openstack Swift  & block Cinder  
Scaleway: Storage object S3  
 
 
Outils majoritairement Open Source 
Applications hétérogènes  
Backup sur stockage S3 , OVHcloud ou Scaleway selon les cas, régions  
Besoin de répliquer les applications sur cluster de test 
Possibilité de PRA sur un autre  cloud provider 
 
 
Exemple d'application 
Nextcloud 
Chart Helm 
1 déploiement de l'application 
1 base Mariadb 
1 cache Redis (master / replicas) 
Ingress, Cronjobs, etc. 
 
https://github.com/nextcloud/helm 
 
Exemple d'application 
Nextcloud 
$ kubectl get deployment,statefulset,cronjob,service,ingress
NAME                        READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nextcloud   1/1     1            1           28d
NAME                                        READY   AGE
statefulset.apps/nextcloud-mariadb          1/1     28d
statefulset.apps/nextcloud-redis-master     1/1     28d
statefulset.apps/nextcloud-redis-replicas   1/1     28d
NAME                           SCHEDULE       SUSPEND   ACTIVE   LAST SCHEDULE   AGE
cronjob.batch/nextcloud-cron   */15 * * * *   False     0        62s             28d
NAME                               TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
service/nextcloud                  ClusterIP   10.3.124.75    <none>        8080/TCP   28d
service/nextcloud-mariadb          ClusterIP   10.3.145.33    <none>        3306/TCP   28d
service/nextcloud-redis-headless   ClusterIP   None           <none>        6379/TCP   28d
service/nextcloud-redis-master     ClusterIP   10.3.207.110   <none>        6379/TCP   28d
service/nextcloud-redis-replicas   ClusterIP   10.3.249.214   <none>        6379/TCP   28d
NAME                                  CLASS    HOSTS                     ADDRESS                            PORTS     AGE
ingress.networking.k8s.io/nextcloud   <none>   nextcloud.demo.vrchr.fr   ip-135-125-84-204.gra.lb.ovh.net   80, 443   28d
 
Backup & Restore, l'aventure... 
 
Velero - Première fois 
1er backup 
$ velero backup create nextcloud-backup-1 --include-namespaces nextcloud
$ velero backup describe nextcloud-backup-1
Name:         nextcloud-backup-1
Namespace:    velero
[...]
Phase:  Completed
Errors:    0
Warnings:  0
[...]
Total items to be backed up:  200
Items backed up:              200
[...]
 
Velero - Première fois 
1er restore 
$ velero restore create nextcloud-restore-1 --from-backup nextcloud-backup-1
$ velero restore nextcloud-restore-1
Name:         nextcloud-restore-1
Namespace:    velero
Labels:       <none>
Annotations:  <none>
Phase:                       Completed
Total items to be restored:  200
Items restored:              200
 
Velero - Première fois 
1er fail 
Objets kubernetes sauvés, données sacrifiées !
 
 
Velero Snapshots, Backups, Restore 
Volumes Persistants 
 
Velero - Sauvegarde des données 
Objects Kubernetes 
Les objets kubernetes sont exportés sur bucket S3
3 types de storage  pour les données persistantes 
Snapshots  des Persistent Volumes (PV) via API  du Cloud Provider
 
Snapshots  des Persistent Volumes (PV) via CSI  (>= version 1.4 )
 
 
Export  volumes montés des pods sur Bucket S3 via Restic  
 
Velero - Snapshots PV via API 
 
Velero - Snapshots PV via CSI 
 
Velero - Snapshot PV via CSI 
Activation avec chart Helm 
Sous réserve que votre CSI le supporte : --features=EnableCSI
snapshotsEnabled:  true 
[... ]
configuration: 
  [... ]
  features:  EnableCSI 
[... ]
initContainers: 
  -  name:  velero-plugin-for-csi 
    image:  velero/velero-plugin-for-csi:v0.3.1 
    volumeMounts: 
      -  mountPath:  /target 
        name:  plugins 
 
Velero - Snapshot PV via CSI 
J'ai testé pour vous 
$  velero backup get                                        
NAME                            STATUS            ERRORS   WARNINGS   CREATED                          EXPIRES   STORAGE LOCATION   SELECTOR
daily-s3-20220920000000         Failed            0        0          2022-09-20 02:00:00 +0200 CEST   1d        velero-gra9        <none>
daily-s3-20220916000004         Completed         0        0          2022-09-16 02:00:04 +0200 CEST   1d        velero-gra9        <none>
daily-s3-20220915000003         Completed         0        0          2022-09-15 02:00:03 +0200 CEST   5h        velero-gra9        <none>
daily-snapshot-20220920010027   Failed            0        0          2022-09-20 03:00:27 +0200 CEST   1d        velero-gra9        <none>
daily-snapshot-20220915010003   Completed         0        0          2022-09-15 03:00:03 +0200 CEST   6h        velero-gra9        <none>
$  kubectl logs -f velero-5b86bc8db-5p8md 
time="2022-10-03T19:32:22Z" level=info msg="Waiting for volumesnapshotcontents
snapcontent-bc5660db-b0a4-4cc5-98cb-a071d5473dcb to have snapshot handle. Retrying in 5s" [...]
time="2022-10-03T19:32:27Z" level=info msg="Waiting for volumesnapshotcontents
snapcontent-bc5660db-b0a4-4cc5-98cb-a071d5473dcb to have snapshot handle. Retrying in 5s" [...]
 
Velero - Snapshot PV via CSI 
J'ai insisté, avec les équipes du CSP 
$  velero backup get                                        
NAME                            STATUS      ERRORS   WARNINGS   CREATED                          EXPIRES   STORAGE LOCATION   SELECTOR
daily-s3-20221004182135         Completed   0        0          2022-10-04 20:21:35 +0200 CEST   1d        velero-gra9        <none>
daily-s3-20221004181435         Completed   0        0          2022-10-04 20:14:35 +0200 CEST   1d        velero-gra9        <none>
[...]
daily-snapshot-20221004190535   Completed   0        0          2022-10-04 21:05:35 +0200 CEST   1d        velero-gra9        <none>
daily-snapshot-20221004190035   Completed   0        0          2022-10-04 21:00:35 +0200 CEST   1d        velero-gra9        <none>
daily-snapshot-20221004185535   Completed   0        0          2022-10-04 20:55:35 +0200 CEST   1d        velero-gra9        <none>
daily-snapshot-20221004185035   Completed   0        0          2022-10-04 20:50:35 +0200 CEST   1d        velero-gra9        <none>
[...]
 
Velero - Backup via Restic 
 
Velero - Backup via Restic 
Activation avec chart Helm 
deployRestic:  true  
[... ]
configuration: 
  [... ]
  defaultVolumesToRestic:  true 
[... ]
initContainers: 
  
  -  name:  velero-plugin-for-aws 
    image:  velero/velero-plugin-for-aws:v1.5.1 
    volumeMounts: 
      -  mountPath:  /target 
        name:  plugins 
 
Velero - Backup via Restic 
2 modes  de backup 
Opt-in : rien par défaut, on sélectionne ce qu'on veut sauvegarder 
podAnnotations: 
  
  backup.velero.io/backup-volumes-includes:  nextcloud-main 
Opt-out : tout par défaut, on sélectionne ce qu'on veut exclurePar défaut depuis Velero 1.5  
podAnnotations: 
  
  backup.velero.io/backup-volumes-excludes:  redis-data 
 
Velero - Restore 
Données (PV/PVC) 
Si Snapshot API ou CSI: Restore  du volume, puis remapping  / reference
 
Si Restic: Création  d'un nouveau volume, réhydratation  des données
 
 
 
Velero - Restore avec Restic 
 
 
Velero - Snapshots ou Restic ? 
Snapshot 
Restic 
 
 
Non atomique 
Non atomique 
 
Même média 
Média différent 
 
Plus rapide 
Plus lent 
 
Proche 
Distant ( 
 
Non chiffré ( 
Chiffré 
 
Même Cloud Provider ( 
Cloud Provider Agnostic 
 
 
 
Velero - Snapshots ou Restic ? 
Rappels de bonnes pratiques 
voir même 3-2-1-1 
 
Velero - Snapshots ou Restic ? 
Les 2  ! Mais... 
Bien configurer l'opt-in  / opt-out  côté Restic (defaultVolumesToRestic )
 
Bien configurer includes  / excludes  des volumes
 
Bien configurer l'utilisation de snapshots (--snapshot-volumes)
 
 
Si opt-in  && includes  : pas de snapshots des volumes 
 
time="2022-10-02T00:01:04Z" level=info msg="Skipping snapshot of persistent volume \
because volume is being backed up with restic."
 
Velero - Snapshots ou Restic ? 
Mes recommendations 
opt-out  par défaut
 
1 schedule classique: backup S3, avec excludes  pour certains volumes, sans snapshots (snapshotVolumes: false )
 
1 schedule snapshots: defaultVolumesToRestic: false  (opt-in 
 
Dans le doute : Restic 
 
 
 
 
Restic - Généralités 
Simple
 
Multi backend (Local, SFTP, S3, ...)
 
Rapide (Backup Incrémental & Déduplication)
 
Secure
 
Intégré à Velero
 
 
Restic is a backup program that is fast, efficient and secure. It supports the three major operating systems (Linux, macOS, Windows) and a few smaller ones (FreeBSD, OpenBSD). 
 
 
Restic - Incrémental 
Backup  
Restore  
Velero won’t restore a resource if a that resource is scaled to 0 and already exists in the cluster. 
 
 
Restic - Restauration partielle 
Exemple de besoin : récupérer juste  1 fichier effacé par un humain 
Comment le récupérer depuis le repository restic ?
$  export  AWS_SECRET_KEY_ID="Si vous lisez ce message, RDV sur le stand Accenture" $  export  AWS_SECRET_ACCESS_KEY="Place offerte pour le DevOps D-Day aux 2 premiers" $  export  ACN_SECRET_CODE="velero" 
$  restic snapshots -r s3:https://s3.fr-par-.scw.cloud/backup-velero-nextcloud/restic/nextcloud 
enter password for repository:
 
Restic - Securité 
Secure : Restic uses cryptography to guarantee confidentiality and integrity of your data. The location the backup data is stored is assumed not to be a trusted environment (e.g. a shared space where others like system administrators are able to access your backups). Restic is built to secure your data against such attackers.
 
Those of you familiar with restic may know that it encrypts all of its data. Velero uses a static, common encryption key for all Restic repositories it creates 
 
$ kubectl get secret velero-restic-credentials -o jsonpath="{.data.repository-password}" \
| base64 -d 
https://github.com/vmware-tanzu/velero/pull/4961 
 
Restic - Atomicité 
Note that cluster backups are not strictly atomic. If Kubernetes objects are being created or edited at the time of backup, they might not be included in the backup. The odds of capturing inconsistent information are low, but it is possible 
 
Idée (à la ***) 
Scale à 0 juste avant le backup, au moins pas d'écritures ! 
 
Velero’s Restic integration backs up data from volumes by accessing the node’s filesystem, on which the pod is running. For this reason, Velero’s Restic integration can only backup volumes that are mounted by a pod and not directly from the PVC 
 
 
 
 
Velero - Hooks 
 
Et 1 autre sur les Bases de Données ! 
 
Velero - BDD & Atomicité 
Utilisation des hooks  avec fsfreeze, sqldump
 
Utilisation de BDD réplica en read-onlyréplica , à l'ancienne 
 
 
En dehors  du cluster Kubernetes
 
Utilisation de BDD managée  
 
 
Blueprints de backups ? Voir Kanister  
 
 
 
Velero - Cas d'une migration cloud 
 
Velero - Cas d'une migration cloud 
Quelques points de vigilance
$  velero restore --exclude-resources CustomResourceDefinition,CertificateRequest,Order 
Storage différent : "Changing PV/PVC Storage Class" 
 
kind:  ConfigMap 
metadata: 
  labels: 
    velero.io/change-storage-class:  RestoreItemAction 
data: 
  <old-storage-class>:  <new-storage-class> 
 
 
 
Velero - Cas d'une migration cloud 
Temps de restauration assez long  (si plusieurs centaines de Go)bascule 
Flag --existing-resource-policy pour restore "incrémental" ? 
 
 
 
 
Velero - Cas d'une migration cloud 
Temps de restauration assez long  (si plusieurs centaines de Go)bascule  
 
 
OpenShift MTC 
 
 
 
Velero - Backup qui s'est mal passé 
Storage Location  
spec: 
    storageLocation:  ovh-velero-storage-location 
Timeout  
configuration: 
  resticTimeout:  2h 
 
Velero - Backup qui s'est mal passé 
Objets S3  
 
Velero - Backup qui s'est mal passé 
Restic OOMKilled ! https://tip.golang.org/doc/gc-guide ) 
configuration: 
  extraEnvVars: 
    GOGC:  10 
resources: 
  limits: 
    cpu:  null 
    memory:  2Gi 
restic: 
  resources: 
    limits: 
      cpu:  "2" 
      memory:  4Gi 
 
Velero - Backup qui s'est mal passé 
Restic Locked backend  
stderr=unable to create lock in backend: repository is already locked exclusively by PID 11108
on velero-76cfbd7858-5fr8t by nonroot (UID 65532, GID 65532)
lock was created at 2022-09-30 04:00:05 (1m5.593684965s ago)
storage ID 44a72b6f the `unlock` command can be used to remove stale locks
exit status 1" error.file="/go/src/github.com/vmware-tanzu/velero/pkg/restic/backupper.go:184"
error.function="github.com/vmware-tanzu/velero/pkg/restic.(*backupper).BackupPodVolumes"
logSource="pkg/backup/backup.go:417"
name=nextcloud-mariadb-0
$ kubectl patch backupstoragelocation <STORAGE LOCATION NAME> \
    --namespace velero \
    --type merge \
    --patch '{"spec":{"accessMode":"ReadOnly"}}'
 
Velero - Backup qui s'est mal passé 
Restic, NFS & ReadWriteMany  
5.1. Backup Serveur NFS
5.2. Backup PV Pod 1
5.3. Backup PV Pod 2 
5.4. Backup PV Pod N 
 
msg="Pod volume uses a persistent volume claim which has already been backed up \
with restic from another pod, skipping."
 
Velero - Restore qui s'est mal passé 
Restic Annotations 
 
Selector 
 
 
$ kubectl get all -l app=mariadb-database
NAME                      READY   STATUS    RESTARTS   AGE
pod/mariadb-database-0   1/1     Running   0          93d
 
Velero - Restore qui s'est mal passé 
Base de données corrompue  !aussi  sur Restore 
 
metadata: 
      annotations: 
        backup.velero.io/backup-volumes:  data 
        pre.hook.backup.velero.io/command:  '["/bin/bash", "-c",
          "mkdir -p /bitnami/mariadb/backups \
          && mysqldump -u $MARIADB_USER -p$MARIADB_PASSWORD \
          $MARIADB_DATABASE > /bitnami/mariadb/backups/nextcloud.dump"]' 
Faut-il aussi pouvoir récupérer les dumps (tar)...
$  kubectl cp  nextcloud-mariadb-0:~/nextcloud.dump ./nextcloud.dump                                                          
command terminated with exit code 126
 
Velero - Restore qui s'est mal passé 
Statefulset disparu ?!velero.io/change-storage-class  
 
$  velero restore create nextcloud-migration-22091501 --from-backup nextcloud-22091501 
$  velero restore describe nextcloud-migration-22091501 
[...]
Phase: PartiallyFailed (run 'velero restore logs nextcloud-migration-22091501' for more information)
Total items to be restored:  105
Items restored:              105
Started:    2022-09-15 21:02:46 +0200 CEST
Completed:  2022-09-15 22:13:04 +0200 CEST
[...]
Errors:
  Namespaces:
    nextcloud:  error preparing statefulsets.apps/nextcloud/nextcloud-mariadb: rpc error: code = Aborted desc = plugin panicked: \
                runtime error: invalid memory address or nil pointer dereference
                error preparing statefulsets.apps/nextcloud/nextcloud-redis-master: rpc error: code = Aborted desc = plugin panicked: \
                runtime error: invalid memory address or nil pointer dereference
[...]
 
 
Monitoring 
metrics: 
  serviceMonitor: 
    enabled:  true 
# HELP velero_backup_attempt_total Total number of attempted backups
# HELP velero_backup_deletion_success_total Total number of successful backup deletions
# HELP velero_backup_duration_seconds Time taken to complete backup, in seconds
# HELP velero_backup_failure_total Total number of failed backups
# HELP velero_backup_items_errors Total number of errors encountered during backup
# HELP velero_backup_validation_failure_total Total number of validation failed backups
# HELP velero_csi_snapshot_attempt_total Total number of CSI attempted volume snapshots
successful volume snapshots
# HELP velero_restore_attempt_total Total number of attempted restores
# HELP velero_restore_total Current number of existent restores
# HELP velero_restore_validation_failed_total Total number of failed restores failing validations
# HELP velero_volume_snapshot_attempt_total Total number of attempted volume snapshots
 
Monitoring 
 
Alerting ! 
 
 
Derniers conseils 
Lisez la doc  Velero ! 
Vérifiez  l'état de vos backupsValidez vos restaurations régulièrement  
On n'est pas obligé de tout  mettre dans Kubernetes, cf services managés   
 
Ils utilisent Velero 
Openshift "OADP" & "MTC" 
VMware "TMC" 
Accenture  
Vous ? Parlons-en ! 
 
 
Merci ! 
2022.devops-dday.com 
Rémi Verchère @ Accenture 
 
Notes: Je hais les backups, mais je hais encore plus perdre des données.
Depuis quelques temps j'administre des cluster k8s & applications qui tournent dessus.
On m'a présenté Velero comme l'outil magique,  mais j'y crois pas trop ;)
J'ai pas trouvé bcp de ressources FR sur le sujet, d'où ce talk pour partager avec vous mes galères !
Pas de sauvegarde d'ETCD / Control planes, on reste sur l'applicatif
1. The Velero client makes a call to the Kubernetes API server to create a Backup object.
2. The BackupController notices the new Backup object and performs validation.
3. The BackupController begins the backup process. It collects the data to back up by querying the API server for resources.
4. The BackupController makes a call to the object storage service – for example, AWS S3 – to upload the backup file.
CSI: Container Storage Interface
⚠️  `fsfreeze` & montages NFS
# Velero - Cas d'une migration cloud
- Installation de Velero sur les 2 clusters.
  - Configuration des mêmes Storage Location (Read Only)
- Backup Velero Cluster A, sur Bucket S3 avec Restic
- Restore sur Cluster B, depuis même Bucket S3 avec Restic
- Facile ! Ou pas...
Utilisation de nfs-ganesha-server-and-external-provisioner
---
# Une config de chart helm
# qui marche *à peu près*
---
# Velero - Config qui marche *à peu près*
```yaml
# *** helm get values velero
initContainers:
  - name: velero-plugin-for-aws
    image: velero/velero-plugin-for-aws:v1.5.1
    volumeMounts:
      - mountPath: /target
        name: plugins
  - name: velero-plugin-for-csi
    image: velero/velero-plugin-for-csi:v0.3.1
    volumeMounts:
    - mountPath: /target
      name: plugins
```
---
# Velero - Config qui marche *à peu près*
```yaml
configuration:
  provider: aws
  backupStorageLocation:
    name: ovh-velero-storage-location
    bucket: ovh-velero-storage-location
    default: true
    config:
      region: sbg
      s3ForcePathStyle: true
      s3Url: https://s3.sbg.cloud.ovh.net
  volumeSnapshotLocation:
    config:
      enableSharedConfig: true
      region: gra
```
---
# Velero - Config qui marche *à peu près*
```yaml
configuration:
  extraEnvVars:
    GOGC: 10
  features: EnableCSI
  defaultVolumesToRestic: true
  resticTimeout: 2h
```
---
# Velero - Config qui marche *à peu près*
```yaml
resources:
  limits:
    cpu:
    memory: "2Gi"
snapshotsEnabled: true
deployRestic: true
restic:
  resources:
    limits:
      cpu: "2"
      memory: "4Gi"
```
---
# Velero - Config qui marche *à peu près*
```yaml
credentials:
  secretContents:
    cloud: |
      [default]
      aws_access_key_id="Utilisez plutôt des secrets, bon sang !"
      aws_secret_access_key="Si votre RSSI voit ça vous êtes mal..."
metrics:
  serviceMonitor:
    enabled: true
    additionalLabels:
      release: prom
```
---
# Velero - Sauvegarde Nexcloud
## Schedule S3
Rendez-vous sur mon compte GitLab ;)
## Schedule Snapshot
Rendez-vous sur mon compte GitLab ;)
## Annotations chart Helm
Rendez-vous sur mon compte GitLab ;)