Intégration et livraison continues

Se connecter pour s'inscrire

CI/CD, conteneurs et déploiement

Mettre une application en production de façon reproductible et réversible : chaîne d'intégration, image de conteneur reproductible, contrôle de qualité bloquant, stratégies de déploiement, sécurisation de la chaîne et retour arrière testé.

  1. Public cible

    Débutants, étudiants et professionnels qui souhaitent acquérir une pratique structurée dans ce domaine.

  2. Objectifs

    Comprendre les notions essentielles et les appliquer dans un projet vérifiable.

  3. Prérequis

    Aucune connaissance préalable n’est strictement obligatoire ; les prérequis détaillés sont précisés dans les ateliers.

  4. Niveau

    Tous niveaux

  5. Ressources

    • Documentation officielle et références citées dans les ateliers.
    • Exercices, examens et projet de synthèse du catalogue.
  6. Validation des compétences

    La validation repose sur les évaluations actives et les livrables pratiques du cours.

  7. Besoins techniques

    Un ordinateur, un navigateur et les outils indiqués dans le premier atelier sont suffisants pour commencer.

Exercices, examens et projets

Concepts et chaîne de livraison

Exercice

Atelier CI/CD

Écrire et exécuter une chaîne d'intégration complète.

Obligatoire Consulter
Examen

Examen CI/CD

Évaluer pipeline, artefacts, déploiement et sécurité.

Obligatoire Consulter

Écrire un workflow de CI

Exercice

Atelier CI/CD

Écrire et exécuter une chaîne d'intégration complète.

Obligatoire Consulter
Examen

Examen CI/CD

Évaluer pipeline, artefacts, déploiement et sécurité.

Obligatoire Consulter

Conteneurs et artefacts reproductibles

Exercice

Atelier CI/CD

Écrire et exécuter une chaîne d'intégration complète.

Obligatoire Consulter
Examen

Examen CI/CD

Évaluer pipeline, artefacts, déploiement et sécurité.

Obligatoire Consulter

Déploiement et stratégies

Exercice

Atelier CI/CD

Écrire et exécuter une chaîne d'intégration complète.

Obligatoire Consulter
Examen

Examen CI/CD

Évaluer pipeline, artefacts, déploiement et sécurité.

Obligatoire Consulter

Sécuriser la chaîne

Exercice

Atelier CI/CD

Écrire et exécuter une chaîne d'intégration complète.

Obligatoire Consulter
Examen

Examen CI/CD

Évaluer pipeline, artefacts, déploiement et sécurité.

Obligatoire Consulter

Projet final et méthodologie

Exercice

Atelier CI/CD

Écrire et exécuter une chaîne d'intégration complète.

Obligatoire Consulter
Examen

Examen CI/CD

Évaluer pipeline, artefacts, déploiement et sécurité.

