
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.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- 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
Dans quel contexte ?
Section intitulée « Dans quel contexte ? »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
buildpousse l’image, le jobdeployla 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
Prérequis
Section intitulée « Prérequis »- 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 GitLab
Section intitulée « Le Container Registry GitLab »Ce que c’est
Section intitulée « Ce que c’est »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.0registry.gitlab.com/mon-groupe/mon-app:latestregistry.gitlab.com/mon-groupe/mon-app/api:v3Variables d’authentification automatiques
Section intitulée « Variables d’authentification automatiques »Dans un pipeline GitLab CI, trois variables sont injectées automatiquement dans chaque job :
| Variable | Valeur | Usage |
|---|---|---|
CI_REGISTRY | registry.gitlab.com | Adresse du registre |
CI_REGISTRY_USER | gitlab-ci-token | Utilisateur (token temporaire) |
CI_REGISTRY_PASSWORD | Token du job en cours | Mot de passe (expire avec le job) |
CI_REGISTRY_IMAGE | registry.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.
Construire sans DinD avec Buildah
Section intitulée « Construire sans DinD avec Buildah »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"Tagger les images avec stratégie
Section intitulée « Tagger les images avec stratégie »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égie | Variable | Exemple | Usage |
|---|---|---|---|
| Commit SHA | $CI_COMMIT_SHORT_SHA | a1b2c3d4 | Traçabilité exacte |
| Branche | $CI_COMMIT_REF_SLUG | feature-auth | Staging, review apps |
| Tag Git | $CI_COMMIT_TAG | v1.2.0 | Production, releases |
latest | — | latest | Développement local |
Nettoyage automatique (cleanup policies)
Section intitulée « Nettoyage automatique (cleanup policies) »Sans nettoyage, le Container Registry grossit indéfiniment. GitLab propose des cleanup policies automatiques :
- Allez dans Settings > Packages and registries > Container Registry
- Activez Cleanup policy
- Configurez les règles :
| Paramètre | Recommandation | Effet |
|---|---|---|
| Expiration policy | Activée | Nettoie selon les règles ci-dessous |
| Older than | 90 jours | Supprime les images de plus de 90 jours |
| Keep n tags | 10 | Garde 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 :
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 GitLab
Section intitulée « Le Package Registry GitLab »Ce que c’est
Section intitulée « Ce que c’est »Le Package Registry permet de publier et consommer des packages applicatifs directement dans GitLab. Il supporte :
| Format | Cas d’usage | Commande de publication |
|---|---|---|
| npm | Bibliothèques JavaScript/TypeScript | npm publish |
| Maven | Artefacts Java | mvn deploy |
| PyPI | Packages Python | twine upload |
| NuGet | Bibliothèques .NET | dotnet nuget push |
| Go | Modules Go | Proxy natif |
| Composer | Packages PHP | Via API |
| Conan | Bibliothèques C/C++ | conan upload |
| Helm | Charts Kubernetes | helm push |
| Generic | Tout fichier binaire | Via API HTTP |
Publier un package npm depuis la CI
Section intitulée « Publier un package npm depuis la CI »-
Configurez
.npmrcdans 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} -
Ajoutez le scope dans
package.json:{"name": "@mon-scope/ma-lib","version": "1.0.0"} -
Publiez depuis le pipeline :
publish-npm:stage: deployimage: node:22-alpinescript:- npm publishrules:- if: $CI_COMMIT_TAG
Vérification : allez dans Deploy > Package Registry dans votre projet. Vous devez voir votre package avec la version correspondante.
Publier un package Maven depuis la CI
Section intitulée « Publier un package Maven depuis la CI »publish-maven: stage: deploy image: maven:3.9-eclipse-temurin-21 script: - mvn deploy -s ci_settings.xml rules: - if: $CI_COMMIT_TAGAvec 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
Section intitulée « Le Dependency Proxy »Ce que c’est
Section intitulée « Ce que c’est »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.
Pourquoi c’est critique
Section intitulée « Pourquoi c’est critique »Docker Hub applique des quotas de téléchargement calculés sur une fenêtre glissante de 6 heures :
| Type de compte | Limite par 6 heures |
|---|---|
| Non authentifié | 100 pulls par adresse IPv4 (ou sous-réseau IPv6 /64) |
| Personal (authentifié) | 200 pulls |
| Pro / Team / Business | Illimité |
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.
Configurer le Dependency Proxy
Section intitulée « Configurer le Dependency Proxy »-
Activez-le au niveau du groupe : Settings > Packages and registries > Dependency Proxy
-
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 -
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-alpinescript:- npm testlint:image: ${DOCKER_IMAGE_PREFIX}/python:3.12-slimscript:- 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 projettest: image: $CI_REGISTRY_IMAGE:latest script: - pytest
# Image d'un autre projet du même groupelint: 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 allowlistlint: 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 consommateurDOCKER_AUTH_CONFIG: > {"auths":{"registry.gitlab.com":{"auth":"<base64(username:token)>"}}}Dépannage
Section intitulée « Dépannage »| Symptôme | Cause probable | Solution |
|---|---|---|
denied: access forbidden lors du push | Runner non authentifié | Vérifiez docker login avec CI_REGISTRY_* |
error: toomanyrequests | Quota Docker Hub atteint | Activez le Dependency Proxy ou authentifiez Docker Hub |
| Image poussée mais invisible dans l’UI | Registre désactivé sur le projet | Settings > General > Visibility > Container Registry |
manifest unknown sur le pull | Tag inexistant ou cleanup policy trop agressive | Vérifiez le regex “keep” dans les cleanup policies |
Build Buildah échoue avec STORAGE_DRIVER | Driver overlay non supporté dans le conteneur | Utilisez STORAGE_DRIVER: vfs et BUILDAH_ISOLATION: chroot |
Package npm 403 Forbidden | Scope manquant ou .npmrc mal configuré | Vérifiez que @scope correspond au namespace GitLab |
À retenir
Section intitulée « À retenir »- 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
On passe à la pratique
Section intitulée « On passe à la pratique »Mettez ce guide en application dans le Lab 09 — Publier registry.