Suite à un retour d’expérience, je vous explique comment utiliser les outils du Lean pour améliorer l’expérience des développeurs sur une Infrastructure déployée sur Azure ! 

En tant que DevOps/SRE, vous allez surement devoir faire des choix difficiles pour votre infrastructure. Il se peut que ce choix réponde à un besoin à l'instant T, mais qu'il entraine de la dette technique sur le long terme et beaucoup de frustration. Nous avons rencontré cette problématique sur le service managé d'Azure "App Service".

Pour faire état de la situation, lorsqu'un dev doit changer une variable sur son application, nous devions déployer en prod notre code Terraform, car la définition des variables utilisées par les AppService se faisait depuis notre code. Vous noterez tout de suite que le standard de la séparation Infrastructure/Code Application n'est pas du tout respecté. La déclaration des variables d'environnement des applications des développeurs devaient se faire via notre code Terraform. Cela induisait une dépendance de la part des devs et nous devions communiquer avec eux pour prévoir les modifications de celles-ci.

Pour répondre à ce problème, nous avons effectué un Kaizen, qui est un outil de la méthodologie du Lean. Cet outil permet d'analyser une problématique et d'essayer de la résoudre par petites étapes. Cet article résume donc notre épopée à la recherche de la solution idéale. Nous parlerons des différentes étapes qui nous ont menées à la solution et des différentes solutions envisagées pour séparer la configuration des variables d'environnement sur le service managé Azure App Service.

Quel est le potentiel d'amélioration ?

Cela induit en général un freeze du code Terraform de notre côté de près de trois jours. Cela n'est clairement pas une option, alors que nous n'avons que deux équipes de développeurs. Alors imaginez si nous gérons une infrastructure avec une dizaine d'équipes avec chacune des besoins.

