L'automatisation dans Azure Kubernetes Services avec Azure DevOps

thomasrannou

Thomas Rannou

Posted on February 10, 2021

L'automatisation dans Azure Kubernetes Services avec Azure DevOps

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) !

Alt Text

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 :

Alt Text

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 :

Alt Text

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 :

Alt Text

La description du ressource group qui contiendra nos ressources Azure :

Alt Text

La définition d’un Azure Container Registry :

Alt Text

La définition du cluster Azure Kubernetes Services :

Alt Text

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.

Alt Text

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.

Alt Text

Puis ajouter votre service connection. Vous devrez renseigner les informations suivantes :

Alt Text

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
Enter fullscreen mode Exit fullscreen mode

Pour obtenir le tenantId et le subscriptionId vous pouvez utiliser cette commande :

az account show
Enter fullscreen mode Exit fullscreen mode

Le pipeline

Il faut maintenant créer notre Pipeline pour exécuter ce script Terraform. Dans l’onglet Pipeline, choisir New Pipeline :

Alt Text

Mon code est ici stocké dans mon repo Azure DevOps mais il pourrait tout à fait être utilisé directement depuis mon repo GitHub.

Alt Text

Je choisis mon repository local :

Alt Text

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.

Alt Text

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 :

Alt Text

Vous allez devoir créer et valoriser l’ensemble de ces variables :

Alt Text

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 :

Alt Text

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 :

Alt Text

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 :

Alt Text

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.

Alt Text

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.

Alt Text

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.

Alt Text

(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 :

Alt Text

Le pipeline est en cours d’exécution :

Alt Text

Si vous cliquez sur l’étape Deploy vous obtiendrez les détails de l’exécution du traitement :

Alt Text

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 :

Alt Text

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
Enter fullscreen mode Exit fullscreen mode

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='
Enter fullscreen mode Exit fullscreen mode

Alt Text

Dans Azure, si je retourne dans mon espace de stockage je trouve mon fichier tfstate !

Alt Text
Alt Text

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 :

Alt Text

Un build se relance automatiquement et je pourrais trouver dans les logs :

Alt Text

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).

Alt Text

Pendant le build, mon node pool se verra appliquer la modification demandée et passera automatiquement de 3 à 10 nœuds :

Alt Text

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 :

Alt Text

Mon code étant hébergé sur GitHub, je peux directement passer à la création du pipeline dans l’onglet Pipeline :

Alt Text

J’indique que mon code est sur GitHub, il faudra que vous vous identifiez sur votre compte quand Azure DevOps vous le demandera :

Alt Text

Je choisis le repository concerné :
https://github.com/thomasrannou/DemoAppAzDo

Alt Text

Cette fois-ci je ne vais pas immédiatement lancer de build (Run). Je choisis donc de sauvegarder mon pipeline en l’état (Save) :

Alt Text

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.

Alt Text

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:

Alt Text

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) :

Alt Text

De retour sur mon pipeline, on peut maintenant ajouter les variables globales (bouton Variables) :

Alt Text

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.

Alt Text

Ainsi que le nom de l’image Docker “imageRepository”, ici valorisée comme ceci :

Alt Text

Je peux maintenant exécuter mon pipeline (Run) :

Alt Text

J’ai un indicateur visuel sur mon déploiement :

Alt Text

Une fois le build terminé, un :

kubectl get pods
Enter fullscreen mode Exit fullscreen mode

m’indique que 5 pods exécutent mon application. Via un :

kubectl get services 
Enter fullscreen mode Exit fullscreen mode

je vois également que celle-ci est accessible via une external-ip :

Alt Text

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.

Alt Text

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

Alt Text

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.

Alt Text

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) :

Alt Text

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 :

Alt Text

J’utilise enfin mes deux fichiers yml pour déployer mon application et un service pour l’exposer sur le port 80.

Alt Text

Modification du projet

Mon projet déployé ressemble à ceci :

Alt Text

Si je modifie la page pour ajouter une image, je peux créer une nouvelle branche :

Alt Text
Alt Text

Et déclencher une pull request :

Alt Text

Qui, une fois validée, va lancer un nouveau build coté Azure DevOps :

Alt Text
Alt Text

Mon application se met alors automatiquement à jour via un rolling update Kubernetes !

Alt Text

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

💖 💪 🙅 🚩
thomasrannou
Thomas Rannou

Posted on February 10, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related