Obligatoire Consulter
  1. Concepts et chaîne de livraison

    1. Présentation du cours

      Objectifs

      1. Comprendre ce qu'apporte une chaîne CI/CD et ce qu'elle ne fait pas.
      2. Écrire un workflow de CI exécutable et lisible.
      3. Construire et versionner une image de conteneur reproductible.
      4. Choisir une stratégie de déploiement selon le risque.
      5. Sécuriser la chaîne : secrets, permissions, dépendances.

      Public visé

      Développeurs et exploitants. Aucune expérience préalable de l'intégration continue n'est requise ; des bases de Git et de Docker sont suffisantes.

      Durée

      35 heures. Chaque module finit par un atelier où le pipeline est réellement exécuté.

    2. Intégration continue et livraison continue

      L'intégration continue (CI) consiste à intégrer fréquemment du code dans une branche commune, en le vérifiant automatiquement à chaque apport. La livraison continue (CD) consiste à rendre chaque intégration vérifiable déployable en production, sans étape manuelle.

      Ce que la chaîne fait à chaque push

      1. récupérer le code et ses dépendances ;
      2. installer l'environnement de façon reproductible ;
      3. exécuter les vérifications : qualité, tests, sécurité ;
      4. construire l'artefact ;
      5. le publier ;
      6. déployer, puis surveiller.

      Chaque étape est un état : succès ou échec. Un état en échec arrête la chaîne — c'est tout l'intérêt.

      Ce qu'elle ne fait pas

      La CI/CD ne corrige pas un mauvais code, ne remplace pas les tests, et ne garantit pas qu'un déploiement est sans risque. Elle rend le feedback immédiat : c'est la rapidité du retour qui fait la qualité.

      La règle du lotissement inverse

      Plus une integration est petite et frequente, moins le conflit est cher a resoudre. L'integrer une fois par semaine, en fin de sprint, avec des branches longues, produit des conflits et desyel merges reportes : c'est l'inverse du principe meme de l'integration continue.

    3. Panorama des outils

      OutilCe que c'estPoint d'attention
      GitHub ActionsCI/CD intégré à l'hébergement Git, configuration en YAML dans le dépôtLe coût dépend du nombre d'exécutionsminutes, pas du nombre de dépôt
      GitLab CI/CDintégré à GitLab, pipeline déclaratif en YAMLfonctionnalités avancées liées à l'offre
      Jenkinsserveur d'automatisation autonome, très flexibleà maintenir soi-même : JVM, plugins, sauvegardes
      Argo CDdéploiement continu déclaratif à partir de l'état voulu du clusterspécifique à Kubernetes

      Le choix se fait sur trois critères : l'hébergement déjà en place, la compétence de l'équipe, et le coût réel (le temps de maintenance est un coût).

  2. Écrire un workflow de CI

    1. Anatomie d'un workflow

      Sur GitHub Actions, un workflow est un fichier YAML dans .github/workflows/. Trois parties : un déclencheur, un ou plusieurs jobs, des étapes.

      name: Intégration continue
      
      on:
        push:
          branches: [main]
        pull_request:
      
      jobs:
        tests:
          runs-on: ubuntu-latest
          steps:
            - uses: actions/checkout@v4
      
            - uses: actions/setup-python@v5
              with:
                python-version: '3.12'
                cache: pip
      
            - name: Installer les dépendances
              run: pip install -r requirements.txt
      
            - name: Vérifier la qualité
              run: ruff check .
      
            - name: Exécuter les tests
              run: python -m pytest -q --cov=app --cov-report=term-missing

      Déclencheurs

      on: indique quand la chaîne part. On peut cibler une branche (branches:), un chemin de fichiers (paths:), tags, ou être déclenché par une autre chaîne (workflow_run).

      on:
        push:
          branches: [main]
          paths:
            - 'src/**'
            - 'tests/**'
          paths-ignore:
            - '**.md'      # la doc seule ne déclenche rien

      Ce que l'on ne commit jamais

      • les secrets : ils vont dans les variables d'environnement du dépôt ou du fournisseur ;
      • les fichiers de dépendance générés (node_modules, vendor, .venv) : ils se réinstallent à chaque exécution.
    2. Matrice de tests et cache

      Tester sur une seule version masque les problèmes qui n'apparaissent qu'ailleurs. Une matrice se déclare en une ligne.

      jobs:
        tests:
          runs-on: ubuntu-latest
          strategy:
            fail-fast: false        # on veut le résultat de toutes les versions
            matrix:
              python-version: ['3.11', '3.12', '3.13']
              os: [ubuntu-latest, windows-latest]
          steps:
            - uses: actions/checkout@v4
            - uses: actions/setup-python@v5
              with:
                python-version: ${{ matrix.python-version }}
                cache: pip
            - run: pip install -r requirements.txt
            - run: python -m pytest -q

      Chaque combinaison est un job indépendant. Pour suivre la progression d'un job précis, on utilise la syntaxe ${{ matrix.python-version }}.

      Accélérer sans perdre en fiabilité

      • cache des dépendances : le gestionnaire de paquets est configuré pour réutiliser le cache ;
      • paralléliser les étapes indépendantes dans un même job, ou séparer en jobs quand elles sont vraiment indépendantes ;
      • ne pas réinstaller ce qui est déjà là ;
      • filtrer les tests lents dans un job séparé exécuté en parallèle.
    3. Cache et gestion du temps d'exécution

      Le cache se déclare sur l'action qui le gère, pas globalement : la clé est calculée à partir d'un fichier qui décrit les dépendances, pour être invalidée dès qu'il change.

      - uses: actions/cache@v4
        with:
          path: ~/.cache/pip
          key: pip-${{ runner.os }}-${{ hashFiles('requirements.txt') }}
          restore-keys: |
            pip-${{ runner.os }}-

      hashFiles porte sur le fichier qui décrit les dépendances : si une dépendance change, la clé change et le cache précédent n'est plus réutilisé.

      Mesurer avant d'optimiser

      1. regarder la durée de chaque étape, pas seulement le total ;
      2. l'étape la plus longue est presque toujours l'installation des dépendances ;
      3. le cache gagne du temps mais occupe de l'espace : et le gain réel se voit dans les statistiques de la plateforme.
    4. Exercices

      1. Premier pipeline : écrivez un workflow qui s'exécute à chaque push sur main, installe les dépendances, lance les tests et échoue si la couverture passe sous 80 %.
      2. Cache : ajoutez la mise en cache du gestionnaire de paquets et vérifiez que la seconde exécution est plus rapide.
      3. Matrice : faites tourner les tests sur trois versions du langage et sur deux systèmes, avec fail-fast: false.
      4. Bonus : ajoutez une étape qui ne s'exécute que sur la branche principale.
  3. Conteneurs et artefacts reproductibles

    1. Construire une image de qualité

      Un artefact de livraison doit être reproductible : deux constructions de la même révision donnent la même image. Sans cela, « ça marche en préproduction » ne prouve rien.

      Construire et versionner

      docker build -t mon-service:1.4.2 .
      docker tag mon-service:1.4.2 registry.exemple.fr/mon-service:1.4.2
      docker push registry.exemple.fr/mon-service:1.4.2

      Le tag est le numéro de version, jamais latest seul : latest est une étiquette mouvante, et un déploiement doit pouvoir dire exactement quelle version tourne.

      Le fichier de construction multi-étapes

      # syntaxe moderne : 'AS etape' nomme l'etape
      FROM python:3.12-slim AS deps
      WORKDIR /app
      COPY requirements.txt .
      RUN pip install --no-cache-dir -r requirements.txt
      
      FROM python:3.12-slim AS runtime
      WORKDIR /app
      COPY --from=deps /usr/local /usr/local
      COPY . .
      USER 1000:1000
      CMD ["python", "-m", "app"]

      La construction multi-étapes garde la couche de compilation hors de l'image finale : l'artefact livré ne contient que ce qui sert à exécuter. Exécuter avec un utilisateur non privilégié fait partie de la même discipline.

      reproductibilité

      • .dockerignore pour exclure .git, les tests et les fichiers locaux ;
      • versions de base épinglées par digest, pas seulement par étiquette ;
      • dépendances verrouillées (requirements avec versions épinglées, verrou de dépendances) ;
      • ordre des copies stable pour que le cache de couches reste valable.
    2. Vérifier avant de publier

      La chaîne doit bloquer ce qui ne doit pas être livré, pas seulement signaler. Trois contrôles à placer avant la construction :

      1. analyse de dépendances : vulnérabilités connues et licences interdites ;
      2. analyse statique : erreurs manifestes, secrets par inadvertance ;
      3. analyse de l'image : après construction, avant publication.
            - name: Vérifier les vulnérabilités
              run: pip-audit --strict
      
            - name: Construire
              run: docker build -t mon-service:1.4.2 .
      
            - name: Scanner l'image
              run: |
                test "$(trivy image --severity HIGH,CRITICAL --format json mon-service:1.4.2 | jq '.Results | length')" = "0"

      Le point clé : l'étape échoue si la vérification échoue. Un tableau de bord consultable après coup ne remplace pas une porte fermée dans la chaîne.

    3. Registre et gestion des versions

      Un registre d'images est un dépôt d'artefacts. Il doit être accessible par la chaîne, protégé par des identifiants dédiés, et able de signaler ce qu'il accepte.

      Versionner correctement

      # version semantique : MAJEUR.MINEUR.PATCH
      1.4.2    # version stable fixee
      1.4      # serie de correctifs
      1        # toute la serie 1.x
      sha-9f2c1ab   # version exacte et immuable

      Déployer en production avec une étiquette mouvante est la première cause de « ça marchait hier ». Le déploiement doit nommer la révision, par exemple par empreinte de commit.

      Les secrets de la chaîne

      • un secret par usage, jamais un secret partagé ;
      • accès en écriture uniquement pour la chaîne de construction, en lecture seule ailleurs ;
      • rotation périodique et journalisation des accès ;
      • aucun secret dans les journaux de la chaîne : un secret affiché dans la sortie d'une étape est compromis.
    4. Exercices

      1. Construction en deux étapes : transformez un fichier de construction simple en version multi-étapes et comparez la taille des deux images.
      2. Reproductibilité : construisez deux fois la même image et vérifiez que l'empreinte obtenue est identique. Si elle change, identifiez la source d'instabilité.
      3. Porte fermée : ajoutez une étape qui échoue si une vulnérabilité critique est détectée, et provez-le avec une image volontairement vulnérable.
  4. Déploiement et stratégies

    1. Environnements et configuration

      Un environnement est un déploiement avec ses propres données et sa propre configuration. Trois environnements minimum : développement, préproduction, production.

      La règle : le même artefact est déployé partout. Reconstruire par environnement casse la reproductibilité — ce qui est validé en préproduction n'est alors plus l'artefact qui part en production.

      Configuration par variable d'environnement

      Le code ne contient ni clé ni adresse de production : il lit des variables, injectées par la plateforme selon l'environnement.

      # developpement, dans un fichier local non versionne
      DATABASE_URL=postgresql://localhost:5432/app
      
      # production, dans les variables de l'hebergeur
      DATABASE_URL=postgresql://...:...@db.interne:5432/app

      Ce qui change d'un environnement à l'autre : adresses, identifiants, seuils, activation de fonctionnalités. Ce qui ne change pas : le code et la version de l'artefact.

    2. Stratégies de déploiement

      Choisir une stratégie, c'est choisir un compromis entre la rapidité du retour arrière et la disponibilité pendant la bascule.

      StratégiePrincipeRetour arrière
      Arrêt / démarrageon arrête, on met à jour, on démarreimmédiat mais coupure de service
      Défilant (rolling)instances remplacées par lots successifspossible tant qu'aucun lot n'est terminé
      Bleu / vertdeux environnements identiques, bascule du traficimmédiat, on rebascule le trafic
      Canaripetite fraction du trafic vers la nouvelle versionon retire les canaris, effet local

      Migrer la base : le vrai piège

      Le déploiement du code est réversible ; une migration de base ne l'est pas toujours. Trois règles :

      1. Compatible dans les deux sens : la nouvelle version du code doit fonctionner avec l'ancien schéma, et l'ancienne avec le nouveau.
      2. En deux temps : on ajoute ce qui manque (colonne, table), on déploie le code qui l'utilise, puis on supprime l'ancien élément au déploiement suivant.
      3. Sauvegarde vérifiée avant toute migration destructive, et restauration testée.

      Une migration destructive dans le même déploiement que la mise à jour du code, c'est le meilleur moyen de ne pas pouvoir revenir en arrière.

    3. Retour arrière et bascule progressive

      Le retour arrière doit avoir été préparé avant le déploiement : c'est une décision et une procédure, pas une improvisation.

            - name: Déployer la version preparee
              run: kubectl apply -f manifeste.yaml
      
            - name: Vérifier la sante
              run: ./verification-sante.sh
      
            - name: Revenir en arriere si la verification echoue
              if: failure()
              run: kubectl rollout undo deployment/mon-service

      Le déploiement progressif consiste à étaler la bascule : une fraction du trafic d'abord, on observe, puis on élargit. L'observation porte sur des signaux métier — taux d'erreur, latence, et si possible une métrique qualitative du produit — pas seulement sur « le processus répond ».

      Runbook

      Un runbook écrit avant l'incident vaut dix minutes gagnées pendant : dernière version saine, commande de retour arrière, personnes à prévenir, critères de décision. Il doit être dans le dépôt, versionné comme le reste.

    4. Exercices

      1. Scénario de migration : votre table a une colonne telephone à supprimer et une table factures à créer. Écrivez les étapes de déploiement dans l'ordre, en indiquant à chaque fois ce qui reste réversible.
      2. Runbook : écrivez le runbook de retour arrière de votre application, en moins d'une page.
      3. Stratégie : pour un site à fort trafic, quelle stratégie choisissez-vous, et quel indicateur vous ferait basculer sur l'autre ?
  5. Sécuriser la chaîne

    1. Chaîne d'approvisionnement logicielle

      La chaîne d'intégration est elle-même du code : elle dépend de la plateforme, d'actions tierces et de dépendances. Une action compromise, ou un jeton volé, donne un accès direct à la production.

      La menace la plus courante : le jeton

      Un jeton de déploiement est aussi un mot de passe. Il se protège comme tel : périmètre restreint, durée de vie courte, révocation immédiate possible, journalisation des usages.

      • un jeton par usage et par environnement, jamais un jeton qui touche tout ;
      • jamais de jeton écrit dans un fichier du dépôt ;
      • accès en lecture seule pour tout ce qui n'écrit pas ;
      • vérifier qui a utilisé le jeton, et quand.

      La dépendance non maîtrisée

      Une action est un logiciel que l'on exécute avec nos identifiants. Deux questions à poser avant de l'ajouter : qui la maintient, et que se passe-t-il si elle est compromise ? On privilégie les actions de l'éditeur du dépôt lui-même, et on épingle les versions.

    2. Permissions minimales

      La règle est simple et rarement appliquée : la chaîne reçoit le strict nécessaire, et pas plus.

      1. une chaîne de lecture ne peut pas écrire ;
      2. une chaîne de construction n'a pas à déployer en production ;
      3. les chaînes déclenchées depuis l'extérieur sont plus restraints que celles déclenchées par le dépôt ;
      4. les modifications de configuration du dépôt peuvent exiger une approbation explicite.

      Une pull request qui touche la configuration de la chaîne elle-même mérite un regard humain : c'est elle qui définit ce qui a le droit de se produire.

    3. Secrets et environnement

      Un secret ne doit apparaître ni dans le dépôt, ni dans les journaux, ni dans les artefacts.

      • stockage dédié de la plateforme, chiffré, avec journalisation des lectures ;
      • injection dans l'environnement de l'étape, jamais dans la ligne de commande (elle se lit dans les journaux) ;
      • masquage dans la sortie d'exécution : la majoration des plateformes masque les secrets connus, mais pas une valeur écrite par erreur dans un echo ;
      • rotation régulière, et immédiate en cas de doute.
            - name: Publier
              env:
                JETON: ${{ secrets.JETON_PUBLICATION }}
              run: |
                # la variable d'environnement est injectee, elle n'apparait pas dans la commande
                curl --header "Authorization: Bearer $JETON" https://registre.exemple.fr/v2/

      Le point souvent ignoré : un secret retiré d'un fichier ne l'est pas de l'historique git, ni des caches de la chaîne, ni des journaux déjà collectés. Le changer est la seule action qui vaut.

    4. Provenance et traçabilité

      À la fin, deux questions doivent pouvoir obtenir une réponse rapide : quelle version tourne en production, et quelle version a introduit ce comportement.

      • un identifiant unique par artefact, propagé jusque dans l'application exposée ;
      • les journaux applicatifs portent cet identifiant : on sait immédiatement quelle version écrit la ligne ;
      • les images publiées ne sont jamais réécrites : une étiquette est immuable une fois poussée ;
      • la chaîne elle-même est versionnée et revue.

      Sans cela, un incident se passe à deviner. Avec cela, on remonte de l'incident à la révision en une requête.

    5. Exercices

      1. Audit : prenez une chaîne existante et listez tous les secrets qu'elle utilise, puis dites pour chacun s'il est trop large et comment le restreindre.
      2. Traçabilité : ajoutez l'identifiant de révision dans les journaux de votre application et vérifiez qu'une ligne de log permet de retrouver la version déployée.
      3. Fuite simulée : mettez par erreur un secret en clair dans un journal, expliquez ce qui se passe ensuite, et corrigez la chaîne.
  6. Projet final et méthodologie

    1. Projet fil rouge : mettre une application en production

      Le projet est realized sur une petite application de votre choix, et vise un résultat vérifiable : la chaîne part d'un commit et mène jusqu'à une version déployée et traçable.

      Les six livrables

      1. Chaîne d'intégration : installation reproductible, qualité, tests, couverture minimale, matrice sur deux systèmes.
      2. Image de livraison : construction multi-étapes, utilisateur non privilégié, .dockerignore, empreinte reproductible vérifiée par deux constructions.
      3. Porte de qualité : analyse de dépendances et analyse d'image qui font échouer la chaîne, pas seulement rapportent.
      4. Déploiement : même artefact déployé sur deux environnements, configuration par variables, stratégie choisie et justifiée.
      5. Retour arrière : procédure écrite, testée, avec critère de décision.
      6. Traçabilité : l'identifiant de version remonte des journaux jusqu'au commit.

      Critères de réussite

      • un git clone suivi de la procédure documentée reconstruit tout, sans connaissance préalable ;
      • une modification du code, mergée, se retrouve déployée sans intervention manuelle ;
      • une pull request qui casse un test n'est pas mergée ;
      • le retour arrière est réalisé en moins de cinq minutes et vérifié.
    2. Méthodologie et anti-patterns

      Par où commencer dans un projet existant

      1. un seul pytest qui passe en moins de cinq minutes ;
      2. la chaîne d'intégration, sans déploiement ;
      3. l'image reproductible ;
      4. la porte de qualité ;
      5. enfin le déploiement automatisé.

      Commencer par le déploiement automatisé sur une base non testée, c'est automatiser un accident : on ne saura jamais si un échec vient du code ou de l'infrastructure.

      Les anti-patterns les plus fréquents

      • Déployer depuis un poste : ce qui n'est pas dans la chaîne n'est pas reproductible.
      • Étiquette mouvante en production : on ne sait plus ce qui tourne.
      • Migration destructive en même temps que le code : plus de retour arrière possible.
      • Chaîne qui ne peut pas échouer : un contrôle qui rapporte sans bloquer ne protège rien.
      • Secret en clair dans le dépôt : il le restera dans l'historique.
      • Chaîne de 40 minutes : les développeurs arrêtent de la regarder, et l'évitent chaque jour.

      Faire adopter

      Une chaîne imposée sans explication est contournée. Le meilleur moyen de la faire adopter : rendre le délai entre « j'ai poussé » et « je sais si ça marche » plus court que le délai d'attente du prochain test manuel. L'adoption suit le bénéfice ressenti, pas la note de couverture.

      Outils à connaître

      • ruff, black, mypy : qualité Python
      • pytest : tests
      • trivy, pip-audit : sécurité des dépendances
      • hadolint : qualité des fichiers de construction
      • cosign : signature d'image
    3. Ressources et évaluation

      Évaluation

      • Quiz à la fin de chaque module.
      • Atelier : la chaîne est réellement exécutée, et ses logs lus ensemble.
      • Projet final : les six livrables, évalués sur la reproductibilité et la vérifiabilité — pas sur le nombre d'exécutions.
      • Revue : chaque atelier est relu, et les remarques portent sur des points précis.

      Grille du projet

      • fonctionnel : la chaîne mène du commit au déploiement sans intervention
      • sûr : secrets gérés, permissions minimales, porte de qualité bloquante
      • reproductible : deux constructions donnent la même empreinte
      • exploitable : retour arrière testé, runbook écrit
Sources et documentation de reference

Atelier guidé

Mettre en service un projet qui n'en a pas, et ledemontrer de bout en bout.

  1. Pipeline : ecrire un fichier qui installe, teste et construit, et qui echoue a la premiere erreur.
  2. Quality : ajouter tests statiques et formatage, avec une porte qui bloque la livraison si un controle echoue.
  3. Secrets : sortir les secrets du depot et les lire depuis l’environnement, puis prouver qu’un commit ne les contient pas.
  4. Livraison : declarer les versions de dependances de facon reproductible, et le dire dans le rapport.

Restitution de l’atelier

  • Le pipeline, avec une capture de chaque etape verte.
  • Le rapport d’un echec volontaire, et ce qu’il a prouve.
  • La liste des secrets lies au depot, et comment on le verifie.
Validation : Le pipeline est vert sur une branche neuve, et rouge des qu’un test casse. Les logs durent plus longtemps que le job.

Publié le 28/09/2026