Cinq étapes, pas douze
Installer, tester, construire, déployer en recette, déployer en production. Tout le reste est du confort qui se paiera en incompréhension.
Nous avons hérité de pipelines de plusieurs centaines de lignes, avec des étapes conditionnelles, des scripts appelés par d'autres scripts, et une seule personne capable d'expliquer pourquoi le déploiement échouait le vendredi. Le jour où cette personne part en congé, l'équipe ne déploie plus. Un pipeline doit pouvoir être lu, compris et modifié par n'importe quel développeur de l'équipe en dix minutes.
Étape 1 : installer, de façon reproductible
La première étape récupère le code et installe les dépendances. Elle paraît triviale ; c'est pourtant là que naissent la plupart des « ça marche sur ma machine ».
- Les versions sont verrouillées. Le fichier de verrouillage des dépendances (composer.lock, package-lock.json) est versionné, et le pipeline installe exactement ce qu'il contient, rien de plus.
- L'environnement est fixé. Même version du langage qu'en production, dans la même image de conteneur.
- Le cache est utilisé pour les dépendances, afin que l'étape prenne quelques secondes et non quelques minutes.
Étape 2 : tester, vite et à chaque fois
Les tests tournent à chaque envoi de code, sur chaque branche. Pas seulement avant une mise en production : à chaque fois. Un test qui ne tourne qu'une fois par mois finit par être cassé en permanence, et plus personne ne le regarde.
Nous regroupons dans cette étape tout ce qui vérifie le code sans le déployer :
- l'analyse statique et le formatage, qui échouent en quelques secondes ;
- les tests unitaires ;
- les tests d'intégration, avec une base de données jetable créée pour l'occasion ;
- l'audit des dépendances, qui signale les bibliothèques présentant une faille connue.
La contrainte que nous nous imposons est la durée : moins de dix minutes. Au-delà, les développeurs cessent d'attendre le résultat, enchaînent sur autre chose et découvrent l'échec une heure plus tard. Si les tests deviennent trop longs, on les parallélise ou on les répartit, mais on ne les supprime pas.
Un test instable, qui échoue une fois sur dix sans raison, est traité comme une panne : il est corrigé ou mis en quarantaine dans la journée. Sinon, l'équipe prend l'habitude de relancer le pipeline jusqu'à ce qu'il passe, et le jour où l'échec est réel, plus personne n'y croit.
Étape 3 : construire une seule fois
La construction produit l'artefact qui sera déployé : une image de conteneur, une archive, un paquet. Le principe essentiel : on construit une seule fois, et on déploie le même artefact partout. Ce qui part en production est exactement ce qui a été validé en recette, octet pour octet.
Reconstruire pour chaque environnement, c'est prendre le risque qu'une dépendance ait changé entre-temps. La différence entre les environnements se fait uniquement par la configuration : variables d'environnement, secrets, adresses des services. Jamais par le code.
L'artefact porte un identifiant traçable, généralement l'empreinte du commit. Devant n'importe quel incident, on sait exactement quelle version tourne et quel code elle contient.
Étape 4 : déployer en recette, automatiquement
Chaque fusion sur la branche principale déclenche un déploiement automatique en recette. Personne n'a à le demander. La recette reflète donc toujours l'état réel du code, et le métier peut tester les nouveautés dès qu'elles sont prêtes.
Ce déploiement est suivi de quelques vérifications rapides : la page d'accueil répond, la connexion fonctionne, les migrations de base de données sont passées. Pas une batterie de tests exhaustive, juste de quoi savoir que l'application est vivante.
Étape 5 : déployer en production, sur décision humaine
La mise en production utilise le même script que la recette, avec le même artefact. Seule différence : elle est déclenchée par une personne, d'un clic. Cette validation n'a rien de bureaucratique ; elle permet de choisir le moment, d'éviter le vendredi soir et de prévenir les utilisateurs si nécessaire.
Deux règles l'accompagnent :
- Le retour arrière est prévu. Redéployer la version précédente doit prendre une minute et ne demander aucune réflexion. Comme l'artefact précédent existe toujours, c'est un simple redéploiement.
- Les migrations sont compatibles. Une modification de base de données doit fonctionner avec l'ancienne et la nouvelle version du code, pour que le retour arrière reste possible.
Les secrets n'ont rien à faire dans le dépôt
Mots de passe de base de données, clés d'API, certificats : aucun ne doit apparaître dans le code ni dans le fichier du pipeline. Ils sont stockés dans le gestionnaire de secrets de la plateforme d'intégration continue, injectés au moment du déploiement, et différents pour chaque environnement. La recette n'a jamais accès aux secrets de production.
C'est aussi ce qui permet d'ouvrir le pipeline à toute l'équipe sans inquiétude : chacun peut le lire et le modifier, personne ne voit les clés.
Ce que nous avons volontairement laissé de côté
Nous aurions pu ajouter des environnements intermédiaires, des déploiements progressifs par pourcentage d'utilisateurs, des tests de charge à chaque fusion, des approbations multiples. Certains projets en ont besoin. La plupart, non, et surtout pas au démarrage.
Chaque étape ajoutée doit répondre à un incident réel ou à un risque identifié. « On ne sait jamais » n'est pas une justification : c'est le chemin le plus court vers un pipeline que personne ne comprend.
La page en question
Notre règle de départ tient en une phrase : si le fichier de configuration du pipeline ne tient pas sur un écran, il est trop compliqué. Les détails vivent dans des scripts nommés clairement, que l'on peut lancer à la main depuis son poste. Le pipeline ne fait que les enchaîner.
Un bon pipeline est ennuyeux : il passe au vert, il déploie, et personne n'en parle. C'est précisément ce que l'on attend de lui.
Si votre équipe redoute les mises en production, le problème est rarement le code. C'est presque toujours le chemin qui l'amène en production.