Aller au contenu
CI/CD & Automatisation medium

Bonnes pratiques CI/CD

23 min de lecture

Deux équipes peuvent utiliser le même outil de CI et obtenir des résultats opposés. Chez l'une, chaque exécution part du même état, un échec se localise en quelques secondes et le résultat ne dépend pas de la machine qui a joué le job. Chez l'autre, les exécutions divergent sans raison apparente, les erreurs remontent des heures plus tard et personne ne sait reproduire la panne.

L'écart ne vient pas de l'outil mais des principes de conception appliqués au pipeline : reproductibilité, rapidité du retour, isolation des étapes.

Certaines chaînes fonctionnent pendant des années sans intervention. D'autres s'effondrent au moindre changement. La différence tient rarement aux outils (GitHub Actions, GitLab CI, Jenkins...), elle tient aux principes appliqués.

Ce guide présente les bonnes pratiques qui distinguent une pipeline robuste d'une pipeline fragile. Ces principes sont universels : ils s'appliquent quel que soit l'outil que vous utilisez.

Une pipeline CI/CD n'est pas un script qu'on écrit une fois et qu'on oublie. C'est un système critique qui :

  • Valide chaque modification de code avant qu'elle n'atteigne les utilisateurs
  • Automatise les déploiements, parfois des dizaines par jour
  • Détient des secrets (clés d'API, credentials de production)
  • Impacte la productivité de toute l'équipe quand elle dysfonctionne

Une mauvaise pipeline, c'est :

  • Des heures perdues à attendre des résultats
  • Des bugs qui passent en production parce que « les tests étaient verts »
  • Des déploiements qui échouent le vendredi soir
  • Des développeurs qui contournent la pipeline parce qu'elle est trop lente

Une bonne pipeline, c'est :

  • Un feedback en minutes, pas en heures
  • La certitude que ce qui est testé = ce qui est déployé
  • Des déploiements prévisibles et reproductibles
  • Une équipe qui fait confiance à son outillage

En résumé : Une bonne pipeline est prévisible, rapide et autonome. Elle produit le même résultat à chaque exécution, donne un feedback en minutes, et ne dépend pas d'un humain pour fonctionner.

Build once, deploy many : construire une fois, déployer partout

Section intitulée « Build once, deploy many : construire une fois, déployer partout »

Le principe : l'artefact (image Docker, binaire, bundle JS...) est construit une seule fois, puis déployé tel quel dans chaque environnement (dev, staging, production).

Voici un pattern très courant... et très risqué :

# ❌ PROBLÈME : on reconstruit pour chaque environnement
staging:
script:
- npm install # Télécharge les dépendances
- npm run build # Build n°1
- docker build -t app:staging .
- docker push registry/app:staging
production:
script:
- npm install # Re-télécharge (versions peut-être différentes !)
- npm run build # Build n°2 (potentiellement différent !)
- docker build -t app:production .
- docker push registry/app:production

Qu'est-ce qui peut mal tourner ?

Entre le build staging et le build production (quelques jours plus tard) :

  • Une dépendance npm a été mise à jour (même en patch version)
  • L'image de base Docker a changé
  • Un outil de build a évolué
  • Une variable d'environnement système est différente

Résultat : l'artefact en production n'est pas celui que vous avez testé en staging. Et quand ça casse, vous entendez : « Mais ça marchait en staging ! »

# ✅ SOLUTION : un seul build, promu d'environnement en environnement
build:
script:
- npm install
- npm run build
- docker build -t registry/app:$COMMIT_SHA . # Tag unique par commit
- docker push registry/app:$COMMIT_SHA
staging:
script:
- docker pull registry/app:$COMMIT_SHA # Même artefact
- helm upgrade app ./chart --set image.tag=$COMMIT_SHA -f values-staging.yaml
production:
script:
- docker pull registry/app:$COMMIT_SHA # Toujours le même artefact
- helm upgrade app ./chart --set image.tag=$COMMIT_SHA -f values-production.yaml

Ce qui change entre les environnements : uniquement la configuration (variables d'environnement, secrets, URLs de base de données).

Ce qui ne change jamais : l'artefact lui-même.

Le tableau oppose les deux approches sur les critères qui pèsent en incident. Lisez d'abord la ligne Rollback : avec un rebuild, revenir en arrière suppose de reconstruire une ancienne version, donc de rejouer un build qui peut échouer au pire moment. Avec la promotion d'artefact, le rollback se résume à redéployer un tag déjà présent dans le registre, opération quasi instantanée.

AspectRebuild par environnementPromotion d'artefact
Reproductibilité❌ Incertaine✅ Garantie
Confiance« Ça marchait en staging... »« C'est le même artefact »
Temps de déploiementLong (rebuild complet)Rapide (juste déployer)
RollbackRebuild l'ancienne version (risqué)Redéployer l'ancien tag (instantané)

Pour que la promotion fonctionne, votre application doit :

  1. Séparer le code de la configuration

    • const API_URL = "https://prod.example.com" en dur dans le code
    • const API_URL = process.env.API_URL lu au démarrage
  2. Accepter la configuration au runtime

    • Variables d'environnement
    • Fichiers de configuration montés
    • Secrets injectés par le système d'orchestration
  3. Tagger les artefacts de manière unique

    • app:staging, app:production (on ne sait pas quel code c'est)
    • app:abc123def456 (SHA du commit = traçabilité totale)

Immutabilité : ce qui est créé ne change jamais

Section intitulée « Immutabilité : ce qui est créé ne change jamais »

Le principe : un artefact, une fois créé, ne doit jamais être modifié. Si un changement est nécessaire, on crée un nouvel artefact.

Imaginez ce scénario :

  1. Lundi : vous déployez l'image app:latest en production, tout fonctionne
  2. Mardi : un collègue rebuild app:latest avec une correction
  3. Mercredi : un autre service redémarre et pull app:latest
  4. Jeudi : ce service ne fonctionne plus, mais personne ne comprend pourquoi

Le problème : app:latest de lundi ≠ app:latest de mardi. Le tag est le même, mais le contenu a changé. C'est l'absence d'immutabilité.

Ces quatre pratiques ont un point commun : elles laissent le contenu d'un artefact évoluer alors que son identifiant reste figé. Le cas le plus fréquent est le premier, les tags mutables comme latest : deux docker pull latest à une semaine d'écart peuvent ramener des images différentes, et plus rien ne relie ce qui tourne au code qui l'a produit.

PratiqueProblème
Tags mutables (latest, stable, main)Le contenu change, le nom reste
Modification d'un artefact après créationImpossible de savoir ce qui tourne vraiment
Scripts qui patchent en productionÉtat différent de ce qui est versionné
Déploiement sans tag explicite« Quelle version est en prod ? », « Euh... »

À l'inverse, ces mécanismes garantissent qu'un identifiant pointe pour toujours vers le même contenu. Le schéma illustre le principe : chaque SHA de commit ouvre une image distincte, une correction produit un nouvel artefact plutôt que d'écraser l'ancien. Le tableau qui suit décline ce principe en pratiques concrètes, du tag par empreinte à la protection des tags côté registre.

Registre d'images avec tags immutables
abc123 ─────▶ image v1.2.3 (ne change jamais)
def456 ─────▶ image v1.2.4 (nouvel artefact)
ghi789 ─────▶ image v1.2.5 (nouvel artefact)
PratiqueBénéfice
Tags par SHA de commit (app:abc123def)Traçabilité totale : code → artefact
Versioning sémantique avec releases figéesv1.2.3 pointe toujours vers le même contenu
Infrastructure as CodeLa config est versionnée, pas modifiée à la main
Registre avec protection des tagsImpossible d'écraser un tag existant

La règle se ramène à une question : si je rejoue ce pipeline dans six mois, obtiendrai-je le même artefact ? Un tag mobile répond non, une empreinte répond oui.

# ❌ Tag mutable : dangereux
docker build -t app:latest .
docker push app:latest
# ✅ Tag immutable : sûr
docker build -t app:$CI_COMMIT_SHA .
docker push app:$CI_COMMIT_SHA
# Pour la lisibilité, on peut ajouter un tag sémantique
# MAIS le SHA reste la référence de vérité
docker tag app:$CI_COMMIT_SHA app:v1.2.3
docker push app:v1.2.3

Le principe : exécuter la même pipeline sur le même commit doit produire exactement le même résultat, que ce soit la première ou la dixième fois.

Même commit (abc123), trois exécutions différentes
Run 1 (lundi) : commit abc123 → artefact xyz789
Run 2 (mercredi) : commit abc123 → artefact xyz789 ✅ identique
Run 3 (vendredi) : commit abc123 → artefact xyz789 ✅ identique

Sans idempotence :

  • Debugging impossible : « Ça marchait hier, pourquoi ça casse aujourd'hui ? »
  • Rollback incertain : rebuilder l'ancienne version ne donne pas le même résultat
  • Tests non fiables : le même test passe ou échoue aléatoirement

Chaque ligne du tableau introduit une source de non-déterminisme : quelque chose qui varie d'une exécution à l'autre alors que le commit, lui, n'a pas bougé. Repérez la première cause, les dépendances non épinglées : c'est la plus courante et la plus vicieuse, car un npm install sans lockfile peut ramener une version différente sans qu'aucun de vos fichiers n'ait changé.

CauseExempleProblème
Dépendances non épingléesnpm install sans lockfileUne dépendance est mise à jour entre deux builds
Timestamps dans l'artefactDate de build dans le binaireL'artefact change à chaque build
Données externesTests qui appellent une vraie APIL'API peut répondre différemment
État global modifiéScript qui modifie une variable globaleLe deuxième run voit un état différent
Ordre non déterministeTests parallèles mal isolésLes tests s'influencent mutuellement

1. Épingler toutes les dépendances

Fenêtre de terminal
# ❌ Non déterministe : peut changer demain
npm install
pip install requests
# ✅ Déterministe : toujours les mêmes versions
npm ci # Utilise package-lock.json
pip install -r requirements.txt --no-deps # Versions exactes

Les fichiers de lock à committer :

ÉcosystèmeFichier de lock
Node.js (npm)package-lock.json
Node.js (yarn)yarn.lock
Python (pip)requirements.txt avec versions exactes
Python (poetry)poetry.lock
Gogo.sum
RustCargo.lock

2. Éviter les timestamps et données variables

# ❌ La date change à chaque build
RUN echo "Built on $(date)" > /app/version.txt
# ✅ Utiliser des informations déterministes
ARG COMMIT_SHA
RUN echo "Commit: $COMMIT_SHA" > /app/version.txt

3. Isoler les tests

# ❌ Test qui dépend d'un état global
def test_user_count():
assert User.count() == 5 # Et si un autre test a créé des users ?
# ✅ Test qui crée son propre contexte
def test_user_count():
with fresh_database():
create_users(5)
assert User.count() == 5

4. Mocker les dépendances externes

# ❌ Appelle une vraie API (peut changer, être lente, être down)
def test_weather():
response = requests.get("https://api.weather.com/paris")
assert response.status_code == 200
# ✅ Mock l'API
def test_weather(mock_weather_api):
mock_weather_api.return_value = {"temp": 20}
result = get_weather("paris")
assert result["temp"] == 20

Feedback rapide : savoir en minutes si le code est valide

Section intitulée « Feedback rapide : savoir en minutes si le code est valide »

Le principe : un développeur doit savoir en quelques minutes, pas en heures, si son code est valide.

Pourquoi c'est fondamental ?

La valeur d'un test ne tient pas seulement à ce qu'il détecte, mais au délai au bout duquel il le signale. Un échec remonté après quarante minutes arrive alors que le développeur a déjà ouvert un autre sujet.

Plus le feedback est tardif :

  • Plus le développeur a changé de contexte (il travaille sur autre chose)
  • Plus il est difficile de se souvenir de ce qu'on a fait
  • Plus la correction prend du temps

Objectifs de temps réalistes :

ÉtapeObjectifPourquoi cette durée
Lint + format< 1 minVérifications syntaxiques, très rapides
Tests unitaires< 3 minTests isolés, pas de dépendances externes
Build< 5 minCompilation, bundling
Tests d'intégration< 10 minTests avec base de données, services
Tests end-to-end< 15 minTests navigateur, scénarios complets

Si votre pipeline dépasse 30 minutes, les développeurs commencent à la contourner (« je merge, on verra bien ») ou à faire du multi-tâche inefficace.

1. Paralléliser les jobs indépendants

Au lieu d'exécuter lint, tests et scan de sécurité l'un après l'autre, exécutez-les en parallèle :

Parallélisation des jobs dans une
pipeline

2. Fail fast, s'arrêter dès qu'un check rapide échoue

Si le lint échoue en 3 secondes, inutile de lancer les tests qui durent 30 secondes :

lint (3s)
├── échec → STOP (on a gagné 30s)
└── succès → tests (30s)
└── build (2min)

3. Utiliser le cache de manière agressive

Télécharger les dépendances à chaque exécution est du gaspillage :

Sans cacheAvec cache
npm install : 3 minnpm install : 10 sec
pip install : 2 minpip install : 5 sec
Téléchargement images Docker : 1 minDéjà en cache : 0 sec

4. Organiser les tests en pyramide

L'idée est d'avoir beaucoup de tests rapides (unitaires) et peu de tests lents (end-to-end) :

Pyramide des tests dans une pipeline
CI/CD

Les tests unitaires détectent 80% des bugs en quelques secondes. Les tests E2E vérifient les scénarios critiques, mais sont réservés aux parcours essentiels.

Séparation build / deploy : deux responsabilités distinctes

Section intitulée « Séparation build / deploy : deux responsabilités distinctes »

Le principe : le build crée un artefact générique. Le deploy l'installe avec une configuration spécifique. Les deux ne doivent pas être mélangés.

# ❌ COUPLAGE : le build connaît la destination
build-staging:
script:
- API_URL=https://staging.example.com npm run build
- docker build -t app:staging .
- deploy-to-staging
build-production:
script:
- API_URL=https://api.example.com npm run build
- docker build -t app:production .
- deploy-to-production

Problèmes :

  • Duplication de code (le build est répété deux fois)
  • Impossible de promouvoir l'artefact (staging ≠ production)
  • Si on ajoute un environnement (preprod), il faut un nouveau job

Le build produit un artefact indépendant de sa destination, le déploiement l'injecte dans un environnement donné. Cette frontière permet de promouvoir en production exactement le binaire validé en recette, sans le reconstruire.

# ✅ SÉPARATION : build générique, deploy configuré
build:
script:
- npm run build # Pas de config d'environnement
- docker build -t app:$COMMIT_SHA .
- docker push registry/app:$COMMIT_SHA
deploy-staging:
needs: [build]
script:
- docker pull registry/app:$COMMIT_SHA
- helm upgrade app ./chart \
--set image.tag=$COMMIT_SHA \
--set apiUrl=https://staging.example.com \
-f values-staging.yaml
deploy-production:
needs: [build]
script:
- docker pull registry/app:$COMMIT_SHA # Même artefact !
- helm upgrade app ./chart \
--set image.tag=$COMMIT_SHA \
--set apiUrl=https://api.example.com \
-f values-production.yaml

La colonne qui protège la promotion d'artefact est la dernière, Ce qu'elle NE fait PAS. Tant que le build n'injecte aucune URL ni secret, et que le deploy ne recompile rien, l'artefact validé en test est bien celui qui part en production. Dès qu'une étape déborde de son rôle, la garantie « ce qui est testé égale ce qui est déployé » tombe.

ÉtapeResponsabilitéCe qu'elle NE fait PAS
BuildCompiler, bundler, créer l'artefactInjecter des URLs, secrets, configs d'env
TestValider que l'artefact fonctionneModifier l'artefact
DeployInstaller l'artefact + injecter la configRecompiler, modifier le code

La configuration spécifique à l'environnement doit être injectée au runtime, pas au build :

// ❌ Configuration au build (en dur dans le code)
const API_URL = "https://api.example.com";
// ✅ Configuration au runtime
const API_URL = process.env.API_URL || "http://localhost:3000";
values-staging.yaml
apiUrl: https://staging.example.com
logLevel: debug
replicas: 1
# values-production.yaml
apiUrl: https://api.example.com
logLevel: warn
replicas: 3

Pipeline déclarative : décrire quoi, pas comment

Section intitulée « Pipeline déclarative : décrire quoi, pas comment »

Le principe : votre fichier de pipeline doit décrire ce que vous voulez obtenir (quoi), pas les détails d'implémentation (comment). C'est la plateforme qui gère l'orchestration.

# ❌ IMPÉRATIF : le script gère tout lui-même
steps:
- run: |
if [ "$BRANCH" = "main" ]; then
npm run build
docker build -t app .
docker push registry/app:latest
if [ "$DEPLOY" = "true" ]; then
kubectl config use-context production
kubectl apply -f k8s/
kubectl rollout status deployment/app
fi
elif [ "$BRANCH" = "develop" ]; then
npm run build
docker build -t app .
docker push registry/app:dev
# ... encore du code
fi

Problèmes :

  • Difficile à lire : il faut suivre la logique du script
  • Difficile à maintenir : un changement peut casser autre chose
  • Pas de réutilisation : tout est dans un gros script
  • Pas de parallélisation : la plateforme ne peut pas optimiser

Vous décrivez l'état attendu, la plateforme choisit la séquence d'opérations pour l'atteindre. L'intérêt pratique est la reprise : un job interrompu se rejoue sans effet de bord, là où une suite d'ordres impératifs laisse le système à mi-chemin.

# ✅ DÉCLARATIF : intention claire, plateforme orchestre
permissions: {}
jobs:
build:
runs-on: ubuntu-24.04
permissions:
contents: read
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: '20'
- run: npm ci
- run: npm run build
- uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
with:
push: true
tags: registry/app:${{ github.sha }}
deploy-staging:
needs: build
if: github.ref == 'refs/heads/main'
environment: staging
steps:
- uses: azure/k8s-deploy@51ca02a8b7225fbd0924aac359c5b336a5f1e5b4 # v7.0.0
with:
manifests: k8s/staging/
images: registry/app:${{ github.sha }}
deploy-production:
needs: deploy-staging
if: github.ref == 'refs/heads/main'
environment: production # Approbation requise
steps:
- uses: azure/k8s-deploy@51ca02a8b7225fbd0924aac359c5b336a5f1e5b4 # v7.0.0
with:
manifests: k8s/production/
images: registry/app:${{ github.sha }}

Au-delà de la lisibilité, la ligne décisive est Optimisation. Un script impératif impose sa séquence, la plateforme ne peut rien paralléliser toute seule. Une description déclarative expose au contraire un graphe de dépendances que la plateforme lit pour lancer en parallèle tout ce qui est indépendant, sans que vous ayez à l'orchestrer à la main.

AspectImpératifDéclaratif
LisibilitéSuivre la logique du scriptStructure visible immédiatement
RéutilisationCopier-collerActions/plugins partagés
MaintenanceModifier des scripts complexesChanger des paramètres
OptimisationManuelle (parallélisation)Automatique par la plateforme
VisualisationPas de grapheGraphe de dépendances généré

Ces cinq mots-clés forment le vocabulaire commun à la plupart des plateformes, même si la syntaxe exacte varie. Retenez surtout needs, qui déclare les dépendances entre jobs : c'est lui qui construit le graphe d'exécution et permet à la plateforme de savoir quoi lancer en parallèle et quoi attendre. Les exemples ci-dessous utilisent la syntaxe GitHub Actions, transposable ailleurs.

ConceptSignificationExemple
needs« Ce job dépend de celui-là »needs: [build, test]
if« Exécuter seulement si... »if: github.ref == 'refs/heads/main'
environment« Déployer dans cet environnement »environment: production
matrix« Exécuter pour chaque combinaison »matrix: { node: [18, 20] }
uses« Utiliser cette action réutilisable »uses: actions/checkout@v4

Fail fast, fail loud : échouer vite et clairement

Section intitulée « Fail fast, fail loud : échouer vite et clairement »

Le principe : quand quelque chose ne va pas, la pipeline doit s'arrêter immédiatement et le signaler clairement.

Pourquoi c'est important ?

Une erreur silencieuse ou tardive est bien pire qu'une erreur bruyante et immédiate :

  • Silencieuse : le bug passe en production, les utilisateurs le découvrent
  • Tardive : vous avez déjà mergé 10 autres commits, impossible de savoir lequel a cassé
  • Bruyante et immédiate : vous corrigez en 5 minutes, personne n'est impacté

1. S'arrêter immédiatement

Ne jamais continuer avec un état invalide. Si une étape échoue, les suivantes n'ont pas de sens.

Fenêtre de terminal
# ❌ Script qui ignore les erreurs
result=$(command_that_might_fail)
# Continue même si la commande a échoué...
next_command
deploy # Déploie du code potentiellement cassé !
Fenêtre de terminal
# ✅ Script qui s'arrête au premier problème
set -euo pipefail # Arrêt automatique en cas d'erreur
result=$(command_that_might_fail)
# Si la commande échoue, le script s'arrête ici
next_command # N'est jamais atteint si échec

Explication de set -euo pipefail :

OptionSignification
-eArrêter le script si une commande retourne une erreur
-uArrêter si une variable non définie est utilisée
-o pipefailConsidérer un pipeline comme échoué si n'importe quelle commande échoue

2. Notifier clairement

Une notification d'échec doit être :

Critère❌ Mauvais✅ Bon
Timing30 minutes après l'échecImmédiatement
DestinataireToute l'équipe (spam)L'auteur du commit
Contenu« Pipeline failed »« Test user_login_test failed: expected 200, got 401 »
ActionChercher dans les logsLien direct vers la ligne qui a échoué

3. Faciliter le debugging

Quand une pipeline échoue, le développeur doit pouvoir comprendre pourquoi sans fouiller 500 lignes de logs :

  • Logs structurés : sections claires pour chaque étape
  • Contexte préservé : variables d'environnement, versions utilisées
  • Artefacts de debug : screenshots pour les tests E2E, rapports de couverture
  • Reproduction locale possible : « Pour reproduire : make test-integration »

Observabilité : voir ce qui se passe sans fouiller

Section intitulée « Observabilité : voir ce qui se passe sans fouiller »

Le principe : la pipeline doit exposer son état de santé de manière proactive. Vous ne devriez pas avoir à fouiller les logs pour savoir si tout va bien.

Ces métriques répondent chacune à une question de santé différente, mais deux méritent une attention particulière. Le taux de succès trahit une pipeline qui perd la confiance de l'équipe, et les tests flaky rongent cette confiance à bas bruit. La colonne des seuils donne des repères de départ à ajuster selon votre contexte, ce ne sont pas des valeurs universelles.

MétriqueCe qu'elle révèleSeuil d'alerte typique
Durée totaleRégression de performance> 15 min (selon contexte)
Durée par jobGoulot d'étranglementJob qui double de durée
Taux de succèsSanté globale< 90% sur 24h
Tests flakyTests non fiablesMême test échoue > 2x/semaine aléatoirement
Temps de queueManque de runners> 5 min d'attente
Fréquence de déploiementVélocité de l'équipeBaisse soudaine

Un test flaky est un test qui échoue parfois sans raison apparente, puis passe à la relance.

Pourquoi c'est grave :

  • Les développeurs perdent confiance dans la pipeline (« oh, ça a échoué, je relance »)
  • Les vrais problèmes passent inaperçus (noyés dans le bruit)
  • Temps perdu à relancer des pipelines

Comment les détecter :

  • Suivre les tests qui échouent puis passent sur le même commit
  • Identifier les tests avec un taux de succès < 99%
  • Alerter quand un test spécifique échoue plus de X fois par semaine

Que faire :

  1. Marquer le test comme flaky (pour ne pas bloquer les autres)
  2. Créer un ticket prioritaire pour le corriger
  3. Corriger la cause racine (souvent : dépendance au timing, état partagé, ressource externe)

Ne vous noyez pas dans les alertes. Concentrez-vous sur ce qui est actionnable :

ConditionAction requise
Pipeline principale > 20 minInvestiguer la régression de performance
Taux de succès < 85% sur 24hProblème systémique, prioriser la correction
Test X échoue > 3 fois cette semaineMarquer comme flaky, créer ticket
Temps de queue > 10 minAjouter des runners ou optimiser le parallélisme
Déploiement production échoueAlerte immédiate à l'équipe on-call

Un bon dashboard de pipeline montre en un coup d'œil :

Exemple de dashboard de
pipeline CI/CD

  1. Feedback rapide, Le développeur doit savoir en minutes si son code est valide. Parallélisez, cachez, fail fast.

  2. Fail fast, fail loud, Une erreur silencieuse est pire qu'une erreur bruyante. Arrêtez-vous immédiatement, notifiez clairement.

  3. Build once, deploy many, Construisez l'artefact une fois, déployez-le partout. Ce que vous testez = ce que vous déployez.

  4. Immutabilité, Un artefact créé ne change jamais. Si changement nécessaire, créez un nouvel artefact. Évitez les tags mutables (latest).

  5. Idempotence, Même commit = même résultat. Épinglez les dépendances, isolez les tests, évitez les états globaux.

  6. Séparation build/deploy, Le build crée un artefact générique. Le deploy injecte la configuration. Ne mélangez pas.

  7. Pipeline déclarative, Décrivez le quoi, pas le comment. Laissez la plateforme orchestrer.

  8. Observabilité, Mesurez la durée, le taux de succès, les tests flaky. Alertez sur ce qui est actionnable.

Avant de merger une modification de pipeline, vérifiez :

  • Build once : L'artefact est construit une seule fois
  • Immutabilité : Les tags sont immutables (SHA, pas latest)
  • Idempotence : Les dépendances sont épinglées (lockfiles committés)
  • Feedback rapide : La pipeline complète en moins de 15 minutes
  • Fail fast : Un échec arrête la pipeline immédiatement
  • Notifications : Les alertes sont actionnables (lien direct, contexte)
  • Séparation : Build et deploy sont des jobs distincts
  • Déclaratif : La logique est dans la structure, pas dans des scripts

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn