RousselTMLEARNING

DevOps

CI/CD de bout en bout (5/5) : GitHub Actions, GitLab CI, Jenkins et Argo CD en pratique

Comparer et utiliser les outils CI/CD : GitHub Actions, GitLab CI, Jenkins, Argo CD et Flux ; pipeline complet du commit à la production, workflows réutilisables, sécurité des runners et métriques du pipeline.

1. Panorama des outils #

Choisir sans dogmatisme.

Comparaison #

OutilModèlePoints fortsPoints d'attention
GitHub ActionsYAML dans .github/workflows, runners hébergés ou auto-hébergésintégration GitHub, marketplace d'actions, OIDCépingler les actions tierces, coût des minutes
GitLab CI.gitlab-ci.yml, runners GitLabplateforme tout-en-un (registre, sécurité, environnements), auto-hébergeablefichiers complexes à grande échelle (utiliser include et components)
JenkinsJenkinsfile (Groovy), agentstrès extensible, auto-hébergé, historique importantmaintenance des plugins, sécurité du contrôleur
Argo CD / FluxGitOps : le cluster tire l'état depuis Gitsynchronisation continue, détection de dérive, retour arrière par GitKubernetes uniquement, ne remplace pas la CI
AutresCircleCI, Azure Pipelines, Tekton, Dagger, Buildkiteselon l'écosystème—

Push ou pull #

Chaîne CI/CD complète
La CI construit et publie ; Argo CD déploie en tirant l'état décrit dans Git.

En mode push, le pipeline se connecte à la cible et déploie (kubectl, Helm, SSH) : simple, mais la CI détient des accès à la production. En mode pull (GitOps), un agent dans le cluster lit le dépôt et applique les changements : la CI n'a besoin que d'écrire dans Git.

2. Un pipeline complet avec GitHub Actions #

Du commit à la production.

Le workflow #

name: delivery
on:
  push: { branches: [main] }
  pull_request: {}
permissions: { contents: read }
concurrency: { group: delivery-${{ github.ref }}, cancel-in-progress: true }

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with: { python-version: "3.12", cache: pip }
      - run: pip install -r requirements.txt && ruff check . && pytest -q

  build:
    needs: test
    if: github.event_name == 'push'
    runs-on: ubuntu-latest
    permissions: { contents: read, packages: write, id-token: write }
    outputs: { image: "${{ steps.meta.outputs.image }}" }
    steps:
      - uses: actions/checkout@v4
      - id: meta
        run: echo "image=ghcr.io/${GITHUB_REPOSITORY,,}:${GITHUB_SHA::7}" >> "$GITHUB_OUTPUT"
      - uses: docker/login-action@v3
        with: { registry: ghcr.io, username: "${{ github.actor }}", password: "${{ secrets.GITHUB_TOKEN }}" }
      - uses: docker/build-push-action@v6
        with: { push: true, tags: "${{ steps.meta.outputs.image }}" }
      - uses: aquasecurity/trivy-action@0.28.0
        with: { image-ref: "${{ steps.meta.outputs.image }}", severity: CRITICAL, exit-code: "1" }

  deploy-staging:
    needs: build
    environment: staging
    runs-on: ubuntu-latest
    steps:
      - run: ./deploy.sh staging "${{ needs.build.outputs.image }}"
      - run: ./smoke-test.sh https://staging.example.com

  deploy-production:
    needs: [build, deploy-staging]
    environment: production          # règle d'approbation configurée sur l'environnement
    runs-on: ubuntu-latest
    steps:
      - run: ./deploy.sh production "${{ needs.build.outputs.image }}"
      - run: ./smoke-test.sh https://shop.example.com

Réutiliser #

# workflow réutilisable appelé par plusieurs dépôts
jobs:
  ci:
    uses: mon-org/pipelines/.github/workflows/python-ci.yml@v3
    with: { python-version: "3.12" }
    secrets: inherit

3. Le même pipeline avec GitLab CI et Jenkins #

Les concepts sont identiques.

GitLab CI #

stages: [test, build, deploy]
variables: { IMAGE: "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA" }
test:
  stage: test
  image: python:3.12
  cache: { paths: [.cache/pip] }
  script: [pip install -r requirements.txt, pytest -q]
build:
  stage: build
  image: docker:27
  services: [docker:27-dind]
  rules: [{ if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH' }]
  script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - docker build -t $IMAGE . && docker push $IMAGE
deploy-staging:
  stage: deploy
  environment: { name: staging, url: https://staging.example.com }
  script: [./deploy.sh staging $IMAGE]
deploy-production:
  stage: deploy
  environment: { name: production }
  when: manual
  script: [./deploy.sh production $IMAGE]

Jenkins #

// Jenkinsfile (pipeline déclaratif)
pipeline {
  agent { docker { image 'python:3.12' } }
  environment { IMAGE = "registry.example.com/shop/api:${env.GIT_COMMIT.take(7)}" }
  stages {
    stage('Test')  { steps { sh 'pip install -r requirements.txt && pytest -q' } }
    stage('Build') { agent any
      steps { sh 'docker build -t $IMAGE . && docker push $IMAGE' } }
    stage('Staging') { steps { sh './deploy.sh staging $IMAGE' } }
    stage('Production') {
      input { message 'Déployer en production ?' }
      steps { sh './deploy.sh production $IMAGE' } }
  }
  post { failure { echo 'Pipeline en échec : prévenir l\'équipe' } }
}

4. Sécurité et santé du pipeline #

La CI est une cible de choix.

Sécuriser #

  • Permissions minimales par défaut (permissions: contents: read), élargies job par job.
  • Actions tierces épinglées par SHA de commit, revues avant adoption.
  • Pas de secrets exposés aux pull requests venant de forks.
  • Runners auto-hébergés éphémères (un job, une machine), jamais partagés entre projets de confiance différente.
  • OIDC vers le cloud plutôt que des clés longues.
Erreur Courante : Un runner auto-hébergé persistant attaché à un dépôt public permet à n'importe qui d'exécuter du code sur votre réseau via une pull request.

Mesurer le pipeline #

IndicateurCible
Durée du pipeline de commit< 10 min
Taux de succès sur main> 90 %
Délai de réparation d'un build cassé< 1 h
Taux de relance (tests instables)en baisse
Délai commit → productionvoir les métriques DORA

Articles liés

Organiser le DevOps : flux de valeur, équipes et culture sans blâme

Mettre en place une organisation DevOps : chaîne de valeur et value stream mapping, Team Topologies, « you bu…

Git pour le DevOps : branches, revues de code et versions

Organiser le travail avec Git dans une démarche DevOps : trunk-based development ou GitFlow, branches courtes…

CI/CD de bout en bout (1/5) : principes et anatomie d'un pipeline

Comprendre la CI/CD de bout en bout : intégration continue, livraison continue et déploiement continu, étapes…

Pour aller plus loin