Aller au contenu
CI/CD & Automatisation medium

Registries GitLab : construire et publier images et packages

16 min de lecture

logo gitlab

Vos jobs CI construisent des images Docker, mais vous les poussez manuellement vers Docker Hub ? Vos docker pull échouent avec une erreur HTTP 429 parce que Docker Hub limite les téléchargements ? GitLab intègre deux registres au niveau de chaque projet — le Container Registry pour les images Docker et le Package Registry pour les packages applicatifs — ainsi qu’un Dependency Proxy au niveau du groupe pour mettre en cache les images Docker Hub. Ce guide vous montre comment les utiliser concrètement dans vos pipelines.

  • Construire et pousser une image Docker depuis un pipeline GitLab CI
  • Publier un package npm ou Maven dans le Package Registry
  • Configurer le Dependency Proxy pour éviter les quotas Docker Hub
  • Nettoyer automatiquement les anciennes images avec les cleanup policies
  • Choisir entre DinD et Buildah pour construire des images sans mode privileged

Dès que votre pipeline produit un livrable — une image Docker, un package npm, un artefact Maven — vous avez besoin d’un endroit fiable pour le stocker, le versionner et le distribuer. Sans registre intégré, les équipes finissent par :

  • Pousser manuellement vers Docker Hub avec des identifiants partagés
  • Atteindre les quotas Docker Hub (100 pulls par 6 heures sans authentification, 200 avec un compte Personal)
  • Perdre la traçabilité entre le code source et l’image déployée
  • Multiplier les outils externes (Nexus, Harbor, Artifactory) pour un besoin que GitLab couvre nativement

En administration quotidienne, les registres GitLab servent à :

  • Déployer depuis la CI : le job build pousse l’image, le job deploy la tire — tout reste dans GitLab
  • Partager des images de base entre projets d’un même groupe
  • Distribuer des packages internes (bibliothèques, outils CLI) sans publier sur npmjs.com
  • Contourner les limites Docker Hub via le Dependency Proxy du groupe
  • Un projet GitLab avec un pipeline fonctionnel (voir Premier pipeline)
  • Docker installé localement pour tester les builds (voir Docker : premiers pas)
  • Comprendre les variables CI/CD (les variables CI_REGISTRY_* sont injectées automatiquement)
  • Un runner avec l’executor Docker ou Shell (voir Runners)

Le Container Registry est un registre d’images Docker (compatible OCI) intégré à chaque projet GitLab. Il est activé par défaut sur GitLab.com et sur les instances autogérées correctement configurées.

Chaque image est stockée sous une URL prévisible :

registry.gitlab.com/<namespace>/<projet>[/<sous-chemin>]:<tag>

Par exemple, pour un projet mon-groupe/mon-app :

registry.gitlab.com/mon-groupe/mon-app:1.2.0
registry.gitlab.com/mon-groupe/mon-app:latest
registry.gitlab.com/mon-groupe/mon-app/api:v3

Dans un pipeline GitLab CI, trois variables sont injectées automatiquement dans chaque job :

VariableValeurUsage
CI_REGISTRYregistry.gitlab.comAdresse du registre
CI_REGISTRY_USERgitlab-ci-tokenUtilisateur (token temporaire)
CI_REGISTRY_PASSWORDToken du job en coursMot de passe (expire avec le job)
CI_REGISTRY_IMAGEregistry.gitlab.com/<namespace>/<projet>URL complète de l’image

Vous n’avez jamais besoin de stocker des identifiants dans vos variables CI/CD pour pousser vers le Container Registry de votre projet.

Construire et pousser avec Docker-in-Docker (DinD)

Section intitulée « Construire et pousser avec Docker-in-Docker (DinD) »

La méthode classique utilise le service docker:dind (Docker-in-Docker) pour disposer d’un daemon Docker dans le job :

stages:
- build
build-image:
stage: build
image: docker:27
services:
- docker:27-dind
variables:
DOCKER_TLS_CERTDIR: "/certs"
before_script:
- echo "$CI_REGISTRY_PASSWORD" | docker login "$CI_REGISTRY" -u "$CI_REGISTRY_USER" --password-stdin
script:
- docker build -t "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA" -t "$CI_REGISTRY_IMAGE:latest" .
- docker push "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA"
- docker push "$CI_REGISTRY_IMAGE:latest"

Vérification : après le push, allez dans Deploy > Container Registry dans votre projet GitLab. Vous devez voir votre image avec les deux tags.

Buildah construit des images OCI sans daemon Docker — il s’exécute en espace utilisateur, sans mode privileged. C’est l’alternative recommandée par GitLab depuis l’archivage de kaniko (juin 2025) :

