Aller au contenu principal

GitHub Container Registry (GHCR)

· 4 minutes de lecture

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èreGHCRDocker Hub
Images privéesStockage et transfert décomptés du quota du plan GitHubNombre limité selon le plan
AuthentificationGITHUB_TOKEN (automatique en CI)Token personnel
Intégration CINative (même écosystème)Via secrets
VisibilitéLiée au dépôt GitHubIndé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: write est nécessaire pour pousser vers GHCR
  • GITHUB_TOKEN est généré automatiquement par GitHub Actions : aucun secret à configurer manuellement
  • cache-from: type=gha utilise le cache GitHub Actions pour accélérer les builds successifs
  • docker/metadata-action génère automatiquement les tags et labels OCI standards, dont org.opencontainers.image.source qui 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.