Ce qu'un pipeline CI/CD doit vraiment savoir faire (au-delà du battage médiatique)

Vous poussez du code, le pipeline devient vert, le déploiement part. Mais quand ça casse, vous réalisez que le pipeline n'a jamais été conçu pour gérer l'incident. La migration de base de données s'est exécutée dans le mauvais ordre. L'artefact issu du staging est différent de celui déployé en production. Et le rollback ? Personne n'y avait pensé.

C'est le fossé entre avoir un pipeline et avoir un pipeline qui fonctionne réellement. Des outils comme Jenkins, GitHub Actions, GitLab CI ou ArgoCD prétendent tous résoudre la livraison, mais l'outil en lui-même n'est jamais le problème. Le problème, ce sont les capacités manquantes. Si votre pipeline ne dispose pas des bons blocs de construction, aucun outil ne pourra y remédier.

Voici les six capacités fondamentales que tout pipeline CI/CD doit posséder. Pas des options "nice-to-have". Pas des fonctionnalités que vous ajouterez quand vous aurez le temps. Ce sont les exigences minimales pour amener les modifications du code à la production en toute sécurité.

Build : Transformer le code en quelque chose d'exécutable

Chaque fois qu'un développeur pousse une modification, le pipeline doit convertir ce code en quelque chose qui peut réellement s'exécuter. Pour les langages compilés comme Go, Rust ou Java, cela signifie compiler la source en binaires. Pour les langages interprétés comme Python ou JavaScript, le build implique la vérification de la syntaxe, le regroupement des modules, la résolution des dépendances et la préparation de l'environnement d'exécution.

Le build est la première porte. Si le code ne compile pas, rien d'autre n'a d'importance. Le pipeline doit échouer rapidement ici, sans perdre de temps à exécuter des tests sur un code qui ne peut même pas compiler.

Une erreur courante consiste à traiter le build comme une étape simple qui fonctionne toujours. Mais les environnements de build diffèrent. Un build qui réussit sur le poste du développeur peut échouer dans le pipeline à cause de bibliothèques système manquantes, de versions d'outils différentes ou de variables d'environnement. L'étape de build du pipeline doit être reproductible et isolée, afin que ce qui fonctionne en CI fonctionne partout.

Test : Détecter les problèmes avant qu'ils n'atteignent les utilisateurs

Après un build réussi, le pipeline doit exécuter des tests automatisés. Il ne s'agit pas seulement de tests unitaires qui s'exécutent en quelques millisecondes. Un pipeline sain exécute plusieurs couches de tests :

  • Tests unitaires qui vérifient les comportements individuels
  • Tests d'intégration qui vérifient comment les composants fonctionnent ensemble
  • Tests de bout en bout qui simulent des scénarios utilisateur réels

Chaque couche détecte différents types de problèmes. Les tests unitaires détectent les erreurs de logique. Les tests d'intégration détectent les incompatibilités entre services. Les tests de bout en bout détectent les défaillances de workflow qui traversent plusieurs systèmes.

La clé est l'automatisation. Les tests doivent s'exécuter sans intervention humaine. Si quelqu'un doit déclencher manuellement les tests ou interpréter les résultats, le pipeline perd sa valeur principale : la rapidité et la cohérence. Chaque test qui s'exécute automatiquement est une chose de moins qu'un humain doit penser à vérifier.

Package : Créer un artefact versionné et déployable

Une fois que le code est compilé et que les tests passent, le pipeline doit empaqueter le résultat dans un artefact qui peut être déployé. Le format de l'artefact dépend de ce que vous livrez :

  • Une image conteneur pour les microservices
  • Un fichier binaire pour les applications de bureau
  • Un APK ou IPA pour les applications mobiles
  • Une archive zip pour les fonctions serverless
  • Un chart Helm pour les déploiements Kubernetes

Chaque artefact doit avoir une version unique. Pas seulement un timestamp ou un numéro de build, mais une version qui fait le lien avec le commit exact, l'exécution du pipeline et les résultats des tests. Cette traçabilité est ce qui vous permet de savoir exactement ce qui s'exécute en production et ce qui a changé entre les versions.

L'artefact doit être stocké dans un registre ou un dépôt central auquel l'étape de déploiement peut accéder. Si vous reconstruisez l'artefact au moment du déploiement, vous perdez la cohérence. L'artefact qui a passé les tests doit être exactement le même artefact qui est déployé.

Déployer : Placer l'artefact dans l'environnement cible

Le déploiement est plus que la copie de fichiers. C'est le processus qui consiste à placer une nouvelle version dans un environnement et à la rendre capable de servir du trafic. Pour le staging, le déploiement signifie installer la nouvelle version pour les tests. Pour la production, cela signifie remplacer la version en cours sans perturber les utilisateurs.

Différentes stratégies de déploiement existent pour différents niveaux de risque :

  • Mise à jour progressive (rolling update) : remplacer les instances une par une
  • Bleu-vert (blue-green) : basculer le trafic entre deux environnements identiques
  • Canary : envoyer d'abord un petit pourcentage de trafic vers la nouvelle version
  • Feature flags : déployer le code mais le garder caché derrière une bascule

