Maîtrisez les pipelines CI/CD pour automatiser le build, les tests et le déploiement de vos applications. Concepts, étapes, outils populaires, bonnes pratiques et exemple de pipeline complet avec GitLab CI.
Qu'est-ce que CI/CD ?
CI/CD (Continuous Integration / Continuous Deployment) est un ensemble de pratiques DevOps qui permettent d'automatiser le processus de livraison logicielle, de la compilation du code jusqu'au déploiement en production.
Continuous Integration (CI)
L'intégration continue consiste à fusionner fréquemment (plusieurs fois par jour) les modifications de code dans une branche principale, et à exécuter automatiquement des tests pour détecter les régressions rapidement.
Continuous Delivery (CD)
La livraison continue garantit que le code est toujours dans un état déployable. Chaque changement validé peut être déployé en production sur simple approbation manuelle.
Continuous Deployment (CD)
Le déploiement continu va plus loin : chaque changement validé par les tests est automatiquement déployé en production sans intervention humaine.
- CI : Build + Test automatique à chaque commit
- Continuous Delivery : CI + Déploiement manuel vers prod
- Continuous Deployment : CI + Déploiement automatique vers prod
Concepts fondamentaux
Pipeline
Un pipeline est un ensemble d'étapes automatisées qui transforment le code source en application déployée. Chaque étape (stage) contient des tâches (jobs) qui s'exécutent séquentiellement ou en parallèle.
Build
Le build compile le code source, installe les dépendances et génère les artefacts (fichiers exécutables, images Docker, bundles JavaScript, etc.).
Test
Les tests automatisés vérifient que le code fonctionne correctement :
- Tests unitaires : Testent des fonctions isolées
- Tests d'intégration : Testent l'interaction entre composants
- Tests end-to-end (E2E) : Simulent un parcours utilisateur complet
Artefact
Un artefact est le résultat du build : fichier JAR, image Docker, bundle JavaScript, package npm, etc. Il est versionné et stocké pour être déployé.
Environnement
Les environnements représentent les différentes étapes du cycle de vie :
- Development : Environnement local du développeur
- Staging / Pre-production : Réplique de la production pour tests
- Production : Environnement accessible aux utilisateurs finaux
Étapes typiques d'un pipeline
1. Source / Checkout
Récupération du code source depuis le dépôt Git (GitHub, GitLab, Bitbucket).
git clone https://github.com/user/mon-projet.git
git checkout main
2. Build
Compilation et installation des dépendances.
# Node.js
npm ci
npm run build
# Java Maven
mvn clean package
# Docker
docker build -t mon-app:latest .
3. Test
Exécution des tests automatisés.
# Tests unitaires
npm run test:unit
# Tests d'intégration
npm run test:integration
# Tests E2E
npm run test:e2e
# Analyse de code (linting)
npm run lint
# Couverture de code
npm run coverage
4. Code Quality
Analyse statique du code (SonarQube, ESLint, etc.).
# Analyse SonarQube
sonar-scanner \
-Dsonar.projectKey=mon-projet \
-Dsonar.sources=src \
-Dsonar.host.url=https://sonar.example.com
5. Security Scan
Détection de vulnérabilités dans les dépendances.
# Audit npm
npm audit
# Scan Docker
docker scan mon-app:latest
# OWASP Dependency-Check
dependency-check --project mon-app --scan .
6. Package / Artifact
Création et stockage de l'artefact déployable.
# Push Docker image
docker tag mon-app:latest registry.example.com/mon-app:1.2.3
docker push registry.example.com/mon-app:1.2.3
# Publish npm package
npm publish
# Upload artifact
aws s3 cp dist/ s3://artifacts/mon-app/1.2.3/ --recursive
7. Deploy
Déploiement vers l'environnement cible.
# Kubernetes
kubectl set image deployment/mon-app mon-app=registry.example.com/mon-app:1.2.3
kubectl rollout status deployment/mon-app
# AWS
aws ecs update-service --cluster prod --service mon-app --force-new-deployment
# SSH
scp -r dist/ user@server:/var/www/mon-app/
ssh user@server 'systemctl restart mon-app'
8. Post-deployment Tests
Vérification que l'application fonctionne en production.
# Smoke tests
curl https://mon-app.com/health
curl https://mon-app.com/api/status
# Tests de performance
ab -n 1000 -c 10 https://mon-app.com/
Outils CI/CD populaires
Solutions hébergées (SaaS)
| Outil | Description | Points forts |
|---|---|---|
| GitHub Actions | CI/CD intégré à GitHub | Intégration native, marketplace d'actions |
| GitLab CI/CD | CI/CD intégré à GitLab | Pipeline as code, auto DevOps |
| CircleCI | Plateforme CI/CD cloud | Performance, cache intelligent |
| Travis CI | CI/CD pour projets open source | Gratuit pour projets publics |
| Azure Pipelines | CI/CD Microsoft Azure | Intégration écosystème Microsoft |
Solutions auto-hébergées
| Outil | Description | Points forts |
|---|---|---|
| Jenkins | Serveur CI/CD open source | Flexible, 1800+ plugins |
| TeamCity | CI/CD de JetBrains | Interface intuitive, gratuit jusqu'à 100 builds |
| Drone | CI/CD containerisé | Léger, basé sur Docker |
| Bamboo | CI/CD d'Atlassian | Intégration Jira/Bitbucket |
Exemple : GitLab CI/CD
GitLab CI/CD utilise un fichier .gitlab-ci.yml à la racine du projet.
Pipeline complet Node.js + Docker + Kubernetes
# .gitlab-ci.yml
variables:
DOCKER_IMAGE: registry.gitlab.com/$CI_PROJECT_PATH
DOCKER_TAG: $CI_COMMIT_SHORT_SHA
stages:
- build
- test
- package
- deploy
# Stage 1 : Build
build:
stage: build
image: node:18-alpine
cache:
paths:
- node_modules/
script:
- npm ci
- npm run build
artifacts:
paths:
- dist/
expire_in: 1 hour
# Stage 2 : Tests en parallèle
test:unit:
stage: test
image: node:18-alpine
dependencies:
- build
script:
- npm ci
- npm run test:unit
coverage: '/All files[^|]*\|[^|]*\s+([\d\.]+)/'
artifacts:
reports:
coverage_report:
coverage_format: cobertura
path: coverage/cobertura-coverage.xml
test:integration:
stage: test
image: node:18-alpine
services:
- postgres:15-alpine
variables:
POSTGRES_DB: test
POSTGRES_USER: test
POSTGRES_PASSWORD: test
dependencies:
- build
script:
- npm ci
- npm run test:integration
test:lint:
stage: test
image: node:18-alpine
script:
- npm ci
- npm run lint
test:security:
stage: test
image: node:18-alpine
script:
- npm audit --audit-level=moderate
allow_failure: true
# Stage 3 : Package Docker
package:
stage: package
image: docker:latest
services:
- docker:dind
dependencies:
- build
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
script:
- docker build -t $DOCKER_IMAGE:$DOCKER_TAG -t $DOCKER_IMAGE:latest .
- docker push $DOCKER_IMAGE:$DOCKER_TAG
- docker push $DOCKER_IMAGE:latest
only:
- main
- develop
# Stage 4 : Deploy Staging
deploy:staging:
stage: deploy
image: bitnami/kubectl:latest
environment:
name: staging
url: https://staging.mon-app.com
script:
- kubectl config use-context staging-cluster
- kubectl set image deployment/mon-app mon-app=$DOCKER_IMAGE:$DOCKER_TAG -n staging
- kubectl rollout status deployment/mon-app -n staging
only:
- develop
# Stage 4 : Deploy Production (manuel)
deploy:production:
stage: deploy
image: bitnami/kubectl:latest
environment:
name: production
url: https://mon-app.com
script:
- kubectl config use-context prod-cluster
- kubectl set image deployment/mon-app mon-app=$DOCKER_IMAGE:$DOCKER_TAG -n production
- kubectl rollout status deployment/mon-app -n production
when: manual
only:
- main
Runners GitLab
Les runners exécutent les jobs du pipeline. Installez un runner sur votre serveur :
# Installation du runner
curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh | sudo bash
sudo apt-get install gitlab-runner
# Enregistrement du runner
sudo gitlab-runner register \
--url https://gitlab.com/ \
--registration-token YOUR_TOKEN \
--executor docker \
--docker-image docker:latest
Exemple : GitHub Actions
GitHub Actions utilise des fichiers YAML dans .github/workflows/.
Pipeline CI/CD complet
# .github/workflows/ci-cd.yml
name: CI/CD Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
env:
NODE_VERSION: '18'
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
retention-days: 1
test:
runs-on: ubuntu-latest
needs: build
strategy:
matrix:
test-type: [unit, integration, e2e]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
name: dist
path: dist/
- name: Run ${{ matrix.test-type }} tests
run: npm run test:${{ matrix.test-type }}
- name: Upload coverage
if: matrix.test-type == 'unit'
uses: codecov/codecov-action@v3
with:
files: ./coverage/lcov.info
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- run: npm ci
- run: npm run lint
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- run: npm audit --audit-level=moderate
docker:
runs-on: ubuntu-latest
needs: [build, test, lint]
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
permissions:
contents: read
packages: write
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=sha,prefix={{branch}}-
type=semver,pattern={{version}}
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
deploy:
runs-on: ubuntu-latest
needs: docker
if: github.ref == 'refs/heads/main'
environment:
name: production
url: https://mon-app.com
steps:
- name: Deploy to Kubernetes
uses: azure/k8s-deploy@v4
with:
manifests: |
k8s/deployment.yaml
k8s/service.yaml
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
namespace: production
Secrets GitHub
Stockez les secrets dans Settings → Secrets and variables → Actions :
DOCKER_USERNAMEDOCKER_PASSWORDKUBE_CONFIGAWS_ACCESS_KEY_ID
Stratégies de déploiement
Blue-Green Deployment
Deux environnements identiques (Blue et Green). Le nouveau code est déployé sur l'environnement inactif, puis le trafic bascule instantanément.
❌ Inconvénients : Coûteux (double infrastructure)
Canary Deployment
Le nouveau code est déployé progressivement : d'abord 5% du trafic, puis 25%, puis 50%, jusqu'à 100%.
❌ Inconvénients : Complexe à mettre en place
Rolling Deployment
Les instances sont mises à jour progressivement, une par une ou par batch.
❌ Inconvénients : Durée de déploiement plus longue
Feature Flags
Les nouvelles fonctionnalités sont déployées mais désactivées par défaut, puis activées progressivement via configuration.
// Exemple avec LaunchDarkly
const client = LaunchDarkly.initialize('sdk-key');
if (client.variation('new-checkout-flow', false)) {
// Nouveau flow
showNewCheckout();
} else {
// Ancien flow
showOldCheckout();
}
Bonnes pratiques
- Pipeline as Code : Versionnez vos pipelines dans Git
- Tests obligatoires : Bloquez les merges si les tests échouent
- Builds rapides : Optimisez avec cache et parallélisation (max 10-15 min)
- Fail fast : Exécutez les tests rapides en premier
- Environnements isolés : Staging = copie exacte de production
- Rollback automatique : Si le déploiement échoue, revenez à la version précédente
- Monitoring : Surveillez les métriques après chaque déploiement
- Blue-Green ou Canary : Minimisez l'impact des bugs en prod
- Secrets sécurisés : Ne committez jamais de secrets dans Git
- Notifications : Alertez l'équipe sur Slack en cas d'échec
- Artifacts versionnés : Gardez les artefacts pour rollback rapide
- Documentation : Documentez le processus de rollback manuel
Métriques à surveiller
| Métrique | Objectif |
|---|---|
| Build Time | < 10 minutes |
| Deployment Frequency | Plusieurs fois par jour |
| Lead Time | < 1 heure (commit → production) |
| Mean Time to Recovery (MTTR) | < 1 heure |
| Change Failure Rate | < 15% |
Conclusion
Les pipelines CI/CD sont devenus indispensables pour livrer des applications de qualité rapidement et en toute confiance. En automatisant build, tests et déploiement, vous réduisez les erreurs humaines et accélérez la mise en production.
Combinez CI/CD avec Docker, Kubernetes et Jenkins pour créer une chaîne DevOps complète et professionnelle.