
Automatiser la création d'images Docker avec GitHub Actions
Dans le monde du développement moderne, l'automatisation est clé. L'une des tâches les plus courantes est la création et la publication d'images Docker. Au lieu de le faire manuellement à chaque nouvelle version, nous pouvons utiliser GitHub Actions pour l'automatiser.
Dans cet article, je vais vous expliquer pas à pas comment fonctionne le workflow de déploiement (build-and-push.yml) que j'utilise pour ce projet.
1. Déclencheurs (Triggers) : Quand le workflow s'exécute-t-il ?
Tout workflow commence par définir les conditions de son exécution.
on:
push:
tags:
- 'v*'
workflow_dispatch:
inputs:
tag:
description: 'Version tag (ex: v1.0.0)'
required: true
type: string
Ici, le workflow se déclenche de deux manières :
- Automatiquement : À chaque fois qu'un tag Git commençant par
v(par exemplev1.0.0) est poussé sur le dépôt. - Manuellement : Grâce à
workflow_dispatch, on peut lancer le workflow depuis l'interface GitHub en spécifiant un tag manuellement.
2. Variables d'environnement
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
FORCE_JAVASCRIPT_ACTIONS_TO_NODE22: true
Nous définissons quelques variables pour éviter de répéter les mêmes informations :
REGISTRY: Nous utilisons le GitHub Container Registry (ghcr.io).IMAGE_NAME: Le nom de l'image correspondra automatiquement au nom de notre dépôt GitHub.
3. Configuration du Job et Permissions
jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
Le job s'exécute sur un environnement Ubuntu fourni par GitHub.
Il est crucial de configurer les permissions correctement. Le workflow a besoin d'un accès en lecture au code source (contents: read) et d'un accès en écriture pour publier l'image Docker (packages: write).
4. Les étapes du Workflow (Steps)
Voici le cœur du processus, divisé en plusieurs actions.
Étape 1 : Récupération du code
- name: Checkout repository
uses: actions/checkout@v6
On commence par télécharger le code source du dépôt pour que GitHub Actions puisse travailler dessus.
Étape 2 : Préparation de Docker Buildx
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
Buildx est un plugin Docker indispensable qui offre des fonctionnalités avancées, notamment la mise en cache, ce qui accélère considérablement les builds ultérieurs.
Étape 3 : Authentification
- name: Log in to GitHub Container Registry
uses: docker/login-action@v4
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
Avant de publier, le workflow doit se connecter au registre. L'avantage d'utiliser GitHub Actions est que le GITHUB_TOKEN est généré automatiquement ; pas besoin de créer un secret manuellement.
Étape 4 : Gestion des tags et métadonnées
- name: Extract metadata for Docker
id: meta
uses: docker/metadata-action@v6
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=tag
type=raw,value=${{ inputs.tag }},enable=${{ github.event_name == 'workflow_dispatch' && inputs.tag != '' }}
type=raw,value=latest,enable=true
Cette action génère intelligemment les tags pour notre image :
- Le tag Git déclencheur (
v1.0.0). - Le tag fourni manuellement (en cas d'exécution via
workflow_dispatch). - Un tag
latestappliqué automatiquement pour pointer vers la version la plus récente.
Étape 5 : Build et Push
- name: Build and push Docker image
uses: docker/build-push-action@v7
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
C'est ici que la magie opère. Cette action construit l'image en utilisant le Dockerfile situé à la racine (context: .), lui applique les tags générés précédemment, puis la pousse sur le registre.
Voici un exemple de Dockerfile multi-stage adapté à une application Nuxt utilisant pnpm :
ARG NODE_VERSION=24.18.0-alpine
FROM node:${NODE_VERSION} AS build
WORKDIR /app
COPY pnpm-lock.yaml package.json pnpm-workspace.yaml ./
# COPY patches ./patches
# Install pnpm directly and install dependencies
RUN npm install -g pnpm@10.34.5 && \
pnpm install --frozen-lockfile
COPY . .
ENV NODE_OPTIONS="--max-old-space-size=4096"
RUN pnpm build
FROM node:${NODE_VERSION} AS final
WORKDIR /app
COPY --from=build /app/.output .output
EXPOSE 3000
CMD ["node", ".output/server/index.mjs"]
Note de performance : Les paramètres cache-from et cache-to utilisant type=gha (GitHub Actions cache) permettent de sauvegarder les couches Docker entre chaque exécution, réduisant drastiquement le temps de build.
5. Lier ce workflow à Release-It
Pour pousser ce niveau d'automatisation encore plus loin, j'utilise l'outil release-it pour générer les tags automatiquement au lieu de le faire avec des commandes Git manuelles.
Dans mon fichier package.json, j'ai un script dédié :
{
"scripts": {
"release": "dotenv release-it"
}
}
Et une configuration .release-it.json :
{
"git": {
"requireCleanWorkingDir": false,
"tagName": "v${version}",
"commitMessage": "chore: release v${version}"
},
"github": {
"release": true
},
"npm": {
"publish": false
}
}
En tapant simplement pnpm run release dans mon terminal, l'outil me guide pour :
- Choisir le type de version (patch, minor, major).
- Mettre à jour la version dans
package.json. - Créer le commit et le tag Git (
v1.1.13par exemple). - Créer une Release officielle sur GitHub.
Dès que release-it pousse le nouveau tag commençant par v, notre workflow GitHub Actions se déclenche automatiquement !
6. Utiliser l'image Docker générée (Dépôts publics et privés)
Une fois le workflow terminé avec succès, votre image Docker est disponible sur le GitHub Container Registry (GHCR).
Si votre dépôt est public
Tout le monde peut télécharger et exécuter votre image sans aucune authentification. Il suffit de lancer :
docker pull ghcr.io/votre-nom-utilisateur/votre-depot:latest
docker run -p 3000:3000 ghcr.io/votre-nom-utilisateur/votre-depot:latest
Si votre dépôt est privé
Pour les dépôts privés, l'image n'est pas accessible publiquement par défaut. Vous devez d'abord vous authentifier auprès de GHCR avant de pouvoir faire un docker pull.
- Créer un Personal Access Token (PAT) sur GitHub (dans
Settings > Developer settings > Personal access tokens). Ce token doit avoir la permissionread:packages. - Se connecter à GHCR depuis votre serveur ou machine locale :
(Ici,
echo $CR_PAT | docker login ghcr.io -u votre-nom-utilisateur --password-stdin$CR_PATcontient le token que vous avez généré). - Télécharger et lancer l'image comme d'habitude :
docker pull ghcr.io/votre-nom-utilisateur/votre-depot:latest
Astuce : Vous pouvez aussi rendre l'image publique indépendamment de la confidentialité du code source si vous le souhaitez, en modifiant les paramètres de visibilité du package dans l'onglet "Packages" de votre compte GitHub.
Note sur le tag latest : Bien que les exemples ci-dessus utilisent :latest par commodité, vous n'êtes pas obligés de l'utiliser. En environnement de production, il est vivement recommandé de cibler une version spécifique générée par votre workflow (par exemple :v1.1.13) pour figer la version et éviter les mauvaises surprises lors des déploiements.
Conclusion
Avec ce fichier de configuration, publier une nouvelle version de votre application devient aussi simple que de créer un tag Git. L'intégration de la mise en cache et la gestion automatique des tags font de ce workflow une solution robuste et prête pour la production.