Le pipeline doit prendre en charge la stratégie appropriée pour chaque environnement. Le staging peut utiliser un simple remplacement. La production nécessite souvent un déploiement progressif avec surveillance. Le pipeline doit automatiser l'ensemble du processus, pas seulement la copie de fichiers.

Migrer : Gérer les changements de base de données en toute sécurité

Si votre application utilise une base de données, le pipeline doit gérer les migrations de schéma. Ajouter une colonne, modifier un type de données ou créer une nouvelle table nécessite l'exécution de scripts de migration dans un ordre spécifique. Ces migrations ne peuvent pas être mélangées aléatoirement avec les déploiements d'application.

La partie délicate est l'ordonnancement. Parfois, la migration doit s'exécuter avant le déploiement du nouveau code applicatif. Par exemple, ajouter une colonne nullable que le nouveau code utilisera. D'autres fois, la migration doit s'exécuter après le déploiement du nouveau code. Par exemple, supprimer une ancienne colonne que l'ancien code référence encore.

Le pipeline doit connaître cet ordre et l'exécuter correctement. Une migration qui s'exécute au mauvais moment peut entraîner des temps d'arrêt, une perte de données, ou les deux. C'est l'une des capacités les plus négligées dans les pipelines CI/CD, et l'une des plus dangereuses à mal exécuter.

Rollback : Annuler quand les choses tournent mal

Tous les déploiements ne réussissent pas. Quand une nouvelle version provoque des erreurs, une dégradation des performances ou une corruption de données, le pipeline doit pouvoir revenir à la version précédente. Le rollback ne consiste pas seulement à redéployer l'ancien artefact. Cela implique :

  • Revenir à la version précédente de l'application
  • Exécuter les migrations inverses sur la base de données
  • Restaurer la configuration de l'infrastructure
  • Vérifier que le rollback a effectivement fonctionné

Le rollback doit être planifié avant le premier déploiement. Si vous concevez le pipeline sans envisager comment annuler une modification, vous vous retrouverez à écrire des scripts de rollback à la hâte pendant que la production est hors service. C'est le pire moment pour s'en occuper.

Pour les migrations de base de données, le rollback signifie disposer de migrations "down" qui annulent les migrations "up". Pour l'infrastructure, cela signifie conserver les fichiers d'état précédents ou utiliser des outils d'infrastructure-as-code qui prennent en charge le rollback d'état. Pour les applications, cela signifie conserver l'artefact précédent disponible et disposer d'une stratégie de déploiement qui permet une commutation instantanée.

Mettre tout ensemble

Ces six capacités — build, test, package, déployer, migrer et rollback — constituent le socle de tout pipeline CI/CD digne de ce nom. Selon ce que vous livrez, certaines capacités peuvent se présenter différemment. Les pipelines d'infrastructure peuvent remplacer le build et le package par la validation de configuration et la préparation d'état. Les pipelines mobiles peuvent ajouter la signature de code et la soumission à l'App Store. Mais les fonctions de base restent les mêmes.

Voici un pipeline GitLab CI minimal qui associe chaque capacité à une étape :

stages:
  - build
  - test
  - package
  - deploy
  - migrate
  - rollback

build:
  stage: build
  script:
    - go build -o app

test:
  stage: test
  script:
    - go test ./...

package:
  stage: package
  script:
    - docker build -t myapp:$CI_COMMIT_SHA .
    - docker push registry.example.com/myapp:$CI_COMMIT_SHA

deploy:
  stage: deploy
  script:
    - kubectl set image deployment/myapp myapp=registry.example.com/myapp:$CI_COMMIT_SHA

migrate:
  stage: migrate
  script:
    - ./run_migrations up

rollback:
  stage: rollback
  script:
    - ./run_migrations down
    - kubectl rollout undo deployment/myapp
  when: manual

Le diagramme suivant montre comment ces six capacités s'enchaînent dans un pipeline typique :

flowchart TD A[Code Push] --> B[Build] B --> C[Test] C --> D{Package} D --> E[Deploy] E --> F[Migrate DB] F --> G{Health Check} G -- Pass --> H[Complete] G -- Fail --> I[Rollback] I --> J[Restore DB] J --> K[Redeploy Previous] K --> L[Verify]

Avant de choisir un outil CI/CD ou de reconcevoir votre pipeline, cartographiez les capacités que vous possédez et celles qui manquent. Un outil qui promet tout mais ne gère pas les migrations de base de données ou la planification du rollback vous laissera vulnérable.

Liste de vérification rapide des capacités

  • Le build s'exécute dans un environnement isolé et reproductible
  • Les tests s'exécutent automatiquement à plusieurs niveaux
  • Les artefacts sont versionnés et stockés dans un registre central
  • Le déploiement prend en charge la stratégie appropriée pour chaque environnement
  • Les migrations de base de données sont ordonnancées correctement par rapport aux déploiements applicatifs
  • Le rollback est testé et fonctionne pour l'application, la base de données et l'infrastructure

L'essentiel à retenir

Un pipeline n'est pas une collection d'étapes. C'est un système qui doit gérer le cycle de vie complet d'une modification : du code au service en cours d'exécution, et inversement si nécessaire. Si votre pipeline ne peut pas builder, tester, packager, déployer, migrer et effectuer un rollback, il est incomplet. Commencez par combler la capacité manquante, pas par changer d'outil.