Aller au contenu principal

GitHub Container Registry (GHCR)

· 5 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 actuellement gratuits pour le Container registry (préavis d'un mois annoncé avant toute facturation)Nombre 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

Amazon ECR, le registry équivalent côté AWS, est présenté dans AWS : Docker sur EC2 et ECR.

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 taguer avec le SHA du commit pour garantir la traçabilité (voir Helm : déploiement par tag immuable) :

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 à partir duquel l'image a été construite.

Workflow GitHub Actions​

Le workflow suivant, écrit pour GitHub Actions, 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.

Application / Projet lié​

Mis en pratique dans le projet2024 → aujourd'huiCI/CD - Workflows GitHub Actions mutualisésWorkflow mutualisé docker-ghcr qui publie les images Docker des dépôts de l'organisation sur GHCR, avec en option un tag immuable par SHA de commit.GitHub ActionsDockerHelmPythonROSZephyr
Mis en pratique dans le projet2023 → aujourd'huiBody AnalysisImages de l'API et du frontend publiées sur GHCR à chaque push sur master, taguées à la fois latest et par SHA de commit.FastAPIReactPostgreSQLDockerAndroid