Bonnes pratiques DevOps : CI/CD, IaC et observabilité
Ce tutoriel présente une approche complète et pragmatique des bonnes pratiques DevOps autour de trois piliers : CI/CD (intégration et déploiement continus), IaC (Infrastructure as Code) et observabilité (logs, métriques, traces). L’objectif est de comprendre pourquoi ces pratiques existent, comment les mettre en place, et quels pièges éviter, avec des commandes réelles et des exemples reproductibles.
1) Prérequis et cadre de référence
Prérequis techniques
- Connaissances de base en Git et ligne de commande
- Un environnement Linux/macOS (ou WSL2 sur Windows)
- Outils recommandés :
gitdocker(et idéalement Docker Compose)terraform(pour l’IaC)kubectl(si vous déployez sur Kubernetes)curl,jq
Vérification rapide :
git --version
docker --version
terraform version
kubectl version --client
Principes DevOps à garder en tête
- Automatiser ce qui est répétable (build, tests, déploiements, provisioning)
- Réduire le lead time (temps entre idée et mise en production)
- Réduire le risque (petits changements, validations automatiques, rollback)
- Mesurer (observabilité) pour piloter et diagnostiquer
2) CI/CD : construire une chaîne fiable et rapide
2.1 CI vs CD : définitions utiles
- CI (Continuous Integration) : à chaque changement, on compile, teste, analyse et on produit des artefacts. On cherche un feedback rapide.
- CD (Continuous Delivery/Deployment) :
- Delivery : prêt à déployer à tout moment (déploiement souvent manuel/validé).
- Deployment : déploiement automatisé jusqu’en production (avec garde-fous).
Dans la pratique, une bonne pipeline CI/CD doit :
- Valider le code (lint, tests, sécurité)
- Construire un artefact immuable (image Docker, package)
- Publier l’artefact (registry)
- Déployer via un mécanisme reproductible (IaC + GitOps idéalement)
- Vérifier (smoke tests, health checks, SLO)
- Permettre rollback/rollforward
2.2 Stratégie Git : branches, PR/MR, et qualité
Recommandations :
- Utiliser des Pull Requests / Merge Requests avec revue
- Activer des checks obligatoires (tests, lint, scan)
- Préférer des branches courtes et merges fréquents
- Maintenir un historique lisible (squash ou rebase selon culture)
Exemples de conventions de commits (inspirées Conventional Commits) :
feat: ...fix: ...chore: ...docs: ...
Vérifier l’historique :
git log --oneline --decorate --graph --all | head -n 30
2.3 Exemple concret : pipeline CI pour une application Node.js conteneurisée
Arborescence type
.
├── src/
├── test/
├── package.json
├── package-lock.json
├── Dockerfile
└── scripts/
├── lint.sh
└── test.sh
Scripts de qualité (exemples)
scripts/lint.sh :
#!/usr/bin/env bash
set -euo pipefail
npm ci
npm run lint
scripts/test.sh :
#!/usr/bin/env bash
set -euo pipefail
npm ci
npm test
Rendre exécutables :
chmod +x scripts/*.sh
Dockerfile (exemple)
FROM node:20-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm test
FROM node:20-alpine
WORKDIR /app
ENV NODE_ENV=production
COPY --from=build /app /app
EXPOSE 3000
CMD ["node", "src/index.js"]
Build local :
docker build -t monapp:dev .
docker run --rm -p 3000:3000 monapp:dev
2.4 Artefacts immuables et versionnement
Bonnes pratiques :
- Ne jamais reconstruire “à la main” en prod : on déploie un artefact déjà validé.
- Taguer les images avec :
- un identifiant immuable (SHA Git)
- éventuellement un tag lisible (
v1.2.3)
- Éviter
latesten production (ou l’utiliser seulement comme alias).
Exemple :
GIT_SHA="$(git rev-parse --short HEAD)"
docker build -t registry.exemple.com/monapp:${GIT_SHA} .
docker push registry.exemple.com/monapp:${GIT_SHA}
2.5 Sécurité dans la CI : SAST, dépendances, secrets
Intégrer des contrôles tôt :
- Scan de dépendances (ex:
npm audit) - Scan image (ex: Trivy)
- Détection de secrets (ex: gitleaks)
Commandes typiques :
npm audit --audit-level=high
Scan d’image avec Trivy (si installé) :
trivy image --severity HIGH,CRITICAL monapp:dev
Détection de secrets (exemple gitleaks) :
gitleaks detect --source . --no-git
Principe clé : un pipeline qui échoue tôt est un pipeline qui protège.
2.6 Déploiement : stratégies et garde-fous
Stratégies de déploiement
- Rolling update : remplacement progressif (Kubernetes par défaut)
- Blue/Green : deux environnements, bascule du trafic
- Canary : déployer à un petit pourcentage d’utilisateurs, observer, puis étendre
Garde-fous indispensables
- Health checks (liveness/readiness)
- Smoke tests post-déploiement
- Timeouts et rollback automatique
- Feature flags pour découpler déploiement et activation
Exemple de smoke test HTTP :
curl -fsS http://mon-service.exemple.com/health
3) IaC : Infrastructure as Code fiable, testable et traçable
3.1 Pourquoi l’IaC est incontournable
Sans IaC, l’infrastructure dérive :
- “ça marchait hier” mais personne ne sait pourquoi
- environnements incohérents (dev ≠ prod)
- changements non tracés
Avec IaC :
- l’infra est versionnée (Git)
- les changements sont reproductibles
- on peut review comme du code
- on peut automatiser la conformité (policies)
Deux familles :
- Déclaratif (Terraform, Pulumi, CloudFormation)
- Configuration management (Ansible, Chef) — souvent complémentaire
3.2 Terraform : structure et bonnes pratiques
Structure recommandée
- Un dossier par “stack” (environnement ou composant)
- Modules réutilisables
- Backend distant pour l’état (state) avec verrouillage
Exemple :
infra/
├── modules/
│ └── réseau/
└── envs/
├── dev/
└── prod/
Initialiser et planifier
Dans un dossier Terraform :
terraform init
terraform fmt -recursive
terraform validate
terraform plan
Appliquer :
terraform apply
Détruire (à manier avec extrême prudence) :
terraform destroy
3.3 Gestion du state : sécurité et collaboration
Le fichier terraform.tfstate contient souvent :
- IDs de ressources
- parfois des valeurs sensibles (selon providers)
Bonnes pratiques :
- Ne jamais committer le state dans Git
- Utiliser un backend distant (S3 + DynamoDB lock, GCS, Terraform Cloud…)
- Chiffrer au repos, limiter les accès
- Activer le verrouillage pour éviter les écritures concurrentes
Même sans montrer de configuration spécifique, retenez :
- state = source de vérité opérationnelle
- il doit être protégé et partagé correctement
3.4 Variables, secrets et séparation des environnements
- Paramétrer via variables (
-var,*.tfvars) - Ne pas stocker les secrets en clair
- Utiliser un gestionnaire de secrets (Vault, AWS Secrets Manager, etc.)
- Séparer dev/prod par :
- comptes/projets distincts
- ou au minimum workspaces, mais la séparation forte est préférable
Exemple d’exécution avec variables :
terraform plan -var="region=eu-west-1" -var="env=dev"
3.5 Import et dérive (drift)
Si une ressource est modifiée hors Terraform, on observe une dérive.
Détecter :
terraform plan
Importer une ressource existante (exemple générique) :
terraform import module.reseau.aws_vpc.main vpc-1234567890abcdef0
Attention : importer ne génère pas automatiquement le code HCL correct. Il faut ensuite aligner la configuration.
3.6 Tests et qualité IaC
Même l’infra doit être testée :
terraform validatetflint(lint)checkov(policies sécurité)- Tests d’intégration (ex: Terratest en Go)
Exemples :
tflint --recursive
checkov -d infra/
4) Observabilité : logs, métriques, traces (et la réalité opérationnelle)
4.1 Monitoring vs observabilité
- Monitoring : on surveille des symptômes connus (CPU, RAM, erreurs 500)
- Observabilité : on peut comprendre un système à partir de ses signaux, y compris pour des scénarios non anticipés.
Les 3 piliers :
- Logs : détails d’événements
- Métriques : séries temporelles agrégées
- Traces : parcours d’une requête à travers plusieurs services
Un 4e pilier souvent ajouté :
- Profils (profiling) : CPU, mémoire, latences au niveau code
4.2 Logs : structurés, corrélables, exploitables
Bonnes pratiques de logs applicatifs
- Format JSON (structuré)
- Champs standard :
timestamplevel(info/warn/error)serviceenvrequest_id/trace_idmessageerror(stacktrace)
- Ne jamais logger de secrets (tokens, mots de passe, données sensibles)
Exemple de log JSON (ligne unique) :
{"timestamp":"2026-05-08T10:12:33.123Z","level":"info","service":"api","env":"prod","request_id":"abc123","message":"Requête traitée","duration_ms":42}
Centralisation
Objectif : éviter de se connecter sur chaque machine/Pod. Solutions fréquentes :
- ELK/EFK (Elasticsearch + Fluentd/Fluent Bit + Kibana)
- Loki + Grafana
- Stack cloud (CloudWatch, Stackdriver, etc.)
Exemple de lecture de logs Docker :
docker logs -f --tail=200 <container_id>
4.3 Métriques : SLI/SLO, RED/USE, et alertes utiles
Métriques “techniques” vs “produit”
- Techniques : CPU, mémoire, saturation, latence DB
- Produit : taux de conversion, nombre de commandes, erreurs métier
Méthodes pratiques
- RED (pour services HTTP) :
- Rate (taux de requêtes)
- Errors (taux d’erreurs)
- Duration (latence)
- USE (pour ressources) :
- Utilization
- Saturation
- Errors
SLI/SLO : piloter par objectifs
- SLI : indicateur mesuré (ex: % requêtes < 300 ms)
- SLO : objectif (ex: 99.9% sur 30 jours)
- Error budget : marge d’erreur acceptable avant de ralentir les changements
Exemple de réflexion :
- SLO : 99.9% de disponibilité mensuelle
- Cela autorise environ 43 minutes d’indisponibilité par mois (30 jours)
4.4 Traces distribuées : comprendre les latences
Dans une architecture microservices, une requête traverse :
- API Gateway
- service A
- service B
- base de données
- cache…
Sans traces, on devine. Avec traces, on voit. Technos typiques :
- OpenTelemetry (instrumentation standard)
- Jaeger / Tempo / Zipkin
- APM (Datadog, New Relic, etc.)
Concepts clés :
- Trace : une requête de bout en bout
- Span : une étape (appel HTTP, requête SQL)
- Context propagation : transmission d’un
trace_identre services
4.5 OpenTelemetry en pratique (exemple conceptuel + commandes)
Même si l’instrumentation dépend du langage, vous pouvez déjà mettre en place un collecteur et exporter des signaux.
Lancer un collecteur OpenTelemetry via Docker (exemple simple) :
docker run --rm -p 4317:4317 -p 4318:4318 otel/opentelemetry-collector:latest
Tester un endpoint OTLP HTTP (selon config, ici purement illustratif) :
curl -v http://localhost:4318/
Dans un vrai setup, vous configurerez le collector pour router vers :
- Prometheus (métriques)
- Tempo/Jaeger (traces)
- Loki/Elastic (logs)
4.6 Alerting : réduire le bruit, augmenter la valeur
Erreurs fréquentes :
- Alerter sur CPU > 80% sans contexte
- Trop d’alertes non actionnables
- Pas de runbooks
Bonnes pratiques :
- Alerter sur des symptômes utilisateur (latence, erreurs)
- Définir des seuils basés sur SLO
- Ajouter un runbook : “que faire quand ça sonne ?”
- Avoir des niveaux : warning vs critical
Exemple de runbook minimal :
- Vérifier la santé du service (
/health) - Vérifier erreurs 5xx
- Vérifier dépendances (DB, cache)
- Vérifier derniers déploiements
- Rollback si nécessaire
5) Mettre ensemble : un flux DevOps cohérent (CI/CD + IaC + Observabilité)
5.1 Chaîne de livraison type
- Dev pousse du code
- CI :
- lint + tests
- scan sécurité
- build image
- push registry
- CD :
- mise à jour des manifests (ou release)
- déploiement automatisé
- Observabilité :
- dashboards (RED/USE)
- traces activées
- logs corrélés
- Post-déploiement :
- smoke tests
- surveillance du budget d’erreur
5.2 Exemple de déploiement Kubernetes (commandes réelles)
Sans entrer dans des manifests complets, voici des commandes typiques d’exploitation.
Voir les ressources :
kubectl get ns
kubectl get pods -n mon-namespace
kubectl get deploy -n mon-namespace
kubectl get svc -n mon-namespace
Décrire un Pod (diagnostic) :
kubectl describe pod -n mon-namespace monapp-xxxxx
Logs d’un Pod :
kubectl logs -n mon-namespace deploy/monapp --tail=200 -f
Rollout status :
kubectl rollout status -n mon-namespace deploy/monapp
Rollback :
kubectl rollout undo -n mon-namespace deploy/monapp
Tester un port-forward pour debug :
kubectl port-forward -n mon-namespace svc/monapp 8080:80
curl -fsS http://localhost:8080/health
5.3 GitOps : déployer via Git comme source de vérité
Principe :
- Les manifests (ou chart Helm / Kustomize) sont dans Git
- Un contrôleur (Argo CD, Flux) synchronise l’état du cluster avec Git
- Les changements passent par PR/MR, donc revue, historique, audit
Avantages :
- Traçabilité forte
- Rollback simple (revert Git)
- Convergence automatique (réduit la dérive)
6) Sécurité et conformité : “shift left” sans casser la vélocité
6.1 Contrôles à intégrer
- Scans de dépendances
- Scans images
- Policies IaC (ex: pas de bucket public)
- Signatures d’artefacts (Sigstore/cosign)
- SBOM (Software Bill of Materials)
Exemple de génération SBOM avec Syft (si installé) :
syft monapp:dev -o json > sbom.json
jq '.artifacts | length' sbom.json
Signer une image avec cosign (si installé) :
cosign sign registry.exemple.com/monapp:${GIT_SHA}
cosign verify registry.exemple.com/monapp:${GIT_SHA}
6.2 Gestion des secrets
Règles :
- Jamais de secrets dans Git
- Secrets injectés à l’exécution (variables d’environnement, volumes, secret manager)
- Rotation régulière
- Moindre privilège (IAM)
Détecter des secrets accidentels avant commit (exemple) :
gitleaks detect --source . --no-git
7) Fiabilité : déploiements sûrs, tests réalistes, et résilience
7.1 Tests : pyramide et couverture utile
- Unit tests : rapides, nombreux
- Integration tests : plus lents, plus réalistes
- End-to-end : peu nombreux, critiques
Exécuter tests en local (Node) :
npm ci
npm test
7.2 Chaos engineering (à dose raisonnable)
Objectif : valider que le système tolère des pannes réalistes. Commencer petit :
- tuer un Pod
- simuler une latence réseau
- limiter CPU/mémoire
Exemple : supprimer un Pod (il doit être recréé) :
kubectl delete pod -n mon-namespace monapp-xxxxx
kubectl get pods -n mon-namespace -w
8) Anti-patterns fréquents (et comment les éviter)
-
Pipeline trop lente
- Solution : paralléliser, cache dépendances, tests ciblés, exécuter SAST en différé si nécessaire (mais bloquer sur critiques).
-
Déploiements manuels non tracés
- Solution : GitOps, RBAC strict, audit.
-
IaC sans modules ni conventions
- Solution : structure standard, modules réutilisables, lint/policies.
-
Observabilité “cosmétique” (dashboards sans action)
- Solution : SLO, alertes actionnables, runbooks, corrélation logs/traces.
-
Secrets dans les variables CI non maîtrisées
- Solution : secret manager, rotation, scopes, masquage, revues.
9) Checklist opérationnelle (résumé actionnable)
CI
- Lint + tests automatiques à chaque PR
- Scan dépendances + secrets
- Artefact immuable (image taggée SHA)
- Publication dans registry
- Build reproductible (
npm ci, lockfiles)
CD
- Déploiement automatisé (rolling/blue-green/canary)
- Smoke tests post-déploiement
- Rollback documenté et testé
- Feature flags pour réduire le risque
IaC
- Terraform
fmt/validate/planen CI - Backend distant + verrouillage
- Policies sécurité (checkov)
- Séparation dev/prod (comptes/projets si possible)
Observabilité
- Logs JSON avec
trace_id/request_id - Métriques RED/USE + dashboards
- Traces distribuées via OpenTelemetry
- Alertes basées SLO + runbooks
10) Conclusion : une approche progressive et durable
Mettre en place CI/CD, IaC et observabilité n’est pas un “projet outil”, c’est une capacité à livrer vite et bien. La progression la plus efficace consiste souvent à :
- Stabiliser la CI (tests, qualité, artefacts)
- Industrialiser le déploiement (CD) avec rollback et vérifications
- Basculer l’infrastructure en IaC (avec state sécurisé et policies)
- Investir dans l’observabilité (corrélation logs/métriques/traces)
- Mesurer via SLO et améliorer en continu
Si vous voulez, je peux proposer une implémentation complète sur un stack précis (par exemple : GitHub Actions + Terraform + Kubernetes + Prometheus/Grafana + Loki + Tempo + OpenTelemetry), avec une arborescence de repo et des scripts reproductibles.