Analyser le temps à gagner :

  • Un LeadTime de 4 jours pour déployer un changement de variable (temps disproportionné par rapport à l'opération)
  • 2 h de touch time par les DevOps pour discuter avec les devs, valider et déployer leurs changements sur notre code
  • 3 jours d'attente des DevOps avant de pouvoir lever le code freeze infra, car nous devons suivre un processus très long.

Notre objectif était donc de réduire ces 3 jours d'attente à 0.

Maintenant que nous avons défini le potentiel d'amélioration, il est important d'étudier les méthodes actuelles et de creuser. Notre objectif dans cette prochaine étape est de connaitre sur le bout des doigts nos problèmes et nos méthodes.

Que faisons-nous actuellement ?

La compréhension complète de notre problème nous permettra de mieux comprendre quels sont les points que nous pouvons/devons améliorer. Il est important de réaliser cette étape et de ne pas sauter directement à la première solution que nous avons trouvée. Cela nous permet de nous assurer que la solution trouvée est la plus adaptée et que nous n'allons pas perdre de temps en aval.

Points clés de notre infrastructure

  • L'infrastructure est sur Azure et l'application Django des développeurs tourne dans le service managé "Azure AppService"
  • L'équipe utilise du Blue Green déploiement : le déploiement en production repose sur un échange (swap) des machines de staging et de prod, pour éviter le downtime.

Le processus actuel

  • Step 1 : Les Devs préviennent les DevOps qu'ils vont ajouter/modifier une variable → Freeze du déploiement infra ❄️
  • Step 2 : Les devs font une Pull request (PR) sur le code infra pour remplacer la variable sur l'App Service staging de production
  • Step 3 : Les DevOps review la PR → Gaspillage, les DevOps ne font jamais de retour
  • Step 4 : Création de la release → On déploie en Dev, Test et UAT
  • Step 5 : Validation fonctionnelle des PO sur l'UAT
  • Step 6 : Déploiement de l'infrastructure en Production
  • Step 7 : Déploiement du code applicatif en production (avec le même processus que les DevOps, déploiement Dev, Test, UAT et validation PO)
  • Step 8 : Freeze du déploiement applicatif ❄️ Il ne faut surtout pas qu'un autre déploiement en prod soit effectué sur l'application avant la step 9
  • Step 9 : Repeat Step 2 → Step 6 pour avoir les variables d'environnement disponible dans le nouveau staging (car il y a eu un swap des instances App Service lors de la mise en production)
  • Step 10 : Arrêt du freeze du déploiement applicatif
  • Step 11 : Arrêt du freeze du déploiement Infrastructure

Observations

  • Un besoin dev entraîne un blocage sur la mise à jour de l'infrastructure = il y a un couplage dans le code qui configure les variables entre l'infra et l'applicatif
  • Améliorer ce processus n'est pas intéressant, il est absurde et existe à cause du problème d'architecture sous-jacent

Flow Actuel vs Cible

Flow Actuel :

flow_actuel

 

Idéalement, un déploiement de l'application se fait avec sa configuration, sans opération supplémentaire. La configuration pourrait aussi se faire de manière découplée (pour révoquer un mot de passe par exemple)

Flow Idéal :

flow_ideal

 

Les Ops doivent déployer deux fois les variables d'environnement : une fois pour préparer le déploiement en prod, une fois sur l'ancienne prod (devenu staging) pour permettre le rollback.

Source de chaque info dans le slot AppService :

slot_app

 

La configuration applicative se trouve dans le code de l'infrastructure.

Analyse préliminaire

À ce moment-là de notre réflexion, nous nous sommes posés certaines questions pour avancer :

  • Comment gérer les app settings autre par que Terraform ?
  • Comment gérer la config de l'app sans app settings ?

Ces deux questions nous ont permis de structurer notre raisonnement dans la suite de notre réflexion. Nous avons donc entrepris d'analyser ensuite quelles sont les variables d'environnement que nous exposons dans App Settings pour essayer d'en déduire des catégories.Certes, cette étape semble peu pragmatique, mais il est important de comprendre toutes les composantes de notre problème. Cela nous permettra de trouver une solution adéquate à notre problème et de pouvoir garantir que celle-ci est la plus adaptée.

Creuser encore : Analyse des variables d'environnement

À la suite de notre analyse des variables d'environnement qui sont déclarées dans App Settings, nous avons remarqué que sur les 69 variables déclarées seules 28 sont gérées par notre équipe de DevOps.

En résumé, nous avons 41 variables gérées par les Devs et 28 par les DevOps sur nos AppService dans notre AppConfig. À la suite de cette analyse, nous avons décidé de creuser les différents types de variables pour déterminer lesquels sont nécessaires et lesquels ne le sont pas. 

4 types de variables d'environnement dans notre AppConfig:

  • String : Chaine de caractère statique dans la ressource Terraform. Pas sensible
  • Var : Chaine de caractère dans un fichier variables-.tfvars. Pas sensible
  • Key vault : Chaine de caractère dans une ressource key vault par environnement Sensible 🛡- Peut provenir d'un ajout Terraform → cela pourrait être du state Terraform si le bucket qui contient ce state est assez sécurisé- Peut provenir d'un ajout d'un utilisateur
  • State : Référence à une chaîne de caractère dans une autre ressource Terraform

Il n'y aucune corrélation entre la source/type de variable et le rôle (DEV ou DevOps).

On en conclut que ces choix ont été arbitraires jusqu'ici et qu'il n'a jamais été challengé → Nous décidons de standardiser ce choix

Où mettre quelles variables ?

Nous avons donc décidé de créer un tableau de décision pour définir l'endroit adéquate d'une variable. 

variables

 

Cette matrice de décision a été créée:

  • String :
    • Dev: Cela doit être dans le code
    • Ops: Doit être le paramètre d'une autre resource terraform
  • KeyVault :
    • Dev: Récupérée via un outil externe
    • Ops: Pas de variable dans le keyvault car on peut y accéder depuis notre code terraform (nous créons la majorité des secrets)
  • Var :
    • Dev: Récupérée depuis un outil externe
    • Ops: Pas de variable dans une variable
  • State :
    • Dev: Pas la main dessus
    • Ops: Doit être le paramètre d'une autre ressource terraform

Il semblerait que nous nous soyons éloigné du problème. Cependant, avant de trouver la solution, nous devons nous assurer que nous n'avons pas de problèmes qui pourraient remonter plus tard, ni de points d'améliorations qui pourraient être réglés rapidement.

Nous avons donc creusé les différentes variables d'environnement pour définir un nouveau standard et nous assurer que la solution sera en adéquation avec celui-ci.

Énumérer les nouvelles idées

Maintenant que nous avons identifié le besoin, le gain et le standard, il est temps de réfléchir à une idée pour résoudre ce problème.

Voici nos idées, qu'elles soient bonnes ou mauvaises :

  • Mettre les variables d'environnement applicatives dans l'image Docker : KO : on ne veut pas build l'image à chaque déploiement et pour chaque environnement.
  • Mettre le code Terraform qui gère les variables dans la code base des devs : KO : ça ne change rien au problème, les variables des dev seront toujours dans le state de l'infra donc créera le freeze infra.
  • Utiliser Azure key vault référence in app service : KO : car ça reste dans App Settings.
  • Charger les variables d'env des DEV dans docker au démarrage : Pour ça → Mettre les variables des devs dans un storage dédié, comme un KeyVault

Choix de la solution

La solution adoptée et que l'on va étudier est le chargement des variables d'environnements dans un docker au démarrage à partir d'un KeyVault Azure managé par les devs.

Points d'attention

Avant de foncer tête baissée sur notre nouvelle idée, nous avons dû réfléchir à tout ce qui pouvait mal tourner. Il est important de toujours faire attention à ne pas introduire de nouveaux problèmes avec notre solution.

Sécurité :

  • Le docker peut accéder à un Key Vault, donc il faut créer un Key Vault dédié avec des droits dédiés

Stabilité :

  • Il faut s'assurer que Django ne démarre pas s'il y a un problème dans le script de récupération de variable
  • Idéalement, Django crash avant le swap Blue/Green s'il lui manque des variables de config

Vitesse :

  • Pas de problème de performance pour les users, les variables marcheront comme avant
  • Le Docker de l'application prendra plus de temps pour démarrer le temps de récupérer les variables d'env

 

Dernière étape : tester l'idée !

On a l'idée, on connait notre nouveau standard pour les variables, et on sait sur ce quoi nous devons faire attention il est temps de valider celle-ci.

Nous avons donc testé les points suivants :

  • Récupérer les infos d'un KeyVault en Python : ✅
  • Transformer les variables du KeyVault en fichier de variable d'environnement : ✅
  • Accéder aux variables dans le terminal après avoir sourcé le fichier : ✅
  • Mettre le script dans un Docker avec un second process python qui affiche les variables d'environnement : ✅

Maintenant que nous avons validé le POC et que nous avons pris en compte les différents points d'attention, il ne nous reste plus qu'à implémenter la solution. En suivant ce processus d'amélioration continue que nous avons entrepris - Kaizen - nous avons dorénavant une solution adaptée et claire pour résoudre notre problème.

Cette méthode peut s'appliquer à un ensemble de problèmes, que ce soit sur des problématiques techniques que managériales. Si vous voulez en savoir plus sur cette méthodologie je vous invite à regarder la méthodologie du Lean et le processus de Kaizen.

N'hésitez pas à nous poser des questions en commentaires !