build-image-buildah:
stage: build
image:
name: quay.io/buildah/stable:latest
variables:
STORAGE_DRIVER: vfs
BUILDAH_FORMAT: docker
BUILDAH_ISOLATION: chroot
before_script:
- echo "$CI_REGISTRY_PASSWORD" | buildah login -u "$CI_REGISTRY_USER" --password-stdin "$CI_REGISTRY"
script:
- buildah bud
--tag "${CI_REGISTRY_IMAGE}:${CI_COMMIT_SHORT_SHA}"
--tag "${CI_REGISTRY_IMAGE}:latest"
.
- buildah push "${CI_REGISTRY_IMAGE}:${CI_COMMIT_SHORT_SHA}"
- buildah push "${CI_REGISTRY_IMAGE}:latest"

Un bon système de tags facilite le déploiement et le rollback :

build-image:
stage: build
image: docker:27
services:
- docker:27-dind
variables:
DOCKER_TLS_CERTDIR: "/certs"
before_script:
- echo "$CI_REGISTRY_PASSWORD" | docker login "$CI_REGISTRY" -u "$CI_REGISTRY_USER" --password-stdin
script:
- |
# Build une seule fois
docker build -t "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA" .
# Ajouter des tags supplémentaires sans rebuilder
docker tag "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA" "$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG"
# Tag sémantique (si on builde un tag Git)
if [ -n "$CI_COMMIT_TAG" ]; then
docker tag "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA" "$CI_REGISTRY_IMAGE:$CI_COMMIT_TAG"
fi
docker push "$CI_REGISTRY_IMAGE" --all-tags
StratégieVariableExempleUsage
Commit SHA$CI_COMMIT_SHORT_SHAa1b2c3d4Traçabilité exacte
Branche$CI_COMMIT_REF_SLUGfeature-authStaging, review apps
Tag Git$CI_COMMIT_TAGv1.2.0Production, releases
latestlatestDéveloppement local

Sans nettoyage, le Container Registry grossit indéfiniment. GitLab propose des cleanup policies automatiques :

  1. Allez dans Settings > Packages and registries > Container Registry
  2. Activez Cleanup policy
  3. Configurez les règles :
ParamètreRecommandationEffet
Expiration policyActivéeNettoie selon les règles ci-dessous
Older than90 joursSupprime les images de plus de 90 jours
Keep n tags10Garde toujours les 10 derniers tags
Name regex (keep)^v\d+\.\d+\.\d+$Protège les tags sémantiques
Name regex (remove).*Supprime tout ce qui n’est pas protégé

Vous pouvez aussi déclencher le nettoyage via l’API :

Fenêtre de terminal
curl --request DELETE \
--header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
"https://gitlab.com/api/v4/projects/$CI_PROJECT_ID/registry/repositories/$REPO_ID/tags/old-tag"

Le Package Registry permet de publier et consommer des packages applicatifs directement dans GitLab. Il supporte :

FormatCas d’usageCommande de publication
npmBibliothèques JavaScript/TypeScriptnpm publish
MavenArtefacts Javamvn deploy
PyPIPackages Pythontwine upload
NuGetBibliothèques .NETdotnet nuget push
GoModules GoProxy natif
ComposerPackages PHPVia API
ConanBibliothèques C/C++conan upload
HelmCharts Kuberneteshelm push
GenericTout fichier binaireVia API HTTP
  1. Configurez .npmrc dans votre projet :

    @mon-scope:registry=https://gitlab.com/api/v4/projects/${CI_PROJECT_ID}/packages/npm/
    //gitlab.com/api/v4/projects/${CI_PROJECT_ID}/packages/npm/:_authToken=${CI_JOB_TOKEN}
  2. Ajoutez le scope dans package.json :

    {
    "name": "@mon-scope/ma-lib",
    "version": "1.0.0"
    }
  3. Publiez depuis le pipeline :

    publish-npm:
    stage: deploy
    image: node:22-alpine
    script:
    - npm publish
    rules:
    - if: $CI_COMMIT_TAG

Vérification : allez dans Deploy > Package Registry dans votre projet. Vous devez voir votre package avec la version correspondante.

publish-maven:
stage: deploy
image: maven:3.9-eclipse-temurin-21
script:
- mvn deploy -s ci_settings.xml
rules:
- if: $CI_COMMIT_TAG

Avec un fichier ci_settings.xml :

<settings>
<servers>
<server>
<id>gitlab-maven</id>
<configuration>
<httpHeaders>
<property>
<name>Job-Token</name>
<value>${CI_JOB_TOKEN}</value>
</property>
</httpHeaders>
</configuration>
</server>
</servers>
</settings>

Le Dependency Proxy est un cache/miroir transparent pour Docker Hub, activé au niveau du groupe GitLab. Quand un runner tire une image publique (alpine, node, python), le proxy la met en cache dans GitLab. Les pulls suivants sont servis depuis le cache, sans toucher Docker Hub.

