L'automatisation dans Azure Kubernetes Services avec Azure DevOps
Thomas Rannou
Posted on February 10, 2021
Dans cet article nous allons parler d’industrialisation avec un cluster Azure Kubernetes Services. Nous verrons comment :
- Automatiser le déploiement d'un cluster avec Terraform
- Automatiser le déploiement d’une application dans ce même cluster.
Let's go.
Automatiser le déploiement d’un AKS avec Terraform et Azure DevOps !
Dans cette première partie, je vous propose de configurer un pipeline Azure DevOps pour exécuter un script Terraform afin de provisionner un cluster Azure Kubernetes Services (AKS) !
Terraform
Terraform est un outil d’Infrastructure As Code qui permet de décrire les ressources (VM, VNet, Web App, cluster Kubernetes, base de données) à provisionner dans un environnement auquel on se connecte au moyen d’un provider.
Il peut s’agir d’un environnement Cloud comme Azure, AWS, GCP ou un environnement on premise virtualisé avec VMWare par exemple. L’infrastructure est décrite grâce au langage de configuration HCL (Hashicorp Configuration Language).
Pour une approche globale de Terraform avec Azure je vous renvoie à cette très bonne vidéo (et sa suite) réalisée par Stanislas Quastana.
Azure DevOps
Les élements présentés ici sont tous disponible dans ce répo GitHub.
Importer les fichiers
Dans mon projet Azure DevOps fraichement créé, onglet Repos j’importe les 6 fichiers disponibles :
Nous avons à disposition les fichiers suivants :
- outputs.tf : permet de spécifier les informations renvoyées par Terraform à l’issu du déploiement
- provider.tf : spécifie le provider cible : ici azurerm, permettra à Terraform de comprendre qu’il cible un déploiement dans le cloud Microsoft
- variables.tf : la définition des variables utilisées dans le script
- variables.tfvars : l’affectation de ces même variables
- main.tf : le script Terraform en lui-même
Voyons maintenant les parties importantes de ces scripts pour notre automatisation.
Les variables
Dans le fichier .tfvars nous avons ceci :
On set les variables avec des valeurs assez abstraites pour le moment, ces variables seront renseignées à l’exécution du pipeline.
Le main.tf
Ce script contient un certain nombre de choses.
La description du Backend pour le stockage du tfstate :
La description du ressource group qui contiendra nos ressources Azure :
La définition d’un Azure Container Registry :
La définition du cluster Azure Kubernetes Services :
On remarque dans ce script l’utilisation des variable définies dans le tfvars au moyen de : ${var.nomDeLaVariable} et la relation entre les composants. Par exemple le resource_group_name et la location du cluster référence le resource group précédemment créé.
On notera également la configuration du node pool ou on précise que l’on utilisera des VM de type D2_V2 déployés dans 3 Availability Zone pour un cluster hautement disponible. Ce node pool est déployé en se basant sur le mécanisme Azure des VMSS.
J’ai également configuré un backend qui cible un Storage Account dans Azure. Cet espace de stockage héberge un conteneur : terraform-azure-kubernetes-tfstate.
Cet espace, je l’ai créé depuis le portail Azure. Il est de type Storage V2 et est en accessibilité publique. Mon conteneur est lui en accessibilité “Objet Blob”. On peut donc accéder à une ressource précise mais il n’est pas possible de lister toutes les ressources présentes dans le conteneur.
La documentation complète pour créer un Azure Storage Account est ici !
Service Connection
Avant de créer notre pipeline Azure DevOps nous aller configurer un service connection à notre tenant Azure. Pour cela dans les Project settings sélectionner l’onglet Service Connections.
Puis ajouter votre service connection. Vous devrez renseigner les informations suivantes :
Pour créer un service principal vous pouvez utiliser cette commande dans une fenêtre Powershell ou le shell du portail Azure :
az ad sp create-for-rbac --name spTerraformAzDo
Pour obtenir le tenantId et le subscriptionId vous pouvez utiliser cette commande :
az account show
Le pipeline
Il faut maintenant créer notre Pipeline pour exécuter ce script Terraform. Dans l’onglet Pipeline, choisir New Pipeline :
Mon code est ici stocké dans mon repo Azure DevOps mais il pourrait tout à fait être utilisé directement depuis mon repo GitHub.
Je choisis mon repository local :
Ici le pipeline est déjà écrit, il faut donc le réutiliser et sélectionner le fichier yml correspondant, ici nommé sobrement azure-pipelines.
Les variables du pipeline
Maintenant que notre pipeline est créé et avant de le détailler et de l’exécuter nous allons lui fournir les variables dont il aura besoin à l’exécution. Pour cela, sélectionner Variables :
Vous allez devoir créer et valoriser l’ensemble de ces variables :
Ici vous avez dû remarquer que toutes mes variables déclarées ont le même nom que la valeur affectée à la variable Terraform dans mon fichier tfvars modulo les deux underscores positionnés avant et après le nom :
aks-cluster-name = __ aks-cluster-name __
Le contenu du pipeline
Si on s’intéresse maintenant au pipeline en lui-même on y trouve tout d’abord la copie des fichiers dans un espace de travail temporaire :
Gestion des variables
Etapes très importante ! Ici nous allons parcourir les fichiers tfvars et provider.tf pour y trouver __ positionnées autour d’un nom de variable. Exemple : __ aks-cluster-name __
Quand on en trouve, on remplace le contenu par la valeur renseignée précédemment dans la variable du pipeline :
Ainsi __ aks-cluster-name __ devient “lenomdemoncluster”.
On passe ensuite à la récupération de la dernière version de Terraform précisée dans une variable également :
Il est maintenant temps de voir les 3 étapes nécessaire à Terraform pour déployer mon cluster.
Init
Le Init permet de tester la connexion à l’environnement cible, ici ma souscription Azure et mon backend. Ce backend, un storage account Azure, doit, je le rappelle, avoir été créé au préalable.
Plan
Le plan permet de comparer le contenu décrit dans le script à son infrastructure actuelle (via le tfstate). Ainsi Terraform obtient une liste d’élément à supprimer / modifier / créer.
Apply
L’étape Apply permet de réaliser le déploiement de notre infrastructure sur Azure. Ici aussi j’ai besoin de passer dans commandOptions le nom de mon fichier de variables.
(Une étape Terraform Validate peux être présente entre le Init et le Plan pour valider la sémantique du script Terraform).
Une fois mon pipeline enregistré, un build démarre :
Le pipeline est en cours d’exécution :
Si vous cliquez sur l’étape Deploy vous obtiendrez les détails de l’exécution du traitement :
Une fois l’exécution achevée, vous pourrez vérifier sur le portail Azure le bon déploiement de votre ressource group contenant un Azure Container Registry et un cluster Azure Kubernetes Services :
Une fois le script exécuté Terraform m’affichera en vert toutes les informations demandées en output.
Vérifions maintenant notre déploiement !
Je me connecte au cluster via :
Az aks get-credentials -–resource-group rg-aks --name clustervacd
Et j’exécute la commande ci-dessous pour vérifier que mes nœuds sont bien sur des Availability Zones différentes :
kubectl describe nodes | select-string -pattern '^Name:','zone='
Dans Azure, si je retourne dans mon espace de stockage je trouve mon fichier tfstate !
Grace à ce state, si je réexécute mon pipeline, il n’y aura pas de redéploiement de mon cluster, puisqu’il existe déjà.
En revanche, si je modifie le node_count dans mon main.tf et que je le positionne à 10 :
Un build se relance automatiquement et je pourrais trouver dans les logs :
Ici Terraform a identifié, grace au tfstate, que ma ressource était bien présente (0 to Add) mais qu’il faut la modifier (1 to change).
Pendant le build, mon node pool se verra appliquer la modification demandée et passera automatiquement de 3 à 10 nœuds :
Voilà pour cette automatisation du déploiement d’un cluster AKS avec Terraform et Azure DevOps ! Terraform nous a ici permis de décrire un cluster AKS hautement disponible grâce aux Availability Zone.
On passe maintenant à la configuration d’un pipeline d’intégration / déploiement continu d’une application sur ce cluster fraichement créé !
Configurer un pipeline CI/CD Azure DevOps pour déployer dans AKS
Nous allons déployer sur notre cluster AKS une application hébergée sur GitHub toujours grâce à Azure DevOps !
Prérequis
Nous avons pour le moment créé :
- Un Azure Container Registry pour stocker l’image Docker générée
- Un cluster Azure Kubernetes Services pour hoster mon application
On peut passer à la partie applicative !
Je crée, tout d’abord, un nouveau projet Azure DevOps :
Mon code étant hébergé sur GitHub, je peux directement passer à la création du pipeline dans l’onglet Pipeline :
J’indique que mon code est sur GitHub, il faudra que vous vous identifiez sur votre compte quand Azure DevOps vous le demandera :
Je choisis le repository concerné :
https://github.com/thomasrannou/DemoAppAzDo
Cette fois-ci je ne vais pas immédiatement lancer de build (Run). Je choisis donc de sauvegarder mon pipeline en l’état (Save) :
Avant de l’exécuter, j’ai besoin d’ajouter 2 services connexion à mon projet Azure DevOps, une connexion à mon Container Registry Azure et une seconde à mon cluster AKS.
Cela va se passer dans les “project settings”, onglet “Service Connections”. J’ajoute dans un premier temps une “Docker Registry service connection” que je nomme acr-connexion:
Vous devez ici choisir votre souscription Azure et le container registry que vous venez de créer précédemment. De même pour établir une connexion avec le cluster AKS (aks-connexion) :
De retour sur mon pipeline, on peut maintenant ajouter les variables globales (bouton Variables) :
J’ai besoin d’une variable “containerRegistry” avec l’url de ma registry précédemment créée. L’url de votre registry se présente comme ceci : nomdelaregistry suivi de azurecr.io.
Ainsi que le nom de l’image Docker “imageRepository”, ici valorisée comme ceci :
Je peux maintenant exécuter mon pipeline (Run) :
J’ai un indicateur visuel sur mon déploiement :
Une fois le build terminé, un :
kubectl get pods
m’indique que 5 pods exécutent mon application. Via un :
kubectl get services
je vois également que celle-ci est accessible via une external-ip :
Description du pipeline
On va maintenant passer en revue le pipeline que nous venons d’exécuter pour comprendre comment on en arrive à ce résultat !
Tout d’abord, on définit les variables de traitement :
- Le nom de ma service connexion à mon Container Registry (acr-connexion)
- Le path du dockerfile (présent sur GitHub)
- Un tag automatiquement généré par le build
- Le nom de mon pull secret, nous y reviendrons.
Première étape : le push sur ma registry, je dois ici renseigner que je veux effectuer un Docker « build and push » avec en paramètres :
- le nom de mon repository (applicationnetcore)
- le path du Dockerfile de mon projet
- la connexion à utiliser pour atteindre mon registry
- le tag généré précédemment
Déploiement
Le déploiement sur mon cluster Kubernetes sera réalisée grâce aux deux fichiers yml présent dans le dossier manifest de mon repository. On trouve un deployment.yml et un service.yml.
En vue de mon installation, je dois modifier (dans mon pipeline) le fichier Deployment.yml pour valoriser :
image: #{containerRegistry}#/#{imageRepository}#:#{tag}#
Pour ce faire, je vais utiliser l’instruction replacetokens. Je précise ici que je veux analyser les fichier .yml pour y trouver des chaines de caractère telles que #{texte}# et les remplacer par une valeur concrète renseignée dans les variables du pipeline (globales comme locales, les deux fonctionnent) :
Après cette étape, le contenu de mon fichier de travail deployment.yml sera par exemple :
image: registryacrdemo.azurecr.io/applicationnetcore:25
Kubernetes exige ensuite un secret pour que mon cluster puisse récupérer l’image sur mon container registry :
J’utilise enfin mes deux fichiers yml pour déployer mon application et un service pour l’exposer sur le port 80.
Modification du projet
Mon projet déployé ressemble à ceci :
Si je modifie la page pour ajouter une image, je peux créer une nouvelle branche :
Et déclencher une pull request :
Qui, une fois validée, va lancer un nouveau build coté Azure DevOps :
Mon application se met alors automatiquement à jour via un rolling update Kubernetes !
C'est la fin de cette mise en œuvre de pipeline Azure DevOps pour automatiser la gestion de mon cluster AKS ainsi que le déploiement d’applications !
J’espère que cet article vous aura été utile !
A bientôt.
Thomas
Posted on February 10, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.