26 septembre 2023
By Lionel Gurret.
Dans cet article, nous allons plonger dans le processus complexe de provisionnement d’une infrastructure Azure pour faciliter la sauvegarde d’un cluster Azure Kubernetes Service (AKS). Alors que des options telles qu’Azure Backup existent, elles laissent souvent à désirer en termes de capacités d’automatisation nécessaires pour orchestrer la création des diverses ressources essentielles via Terraform.
La sauvegarde et la gestion de l’environnement AKS nous conduira à explorer en détail comment définir notre infrastructure via Terraform.
Ensuite, nous déploierons la solution de sauvegarde Velero, tirant parti du potentiel d’Helm pour simplifier et optimiser le processus. Nous mettrons en lumière les meilleures pratiques et les astuces pour assurer une mise en place réussie de Velero.
Tout au long de cet article, nous aborderons des détails techniques, des conseils pratiques et des étapes à suivre pour vous armer de l’expertise nécessaire afin de gérer efficacement votre infrastructure AKS et de garantir la protection de vos données.
Attention : contrairement à ce qui est donné la documentation officielle de vmware pour velero, la solution ne permet pas d’utiliser les Workload Identities (cf. github issue).
Dans notre contexte, le cluster AKS et son resource group ont déjà été provisionnés. Référez-vous à la documentation officielle de Terraform pour cette partie.
Voici le nom de nos ressources pour vous aider à comprendre d’avantage la suite de cet article :
resource "azurerm_resource_group" "rg" {
...
}
resource "azurerm_kubernetes_cluster" "k8s" {
...
}
Nous avons bien sûr dans notre repository, d’autres fichiers Terraform pour la déclaration des providers, des variables, du backend etc.
Ces manifestes Terraform ainsi que le pipeline de provisionnement Azure DevOps pour l’infrastructure ne seront pas couverts par cet article de blog.
Pour pouvoir stocker nos backups et nos snapshots, il est nécessaire de prévoir un storage account et un container.
Vous pouvez choisir de le créer dans le même resource group que celui du cluster AKS, ou comme expliqué dans la documentation (cf. sources), utiliser un resource group dédié aux backups.
Voici le code Terraform utilisé dans notre cas :
resource "azurerm_storage_account" "storaccbackup" {
name = "storaccbackup01"
account_replication_type = "LRS"
account_tier = "Standard"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
}
resource "azurerm_storage_container" "storcontbackup" {
name = "velero"
storage_account_name = azurerm_storage_account.storaccbackup.name
}
Vous pouvez ajouter le paramètre access_tier et le configurer à "Cool" si vos backups ne seront pas fréquemment accédés.
Pour établir un lien entre notre cluster AKS et notre storage account, nous nous reposerons sur un service principal. Comme expliqué précédemment, l’utilisation des Managed Identity n’est malheureusement pas encore disponible.
Voici un exemple de code de création de ce service principal et de ses ressources associées :
data "azuread_client_config" "current" {}
resource "azuread_application" "this" {
display_name = "aks-backup-${local.basename}"
owners = [data.azuread_client_config.current.object_id]
}
resource "azuread_service_principal" "this" {
application_id = azuread_application.this.application_id
}
resource "azuread_service_principal_password" "this" {
service_principal_id = azuread_service_principal.this.object_id
}
Ce service principal doit avoir accès au storage account, nous allons lui ajouter le rôle Contributeur :
resource "azurerm_role_assignment" "contributor_velero" {
principal_id = azuread_service_principal.this.object_id
scope = azurerm_storage_account.storaccbackup.id
role_definition_name = "Contributor"
}
Il est possible de définir un custom role afin de limiter les droits accordés à notre service principal (cf. sources).
Certains paramètres vont devoir être utilisés par Helm lorsque nous installerons Velero sur notre cluster AKS. Il est donc important de stocker les informations suivantes dans un Azure Key Vault :
resource "azurerm_key_vault" "aks_kv" {
...
}
locals {
keyvault_secrets = {
aks-backup-resource-group-name = azurerm_storage_account.storaccbackup.resource_group_name
aks-backup-storage-account-name = azurerm_storage_account.storaccbackup.name
azure-tenant-id = data.azuread_client_config.current.tenant_id
azure-backup-sp-client-id = azuread_application.this.application_id
azure-backup-sp-client-secret = azuread_service_principal_password.this.value
}
}
resource "azurerm_key_vault_secret" "keyvault_secrets" {
for_each = local.keyvault_secrets
name = each.key
value = each.value
key_vault_id = azurerm_key_vault.aks_kv.id
}
Ces variables pourront ainsi être récupérées via un vargroup Azure DevOps lié à notre Azure Key Vault et utilisées dans nos pipelines helm.
Toute l’infrastructure a été définie, on peut à présent la provisionner avec les commandes Terraform bien connues :
terraform init
terraform plan
terraform apply
Dans un autre repository Azure DevOps, nous allons maintenant préparer notre pipeline de déploiement et les fichiers de configuration de Velero.
Premièrement, nous devons créer un fichier credentials-velero contenant les informations suivantes :
AZURE_SUBSCRIPTION_ID=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXX
AZURE_TENANT_ID=#{azure-tenant-id}#
AZURE_CLIENT_ID=#{azure-backup-sp-client-id}#
AZURE_CLIENT_SECRET=#{azure-backup-sp-client-secret}#
AZURE_RESOURCE_GROUP=MC_XXXXXXXXXXXXXXXXXXXXXXXXXXXXX
AZURE_CLOUD_NAME=AzurePublicCloud
Prenez soin d’adapter la variable pour la subscription ID ainsi que l’Azure resource group. Il s’agit du resource group auto généré lors de la création du cluster AKS !
Les variables entre balises seront quant à elles modifiées par notre pipeline Azure DevOPs. Cela nous permet de ne pas afficher de données sensibles dans notre code.
Nous allons aussi passer nos différentes valeurs à Helm avant d’installer le helm chart Velero. Pour cela nous créons le fichier velero-values.yaml dans notre repository :
configuration:
backupStorageLocation:
- name: azure
bucket: velero
provider: azure
config:
resourceGroup: #{aks-backup-resource-group-name}#
storageAccount: #{aks-backup-storage-account-name}#
volumeSnapshotLocation:
- name: azure
provider: azure
config:
resourceGroup: #{aks-backup-resource-group-name}#
storageAccount: #{aks-backup-storage-account-name}#
snapshotsEnabled: true
deployNodeAgent: true
image:
repository: velero/velero
pullPolicy: Always
initContainers:
- name: velero-plugin-for-microsoft-azure
image: velero/velero-plugin-for-microsoft-azure:master
volumeMounts:
- mountPath: /target
name: plugins
Vous pouvez vous référer à la documentation suivante pour les autres configurations.
Voici à présent une partie du contenu de notre fichier de pipeline Azure DevOps qui nous servira à installer Velero sur notre cluster AKS :
...
# We load our variable from our Azure Key Vault
variables:
- group: vargroup-k8s-kv
...
# We install Helm
- task: HelmInstaller@0
displayName: Install helm
inputs:
helmVersion: '3.12.2'
installKubectl: true
# We add the necessary helm repository for Velero
- task: CmdLine@2
displayName: Add helm repos
inputs:
script: |
helm repo add vmware-tanzu https://vmware-tanzu.github.io/helm-charts
helm repo update
# We replace our variables from our "KeyVault vargroup"
- task: replacetokens@5
displayName: Replace tokens in Velero config files
inputs:
rootDirectory: './'
targetFiles: '**/*'
encoding: 'auto'
tokenPattern: 'default'
writeBOM: true
actionOnMissing: 'warn'
keepToken: true
actionOnNoFiles: 'continue'
enableTransforms: false
enableRecursion: false
useLegacyPattern: false
enableTelemetry: true
# We install Velero !
- task: HelmDeploy@0
displayName: Helm Velero
inputs:
connectionType: 'Kubernetes Service Connection'
kubernetesServiceConnection: 'XXXXXXXXXXXXXXXXXX'
namespace: 'velero'
command: 'upgrade'
chartType: 'Name'
chartName: 'vmware-tanzu/velero'
releaseName: 'velero'
valueFile: 'velero-values.yaml'
arguments: "--create-namespace --set-file credentials.secretContents.cloud=./credentials-velero"
Une fois le pipeline lancé et exécuté, nous pouvons vérifier si l’espace de stockage est bien connecté avec notre cluster AKS :
$ kubectl get BackupStorageLocation -n velero
NAME PHASE LAST VALIDATED AGE DEFAULT
azure Available 0s 26m
Nous venons d’installer Velero et son infrastructure avec succès !
Pour créer nos backups, il sera nécessaire d’utiliser le CLI velero.
Voici comment l’installer (documentation) :
wget https://github.com/vmware-tanzu/velero/releases/download/v1.11.1/velero-v1.11.1-linux-amd64.tar.gz
tar -xzvf velero-v1.11.1-linux-amd64.tar.gz
sudo chmod +x ~/velero-v1.11.1-linux-amd64/velero
sudo cp ~/velero-v1.11.1-linux-amd64/velero /usr/local/bin/
velero version
Le backup étant en place, il nous reste bien sûr à valider son fonctionnement. Pour cela, nous allons nous baser sur une application de test fournie par Velero.
Commençons par télécharger et installer l’application sur notre serveur AKS :
cd ~/velero-v1.11.1-linux-amd64/examples/nginx-app
kubectl apply -f base.yml
Vérifions que l’application a été déployée avec succès :
$ kubectl -n nginx-example get all
NAME READY STATUS RESTARTS AGE
pod/nginx-deployment-747864f4b5-8cwv2 1/1 Running 0 22h
pod/nginx-deployment-747864f4b5-w8d48 1/1 Running 0 22h
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/my-nginx LoadBalancer 10.0.24.168 20.250.58.191 80:30605/TCP 22h
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/nginx-deployment 2/2 2 2 22h
NAME DESIRED CURRENT READY AGE
replicaset.apps/nginx-deployment-747864f4b5 2 2 2 22h
Pour lancer notre premier backup, nous lançons la commande suivante :
$ velero backup create test-backup --include-namespaces nginx-example --wait --storage-location azure
Backup request "test-backup" submitted successfully.
Waiting for backup to complete. You may safely press ctrl-c to stop waiting - your backup will continue in the background.
.....
Backup completed with status: Completed. You may check for more information using the commands `velero backup describe test-backup` and `velero backup logs test-backup`.
Nous pouvons vérifier que le backup s’est déroulé correctement et que des fichiers ont été ajoutés dans notre storage container :
On peut également voir notre backup sur le serveur directement :
$ velero backup get
NAME STATUS ERRORS WARNINGS CREATED EXPIRES STORAGE LOCATION SELECTOR
test-backup Completed 0 0 2023-08-15 08:36:58 +0000 UTC 29d azure <none>
Nous allons commencer par supprimer toutes les ressources de notre namespace nginx-example pour simuler une perte de données :
$ kubectl -n nginx-example delete service my-nginx
service "my-nginx" deleted
$ kubectl -n nginx-example delete deployment nginx-deployment --force --grace-period=0
Warning: Immediate deletion does not wait for confirmation that the running resource has been terminated. The resource may continue to run on the cluster indefinitely.
deployment.apps "nginx-deployment" force deleted
$ kubectl -n nginx-example get all
No resources found in nginx-example namespace.
On peut lancer la restauration :
$ velero restore create --from-backup test-backup
Restore request "test-backup-20230815084245" submitted successfully.
Run `velero restore describe test-backup-20230815084245` or `velero restore logs test-backup-20230815084245` for more details.
Comme indiqué par le message de sortie, nous pouvons suivre le processus de restore via la commande suivante comme indiqué :
$ velero restore logs test-backup-20230815084245
time="2023-08-15T08:42:46Z" level=info msg="starting restore" logSource="pkg/controller/restore_controller.go:458" restore=velero/test-backup-20230815084245
time="2023-08-15T08:42:46Z" level=info msg="Starting restore of backup velero/test-backup" logSource="pkg/restore/restore.go:396" restore=velero/test-backup-20230815084245
time="2023-08-15T08:42:46Z" level=info msg="Resource 'customresourcedefinitions.apiextensions.k8s.io' will be restored at cluster scope" logSource="pkg/restore/restore.go:2030" restore=velero/test-backup-20230815084245
time="2023-08-15T08:42:46Z" level=info msg="Getting client for apiextensions.k8s.io/v1, Kind=CustomResourceDefinition" logSource="pkg/restore/restore.go:918" restore=velero/test-backup-20230815084245
time="2023-08-15T08:42:46Z" level=info msg="restore status includes excludes: <nil>" logSource="pkg/restore/restore.go:1189" restore=velero/test-backup-20230815084245
time="2023-08-15T08:42:46Z" level=info msg="Executing item action for customresourcedefinitions.apiextensions.k8s.io" logSource="pkg/restore/restore.go:1196" restore=velero/test-backup-20230815084245
...
Enfin, nous observons que nos ressources sont de nouveau disponibles :
$ kubectl -n nginx-example get all
NAME READY STATUS RESTARTS AGE
pod/nginx-deployment-747864f4b5-8cwv2 1/1 Running 0 15s
pod/nginx-deployment-747864f4b5-w8d48 1/1 Running 0 15s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/my-nginx LoadBalancer 10.0.196.243 20.250.76.149 80:31188/TCP 15s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/nginx-deployment 2/2 2 2 15s
NAME DESIRED CURRENT READY AGE
replicaset.apps/nginx-deployment-747864f4b5 2 2 2 15s
Tout est à présent en place pour automatiser la création des backups !
/! Ne suivez pas (pour le moment) la documentation relative aux Workload Identities
En conclusion, nous avons exploré ensemble comment mettre en place des sauvegardes Velero sur Azure AKS en utilisant Infrastructure as Code (IaC). Il est important de noter que cette méthode offre une solution de sauvegarde robuste pour vos clusters AKS, mais elle peut devenir obsolète à mesure que les fournisseurs Terraform et les services Azure continuent d’évoluer et de s’améliorer.
Chez SoKube, nous comprenons la nature dynamique des technologies cloud et nous nous engageons à rester à la pointe de ces avancées. Notre équipe d’experts est prête à vous aider à naviguer dans le paysage en constante évolution d’Azure et de Terraform. Que vous ayez besoin de guidance, de consultation ou de formation, nous sommes là pour mettre à profit notre expertise et vous fournir les connaissances et les outils nécessaires pour gérer efficacement votre infrastructure cloud.
N’hésitez pas à nous contacter pour tous vos besoins en matière d’Azure et de Terraform. Ensemble, nous pouvons garantir que votre infrastructure reste résiliente, sécurisée et à jour dans cette ère numérique en constante évolution.