Docker Hub applique des quotas de téléchargement calculés sur une fenêtre glissante de 6 heures :

Type de compteLimite par 6 heures
Non authentifié100 pulls par adresse IPv4 (ou sous-réseau IPv6 /64)
Personal (authentifié)200 pulls
Pro / Team / BusinessIllimité

Sur un runner partagé avec plusieurs projets, la limite de 100 pulls par 6 heures (par adresse IP) est atteinte rapidement. Le Dependency Proxy contourne ce problème en servant les images depuis le cache GitLab.

  1. Activez-le au niveau du groupe : Settings > Packages and registries > Dependency Proxy

  2. Utilisez l’URL du proxy dans vos pipelines :

    # Avant (Docker Hub direct, soumis aux quotas)
    image: alpine:3.20
    # Après (via Dependency Proxy, cache du groupe)
    image: ${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX}/alpine:3.20
  3. Pour toutes les images d’un pipeline, utilisez une variable globale :

    variables:
    DOCKER_IMAGE_PREFIX: ${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX}
    test:
    image: ${DOCKER_IMAGE_PREFIX}/node:22-alpine
    script:
    - npm test
    lint:
    image: ${DOCKER_IMAGE_PREFIX}/python:3.12-slim
    script:
    - ruff check .

Vérification : après un premier pull, allez dans Operate > Dependency Proxy au niveau du groupe. Vous devez voir les images mises en cache.

Utiliser des images du Container Registry dans vos pipelines

Section intitulée « Utiliser des images du Container Registry dans vos pipelines »

Une fois vos images construites et poussées, utilisez-les comme images de base dans d’autres jobs ou projets :

# Image du même projet
test:
image: $CI_REGISTRY_IMAGE:latest
script:
- pytest
# Image d'un autre projet du même groupe
lint:
image: registry.gitlab.com/mon-groupe/outils-ci/linter:v2
script:
- run-linter .

Pour tirer une image d’un autre projet, deux options :

Option 1 — CI_JOB_TOKEN + allowlist (recommandé) : le token du job en cours peut accéder au registre d’un autre projet si celui-ci l’autorise explicitement dans sa job token allowlist (Settings > CI/CD > Token Access). Aucun secret supplémentaire à gérer :

# Rien de spécial côté pipeline — le runner s'authentifie automatiquement
# À condition que le projet source ait ajouté votre projet à sa job token allowlist
lint:
image: registry.gitlab.com/mon-groupe/outils-ci/linter:v2
script:
- run-linter .

Option 2 — Deploy Token : pour un accès stable indépendant des pipelines (pulls depuis Docker Desktop, scripts externes), créez un Deploy Token avec la permission read_registry dans le projet source :

# Dans les variables CI/CD du projet consommateur
DOCKER_AUTH_CONFIG: >
{"auths":{"registry.gitlab.com":{"auth":"<base64(username:token)>"}}}
SymptômeCause probableSolution
denied: access forbidden lors du pushRunner non authentifiéVérifiez docker login avec CI_REGISTRY_*
error: toomanyrequestsQuota Docker Hub atteintActivez le Dependency Proxy ou authentifiez Docker Hub
Image poussée mais invisible dans l’UIRegistre désactivé sur le projetSettings > General > Visibility > Container Registry
manifest unknown sur le pullTag inexistant ou cleanup policy trop agressiveVérifiez le regex “keep” dans les cleanup policies
Build Buildah échoue avec STORAGE_DRIVERDriver overlay non supporté dans le conteneurUtilisez STORAGE_DRIVER: vfs et BUILDAH_ISOLATION: chroot
Package npm 403 ForbiddenScope manquant ou .npmrc mal configuréVérifiez que @scope correspond au namespace GitLab
  • Le Container Registry est intégré à chaque projet GitLab — pas besoin de Docker Hub pour vos propres images
  • L’authentification est automatique dans les pipelines via CI_REGISTRY_USER / CI_REGISTRY_PASSWORD
  • Buildah est l’alternative recommandée à DinD pour construire des images sans mode privileged (kaniko est archivé)
  • Le Dependency Proxy met en cache les images Docker Hub au niveau du groupe — indispensable face aux quotas (100 pulls/6h non-auth)
  • Le Package Registry supporte npm, Maven, PyPI, NuGet, Go, Helm et bien d’autres formats
  • Les cleanup policies évitent que votre registre grossisse indéfiniment — protégez vos tags de production
  • L’accès cross-projet privilégie le CI_JOB_TOKEN + allowlist ; les Deploy Tokens servent pour les accès hors pipeline

Mettez ce guide en application dans le Lab 09 — Publier registry.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn