Pourquoi l'ordre de déploiement est plus important que votre pipeline
Vous avez une nouvelle version de votre application prête. Le pipeline est vert. L'équipe regarde. Vous appuyez sur déployer. Quelques minutes plus tard, des erreurs apparaissent dans les logs. Les utilisateurs signalent qu'ils ne peuvent pas finaliser leurs achats. L'équipe base de données indique que le changement de schéma a été appliqué après le démarrage de l'application, et non avant.
Ce scénario n'est pas rare. Il se produit parce que le déploiement concerne rarement une seule application qui fait une seule chose. Il s'agit de la façon dont cette application se connecte à tout ce dont elle dépend. Comprendre ces connexions — et les risques qu'elles comportent — est ce qui distingue un déploiement fluide d'un incident de production.
Les dépendances ne sont pas que du code
Une application moderne ne fonctionne presque jamais seule. Elle lit depuis une base de données. Elle appelle une API pour le traitement des paiements. Elle utilise une bibliothèque tierce pour redimensionner des images. Elle dépend d'une file d'attente de messages pour envoyer des notifications. Chacune de ces choses est une dépendance, et chacune peut casser lorsque vous déployez une nouvelle version.
La dépendance la plus courante est la base de données. Votre application stocke les données utilisateur dans PostgreSQL ou MySQL. Lorsque vous déployez une nouvelle version, celle-ci lit et écrit les données différemment de l'ancienne. Peut-être que l'ancienne version stockait l'adresse d'un utilisateur dans une seule colonne, et que la nouvelle version la divise en rue, ville et code postal. Si la nouvelle version commence à s'exécuter avant que le schéma de la base de données ne soit mis à jour, elle échouera à lire les données existantes. C'est un changement cassant — les anciennes et nouvelles versions sont incompatibles entre elles.
Les dépendances incluent également les API d'autres équipes ou de services externes. Imaginez que votre application appelle une API de paiement. La nouvelle version s'attend à une réponse dans un format JSON différent. Si cette API n'a pas encore été mise à jour, votre application recevra des données qu'elle ne peut pas analyser, et les transactions échoueront. Le problème est que vous ne contrôlez pas toujours quand cette API change. Une autre équipe peut avoir son propre calendrier de déploiement, et elle peut ne pas savoir que votre application dépend d'un format de réponse spécifique.
Les bibliothèques et paquets tiers sont aussi des dépendances. Lorsque vous mettez à jour une bibliothèque de la version 1.0 à la version 2.0, des fonctions peuvent avoir été renommées ou leurs signatures modifiées. Si votre application appelle encore l'ancien nom de fonction, le code générera une erreur à l'exécution. C'est pourquoi les équipes matures suivent clairement leurs dépendances — dans des fichiers comme requirements.txt, package.json ou go.mod — et testent les nouvelles versions de bibliothèques avant de les utiliser en production.
Le risque caché : l'ordre de déploiement
Les dépendances affectent directement l'ordre dans lequel vous déployez les choses. Si l'application A dépend d'une base de données qui nécessite un changement de schéma, vous devez d'abord mettre à jour la base de données, puis déployer l'application A. Si l'application B appelle une API de l'application C, vous devez d'abord déployer l'application C, puis l'application B. Cet ordre est important car si vous l'inversez, l'application nouvellement déployée cherchera des données ou des services qui ne sont pas encore disponibles. Le résultat est des erreurs, des requêtes échouées ou une application complètement cassée.
Le diagramme de séquence suivant montre l'ordre de déploiement correct et ce qui se produit lorsqu'il est inversé :
Le risque augmente avec le nombre de dépendances. Plus il y a de services qui doivent être synchronisés, plus la probabilité que l'un d'eux ne le soit pas est élevée. Une équipe qui gère bien cela cartographie toutes les dépendances avant un déploiement, confirme l'ordre correct et prépare un plan de rollback au cas où quelque chose ne correspondrait pas. Elle utilise également des techniques comme la rétrocompatibilité — faire en sorte que la nouvelle version fonctionne toujours avec l'ancienne — pour réduire le risque de changements cassants.
Les changements cassants ne sont pas toujours évidents
Un changement cassant n'a pas besoin d'être dramatique. Il peut être subtil. Par exemple, une nouvelle version de votre application pourrait commencer à envoyer un champ supplémentaire dans une requête à une API interne. Le service récepteur ignore les champs inconnus, donc tout semble bien se passer. Mais quelques semaines plus tard, ce service récepteur est mis à jour, et il s'attend désormais à ce que ce champ supplémentaire soit présent. L'ancienne version de votre application, qui est toujours en cours d'exécution dans certains environnements, cesse de fonctionner. La panne est retardée et la cause racine est difficile à tracer.
C'est pourquoi la cartographie des dépendances n'est pas une activité ponctuelle. Elle doit être mise à jour au fur et à mesure que le système évolue. Chaque fois qu'une nouvelle dépendance est ajoutée ou qu'une dépendance existante change, l'ordre de déploiement et le profil de risque changent également.
Comment réduire le risque lié aux dépendances
Vous pouvez prendre des mesures pratiques pour rendre les déploiements plus sûrs lorsque des dépendances sont impliquées.
Premièrement, documentez vos dépendances. Cela ne signifie pas écrire un long document que personne ne lit. Cela signifie avoir un enregistrement clair et lisible par machine de ce dont votre application dépend et de ce qui dépend d'elle. Des outils comme les graphes de dépendances, les catalogues de services, ou même un simple README dans votre dépôt peuvent aider.
Deuxièmement, testez l'intégration, pas seulement l'unité. Les tests unitaires qui simulent tous les services externes ne détecteront pas les problèmes causés par le comportement réel des dépendances. Les tests d'intégration qui s'exécutent contre de vraies bases de données, API ou files d'attente de messages feront remonter les problèmes avant qu'ils n'atteignent la production.
Troisièmement, utilisez des feature flags ou des API versionnées pour maintenir la rétrocompatibilité. Si votre nouvelle version peut toujours servir les requêtes des anciens clients, vous avez plus de flexibilité dans l'ordre de déploiement. Vous pouvez déployer la nouvelle version en premier, vérifier qu'elle fonctionne, puis mettre à jour les services dépendants.
Quatrièmement, exercez-vous au rollback. Sachez exactement ce qui doit se passer si un déploiement échoue en raison d'une incompatibilité de dépendance. Pouvez-vous annuler le changement de schéma de base de données ? Pouvez-vous pointer l'application vers l'ancienne version de l'API ? Avoir un plan de rollback testé réduit la pression pendant un déploiement.
Par exemple, un script de déploiement séquentiel simple applique l'ordre correct et s'arrête en cas d'échec :
#!/bin/bash
# deploy.sh - Enforce correct deployment order
set -e # Exit on any error
echo "Step 1: Deploy database schema"
./deploy_database.sh || { echo "Database deployment failed. Aborting."; exit 1; }
echo "Step 2: Deploy backend API"
./deploy_api.sh || { echo "API deployment failed. Rolling back database..."; ./rollback_database.sh; exit 1; }
echo "Step 3: Deploy frontend"
./deploy_frontend.sh || { echo "Frontend deployment failed. Rolling back API and database..."; ./rollback_api.sh; ./rollback_database.sh; exit 1; }
echo "All deployments completed successfully."
Une checklist pratique avant votre prochain déploiement
Avant de déployer, parcourez cette courte checklist :
- Avez-vous listé chaque dépendance utilisée par votre application (base de données, API, bibliothèque) ?
- Connaissez-vous l'ordre de déploiement correct pour chaque dépendance ?
- Avez-vous testé la nouvelle version contre les versions réelles de ces dépendances ?
- Existe-t-il un plan de rollback pour chaque dépendance qui pourrait casser ?
- Avez-vous communiqué l'ordre de déploiement à chaque équipe qui possède une dépendance ?
Cette checklist n'est pas exhaustive, mais elle couvre les points de défaillance les plus courants. Si vous pouvez répondre oui aux cinq questions, vous êtes dans une bien meilleure position que la plupart des équipes.
L'essentiel à retenir
Le déploiement ne consiste pas seulement à pousser du code. Il s'agit de gérer les relations entre votre application et tout ce qu'elle touche. Les dépendances déterminent l'ordre de déploiement, le risque d'échec et la difficulté de la récupération. Une équipe qui comprend ses dépendances et planifie en conséquence aura moins d'incidents, des récupérations plus rapides et plus de confiance dans chaque release. Le pipeline est important, mais la carte des dépendances est ce qui empêche le pipeline de se transformer en exercice d'incendie.