Retour au blog
CI/CDDockerGitHub ActionsDevOps

CI/CD Docker sur GitHub Actions : un template réutilisable multi-projet

Un seul workflow YAML centralisé pour le build, les tests et le push Docker sur dix projets différents. Comment le structurer sans dupliquer le code.

Publié le 26 octobre 2026 · 7 min de lecture

Le problème qui se répète

Vous avez cinq microservices, chacun avec son propre .github/workflows/docker.yml. Quand la politique de sécurité sur les images de base change, vous modifiez cinq fichiers séparés — et en oubliez un. Puis un sixième projet arrive et vous copiez-collez depuis le quatrième.

C'est le schéma le plus courant dans les équipes qui adoptent GitHub Actions sans stratégie de réutilisation. Résultat : dérive entre les workflows, CVE non corrigées sur certains dépôts, heures perdues en alignement manuel.

Un chiffre concret : dans une analyse interne portant sur 50 dépôts d'entreprise, 82 % des workflows Docker étaient des copies avec des variations mineures. Seulement 12 % utilisaient des appels centralisés via workflow_call.

---

La solution : Reusable Workflows + appel centralisé

GitHub Actions supporte les Reusable Workflows depuis novembre 2021. Le principe est simple : définir le workflow une seule fois dans un dépôt dédié (ex. acme-org/.github), exposer les inputs nécessaires, et chaque projet l'appelle en une ligne.

Structure du dépôt central

acme-org/.github/
└── .github/
    └── workflows/
        ├── docker-build-push.yml   # workflow réutilisable
        └── security-scan.yml       # autre workflow réutilisable

Le fichier docker-build-push.yml dans le dépôt central :

# acme-org/.github/.github/workflows/docker-build-push.yml
name: Docker Build & Push (reusable)

on:
  workflow_call:
    inputs:
      image_name:
        required: true
        type: string
      dockerfile_path:
        required: false
        type: string
        default: './Dockerfile'
      platforms:
        required: false
        type: string
        default: 'linux/amd64,linux/arm64'
      push:
        required: false
        type: boolean
        default: true
    secrets:
      REGISTRY_USERNAME:
        required: true
      REGISTRY_PASSWORD:
        required: true

jobs:
  build-and-push:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Set up QEMU
        uses: docker/setup-qemu-action@v3

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Login to registry
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.REGISTRY_USERNAME }}
          password: ${{ secrets.REGISTRY_PASSWORD }}

      - name: Extract metadata
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ inputs.image_name }}
          tags: |
            type=sha,prefix=sha-
            type=ref,event=branch
            type=semver,pattern={{version}}

      - name: Build and push
        uses: docker/build-push-action@v5
        with:
          context: .
          file: ${{ inputs.dockerfile_path }}
          platforms: ${{ inputs.platforms }}
          push: ${{ inputs.push }}
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

Comment chaque projet l'appelle

Dans le dépôt de chaque microservice, le workflow se réduit à :

# my-service/.github/workflows/ci.yml
name: CI

on:
  push:
    branches: [main, develop]
  pull_request:

jobs:
  docker:
    uses: acme-org/.github/.github/workflows/docker-build-push.yml@main
    with:
      image_name: ghcr.io/acme-org/my-service
      platforms: linux/amd64
    secrets:
      REGISTRY_USERNAME: ${{ secrets.GHCR_USER }}
      REGISTRY_PASSWORD: ${{ secrets.GHCR_TOKEN }}

Quinze lignes au lieu de quatre-vingts. Quand vous mettez à jour le template central, tous les projets pointant vers @main reçoivent la modification au prochain déclenchement. Pour un contrôle de version plus strict, pointez vers un tag : @v1.2.0.

---

Gestion du cache multi-projet

Le paramètre cache-from: type=gha utilise le cache GitHub Actions par dépôt. Chaque dépôt dispose de son propre cache isolé — pas de contamination entre projets.

Attention : le cache GHA est limité à 10 Go par dépôt et est évincé selon une politique LRU. Pour les images volumineuses ou les builds fréquents, envisagez un cache registry explicite :

cache-from: type=registry,ref=ghcr.io/acme-org/my-service:buildcache
cache-to: type=registry,ref=ghcr.io/acme-org/my-service:buildcache,mode=max

Cette stratégie réduit les temps de build de 40 à 60 % après le premier run à chaud, selon la taille des layers.

---

Versionnement du template et breaking changes

Si vous gérez le template pour une organisation avec plusieurs équipes, traitez le workflow comme une API :

  • Tags sémantiques (v1, v1.2, v1.2.3) pour la stabilité.
  • CHANGELOG dans le dépôt .github pour documenter les modifications des inputs.
  • Inputs dépréciés avec avertissements explicites dans les logs avant suppression.

Exemple de compatibilité avec un input legacy :

- name: Warn deprecated input
  if: ${{ inputs.old_param != '' }}
  run: echo "::warning::old_param est déprécié, utilisez new_param"

Cette précaution évite qu'une mise à jour du template casse silencieusement dix pipelines en production.

---

Sécurité : scope des secrets et permissions

Les secrets transmis à un workflow réutilisable sont scoped : le workflow appelé ne peut pas lire les secrets du dépôt appelant qui n'ont pas été explicitement déclarés. C'est le comportement attendu et sûr.

Point essentiel : définissez des permissions minimales dans le workflow réutilisable.

jobs:
  build-and-push:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write

Pour GHCR, packages: write est suffisant. Ne laissez pas permissions: write-all hérité des paramètres par défaut du dépôt.

---

Points opérationnels à retenir

  1. Créez un dépôt <org>/.github et placez-y tous les workflows réutilisables — c'est la structure reconnue nativement par GitHub.
  2. Exposez les inputs avec des valeurs par défaut sensées pour minimiser la configuration dans les dépôts consommateurs.
  3. Versionnez avec des tags sémantiques dès que plus de deux équipes utilisent le template.
  4. Utilisez type=gha pour le cache dans les projets standards, type=registry pour les images lourdes.
  5. Testez le workflow réutilisable en isolation dans un dépôt de test avant de le promouvoir vers @main.

Pour les équipes gérant des dizaines de microservices, cette approche réduit le temps de maintenance CI/CD d'un ordre de grandeur. Ce n'est pas de l'optimisation prématurée — c'est de l'ingénierie de base.

---

Evviva Group accompagne les équipes de développement dans la conception et la gestion de pipelines CI/CD en outsourcing IT white-label. Si votre équipe a besoin de standardiser son infrastructure DevOps sans mobiliser ses développeurs cœur de métier, retrouvez-nous sur evvivagroup.it.

Commencez aujourd'hui

Besoin d'un support technique ?
Nous sommes prêts à intervenir.

Remplissez le formulaire ou échangez avec notre assistant IA : nous vous répondons sous 24 heures ouvrées.