Date de publication : 1 avril 2026
Temps de lecture : 9 min
Simplifiez la gestion des images de conteneurs grâce à ce guide pas à pas.

Les ingénieurs de plateforme ont probablement tous déjà eu cette conversation :
« L'équipe de sécurité exige que nous utilisions des images de base durcies. »
« Très bien, mais où dois-je configurer les identifiants d'un nouveau registre ? »
« Et comment faire pour que tout le monde les utilise vraiment ? »
Ou celle-ci :
« Pourquoi nos builds sont-ils aussi lents ? »
« Nous téléchargeons la même image de 500 Mo depuis Docker Hub dans chaque job. »
« On ne pourrait pas simplement la mettre en cache quelque part ? »
Chez Gitlab, nous travaillons sur le registre virtuel de conteneurs précisément pour résoudre ces problèmes. Il s'agit d'un cache pull-through qui se place devant vos registres en amont : Docker Hub, dhi.io (images durcies Docker), MCR et Quay. Vos équipes disposent d'un point de terminaison unique pour effectuer un pull des images. Les images sont mises en cache dès le premier pull, et les pulls suivants sont effectués depuis ce cache. Vos équipes n'ont pas besoin de connaître le registre en amont d'une image donnée, ni de s'en préoccuper.
Cet article vous montre comment configurer le registre virtuel de conteneurs, en particulier avec les images durcies Docker : il s'agit d'une combinaison qui a tout son sens pour les équipes qui souhaitent privilégier la sécurité sans compliquer la vie de leurs développeurs.
Les équipes de plateforme avec lesquelles nous échangeons habituellement gèrent des images de conteneurs réparties sur trois à cinq registres :
Chaque registre possède ses propres spécificités :
Vos configurations CI/CD finissent par être encombrées par une logique spécifique à chaque registre. La gestion des identifiants devient un projet à part entière. Chaque job de pipeline effectue un pull des mêmes images de base sur le réseau, même si elles n'ont pas changé depuis des semaines.
Le registre virtuel de conteneurs centralise ces processus dans une seule URL de registre, un seul flux d'authentification (celui de GitLab), et les images en cache sont servies depuis l'infrastructure de GitLab au lieu de transiter par Internet à chaque fois.
Le modèle est simple :
Votre pipeline effectue un pull :
gitlab.com/virtual_registries/container/1000016/python:3.13
Le registre virtuel vérifie :
1. Cette image est-elle en cache ? → La retourner
2. Non ? → La récupérer en amont, la mettre en cache, la retourner
Vous configurez les registres en amont par ordre de priorité. Lorsqu'une pull request arrive, le registre virtuel vérifie chaque registre en amont jusqu'à trouver l'image. Le résultat est mis en cache pour une durée configurable (24 heures par défaut).
┌─────────────────────────────────────────────────────────┐
│ Pipeline CI/CD │
│ │ │
│ ▼ │
│ gitlab.com/virtual_registries/container/<id>/image │
└─────────────────────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────────────────────┐
│ Registre virtuel de conteneurs │
│ │
│ Registre en amont 1: Docker Hub ──────────────────┐ │
│ Registre en amont 2: dhi.io (images durcies) ────┐│ │
│ Registre en amont 3: MCR ───────────────────────┐││ │
│ Registre en amont 4: Quay.io ──────────────────┐│││ │
│ ││││ │
│ ┌────────────────────────────┴┴┴┴──┐ │
│ │ Cache │ │
│ │ (Manifestes + couches) │ │
│ └──────────────────────────────────┘ │
└────────────────────────────────────────────────────────────────────┘
Les images durcies Docker sont idéales en raison de leur surface d'attaque minimale, de leur nombre de vulnérabilités ou expositions communes (CVE) quasi nul, de leurs nomenclatures logicielles (SBOM) complètes et de la provenance SLSA (Supply chain Levels for Software Artifacts). Ne les négligez pas si vous évaluez des images de base pour des charges de travail sensibles en matière de sécurité.
Cependant, leur adoption génère les mêmes frictions opérationnelles que tout nouveau registre :
Le registre virtuel répond à chacun de ces points :
Un seul identifiant : les équipes s'authentifient auprès de GitLab. Le registre virtuel gère l'authentification en amont. Vous configurez les identifiants Docker une seule fois, au niveau du registre, et ils s'appliquent à tous les pulls.
Aucune modification CI/CD par équipe : vous n'avez qu'à diriger vos pipelines vers votre registre virtuel. La configuration des registres en amont est centralisée.
Adoption progressive : étant donné que les images sont mises en cache avec leur chemin complet, vous pouvez voir dans le cache quelles images font l'objet d'un pull. Si quelqu'un effectue un pull de library/python:3.11 au lieu de la variante durcie, vous le saurez.
Piste d'audit : le cache vous montre exactement quelles images sont utilisées. Cette fonctionnalité est utile pour la conformité et pour comprendre les dépendances réelles de votre flotte.
Voici une configuration concrète utilisant le client Python de ce projet de démonstration.
from virtual_registry_client import VirtualRegistryClient
client = VirtualRegistryClient()
registry = client.create_virtual_registry(
group_id="785414", # Your top-level group ID
name="platform-images",
description="Cached container images for platform teams"
)
print(f"Registry ID: {registry['id']}")
# You'll need this ID for the pull URL
Pour les images officielles comme Alpine, Python, etc. :
docker_upstream = client.create_upstream(
registry_id=registry['id'],
url="https://registry-1.docker.io",
name="Docker Hub",
cache_validity_hours=24
)
Les images durcies Docker sont hébergées sur dhi.io, un registre distinct qui nécessite une authentification :
dhi_upstream = client.create_upstream(
registry_id=registry['id'],
url="https://dhi.io",
name="Docker Hardened Images",
username="your-docker-username",
password="your-docker-access-token",
cache_validity_hours=24
)
# MCR for .NET teams
client.create_upstream(
registry_id=registry['id'],
url="https://mcr.microsoft.com",
name="Microsoft Container Registry",
cache_validity_hours=48
)
# Quay for Red Hat stuff
client.create_upstream(
registry_id=registry['id'],
url="https://quay.io",
name="Quay.io",
cache_validity_hours=24
)
Voici un fichier .gitlab-ci.yml qui effectue un pull des images via le registre virtuel :
variables:
VIRTUAL_REGISTRY_ID: <your_virtual_registry_ID>
build:
image: docker:24
services:
- docker:24-dind
before_script:
# Authenticate to GitLab (which handles upstream auth for you)
- echo "${CI_JOB_TOKEN}" | docker login -u gitlab-ci-token --password-stdin gitlab.com
script:
# All of these go through your single virtual registry
# Official Docker Hub images (use library/ prefix)
- docker pull gitlab.com/virtual_registries/container/${VIRTUAL_REGISTRY_ID}/library/alpine:latest
# Docker Hardened Images from dhi.io (no prefix needed)
- docker pull gitlab.com/virtual_registries/container/${VIRTUAL_REGISTRY_ID}/python:3.13
# .NET from MCR
- docker pull gitlab.com/virtual_registries/container/${VIRTUAL_REGISTRY_ID}/dotnet/sdk:8.0
Les différents registres utilisent des conventions de chemin d'accès distinctes :
| Registre | Exemple d'URL de pull |
|---|---|
| Docker Hub (officiel) | .../library/python:3.11-slim |
| Images durcies Docker (dhi.io) | .../python:3.13 |
| MCR | .../dotnet/sdk:8.0 |
| Quay.io | .../prometheus/prometheus:latest |
Après quelques pulls, vérifiez votre cache :
upstreams = client.list_registry_upstreams(registry['id'])
for upstream in upstreams:
entries = client.list_cache_entries(upstream['id'])
print(f"{upstream['name']}: {len(entries)} cached entries")
Nous avons effectué des tests de pulls d'images via le registre virtuel :
| Indicateur | Sans cache | Avec cache chaud |
|---|---|---|
| Temps de pull (Alpine) | 10,3 s | 4,2 s |
| Temps de pull (Python 3.13 DHI) | 11,6 s | ~4 s |
| Allers-retours réseau vers le registre en amont | À chaque pull | Uniquement en cas de défaut de cache |
Le premier pull conserve la même vitesse (il doit récupérer l'image en amont). Tous les pulls suivants, pendant la durée de validité du cache, proviennent directement du stockage GitLab. Plus d'aller-retour réseau vers Docker Hub, dhi.io, MCR ou tout autre registre.
Pour les équipes qui exécutent des centaines de jobs de pipeline par jour, cela représente des heures cumulées de temps de build économisé.
Voici quelques points à garder à l'esprit :
La valeur par défaut est de 24 heures. Pour les images sensibles en matière de sécurité où vous souhaitez obtenir les correctifs rapidement, envisagez 12 heures ou moins :
client.create_upstream(
registry_id=registry['id'],
url="https://dhi.io",
name="Docker Hardened Images",
username="your-username",
password="your-token",
cache_validity_hours=12
)
Pour les images stables et rarement mises à jour (comme les tags de version spécifiques), une durée de validité plus longue est possible.
Les registres en amont sont interrogés dans l'ordre. Si vous avez des images portant le même nom sur différents registres, le premier registre en amont correspondant l'emporte.
Vous pouvez également configurer les registres virtuels et les registres en amont directement depuis l'interface GitLab, sans appels d'API. Accédez à Paramètres > Paquets et registres > Registre virtuel de votre groupe pour :
Nous développons actuellement les éléments suivants :
Il s'agit d'un logiciel en version bêta qui fonctionne. Des équipes l'utilisent déjà en production, mais nous continuons à itérer en fonction des retours.
Si vous êtes ingénieur de plateforme et êtes confronté à la multiplication des registres de conteneurs, nous aimerions comprendre comment vous travaillez :
Partagez vos retours d'expérience dans le ticket dédié au registre virtuel de conteneurs.
Cet article de blog vous a plu ? Vous avez des questions ou des retours à nous faire ? Donnez votre avis en créant un nouveau sujet sur le forum de la communauté GitLab.
Faites-nous part de vos commentaires