GitHub Container Registry (GHCR)
GitHub Container Registry (GHCR) est le registry d'images Docker intégré à GitHub. Il stocke les images au même endroit que le code source, partage la gestion des accès avec les dépôts GitHub, et s'intègre nativement dans les workflows GitHub Actions via le token GITHUB_TOKEN.
Différences avec Docker Hub
| Critère | GHCR | Docker Hub |
|---|---|---|
| Images privées | Stockage et transfert décomptés du quota du plan GitHub | Nombre limité selon le plan |
| Authentification | GITHUB_TOKEN (automatique en CI) | Token personnel |
| Intégration CI | Native (même écosystème) | Via secrets |
| Visibilité | Liée au dépôt GitHub | Indépendante |
Nommage des images
Les images GHCR suivent la convention :
ghcr.io/<owner>/<image-name>:<tag>
Où <owner> est le nom d'utilisateur GitHub ou l'organisation. Il est recommandé de tagger avec le SHA du commit pour garantir la traçabilité :
ghcr.io/my-org/api:latest
ghcr.io/my-org/api:1.2.3
ghcr.io/my-org/api:sha-a1b2c3d
Chaque déploiement peut ainsi être retracé jusqu'au commit exact dont l'image a été construite.
Workflow GitHub Actions
Le workflow suivant construit et publie une image à chaque push sur main :
name: Build and push Docker image
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ github.repository }}
tags: |
type=sha
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
Points clés :
permissions.packages: writeest nécessaire pour pousser vers GHCRGITHUB_TOKENest généré automatiquement par GitHub Actions : aucun secret à configurer manuellementcache-from: type=ghautilise le cache GitHub Actions pour accélérer les builds successifsdocker/metadata-actiongénère automatiquement les tags et labels OCI standards, dontorg.opencontainers.image.sourcequi relie l'image au dépôt : grâce à ce label, le package hérite des droits d'accès du dépôt dès sa première publication
Utiliser une image GHCR dans un workflow
Une image GHCR peut servir de conteneur d'exécution pour un job GitHub Actions. Pour une image privée, le runner doit s'authentifier avant le pull : le bloc credentials fournit le GITHUB_TOKEN. Ce jeton n'a accès au package que si celui-ci est lié au dépôt du workflow, ou si le dépôt a été ajouté dans Package settings → Manage Actions access.
jobs:
run-in-container:
runs-on: ubuntu-latest
permissions:
packages: read
container:
image: ghcr.io/my-org/my-image:latest
credentials:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v4
- name: Run tests
run: pytest
Authentification locale
Pour pull une image privée depuis une machine locale :
# Créer un Personal Access Token (classic) avec le scope "read:packages"
# dans GitHub Settings → Developer settings → Personal access tokens
# (write:packages pour pousser des images)
echo $GITHUB_PAT | docker login ghcr.io -u <username> --password-stdin
docker pull ghcr.io/my-org/api:latest
Visibilité des packages
À sa première publication, un package GHCR est privé, y compris lorsqu'il provient d'un dépôt public. Un package lié à un dépôt en hérite les droits d'accès (un utilisateur ayant accès en lecture au dépôt peut lire le package), mais pas la visibilité. La visibilité se modifie dans l'onglet Packages du profil GitHub ou de l'organisation → sélectionner le package → Package settings → Change visibility.
L'accès à un package privé se gère séparément du dépôt : il est possible de donner accès à une image sans donner accès au code source.
Nettoyage des anciennes versions
Chaque push crée une nouvelle version du package. Sans nettoyage, les versions s'accumulent. GitHub propose une action dédiée :
- name: Delete old package versions
uses: actions/delete-package-versions@v5
with:
package-name: api
package-type: container
min-versions-to-keep: 10
delete-only-untagged-versions: true
delete-only-untagged-versions: true supprime uniquement les images sans tag (les builds intermédiaires), en conservant toutes les images taguées explicitement. Ce filtre est à manier avec précaution pour les images multi-architecture : chaque plateforme y est stockée comme un manifeste sans tag, référencé par l'index tagué. Supprimer ces manifestes « orphelins » en apparence rend l'image taguée inutilisable.