Introduction
Un registre Docker privé est un élément d’infrastructure critique pour de nombreuses équipes de développement. Il stocke et sert des images de conteneurs, et lorsqu’il tombe en panne, il peut bloquer les pipelines CI/CD, empêcher les déploiements et frustrer les développeurs. Ce guide se concentre sur les erreurs courantes du registre Docker et sur la manière de les corriger avec des exemples pratiques. Nous couvrons les erreurs de configuration, les problèmes de stockage, les problèmes d’authentification et les pièges opérationnels. Chaque section fournit des commandes concrètes, les résultats attendus et les étapes de récupération.
Cet article s’adresse aux opérateurs, aux ingénieurs DevOps et aux développeurs qui gèrent un registre Docker auto-hébergé (l’image registry:2 de Docker, souvent appelée Distribution). Il suppose que vous avez des compétences de base en Docker et en ligne de commande Linux, ainsi qu’un accès à l’hôte du registre. Nous mettons l’accent sur une approche prudente : observer avant de modifier, limiter le rayon d’impact, toujours utiliser des exemples sans secrets réels et vérifier après chaque correction. Nous ne couvrirons pas les registres gérés comme Docker Hub, Amazon ECR ou Google Artifact Registry, sauf occasionnellement à des fins de comparaison. L’objectif est de vous aider à diagnostiquer et à résoudre rapidement les problèmes de votre propre registre.
Inventaire des versions et de l’environnement
Avant de procéder au dépannage, vous devez avoir une vision claire de la configuration de votre registre. Connaître la version exacte, la méthode de déploiement et le backend de stockage est essentiel, car les erreurs et les correctifs diffèrent selon les versions.
Commencez par trouver le conteneur du registre et sa version. Exécutez :
docker ps --format "table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}"
Recherchez un conteneur utilisant une image comme registry:2 ou une image personnalisée. Pour obtenir la version exacte, exécutez à l’intérieur du conteneur :
docker exec <conteneur-registre> registry --version
Exemple de sortie attendue :
registry github.com/docker/distribution v2.8.3+unknown
Si vous exécutez le registre sous Docker Compose ou Kubernetes, trouvez le fichier manifeste ou de déploiement. Pour Compose, docker compose ps et docker compose config affichent l’état actuel et la configuration effective. Pour Kubernetes, utilisez kubectl get pods -l app=registry -o yaml et kubectl describe pod <nom-du-pod>.
Notez également comment le registre est configuré. Le fichier de configuration principal est généralement /etc/docker/registry/config.yml à l’intérieur du conteneur, mais il peut être monté depuis l’hôte. Inspectez les montages du conteneur :
docker inspect <conteneur-registre> --format '{{ json .Mounts }}' | jq
Cela montre les volumes et les montages de type bind, qui sont cruciaux pour le dépannage du stockage. Par exemple :
[
{
"Type": "bind",
"Source": "/opt/registry/data",
"Destination": "/var/lib/registry",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
]
Dans ce cas, les données sont stockées sur l’hôte à /opt/registry/data. Si ce chemin n’est pas persistant ou a des permissions incorrectes, le registre échouera à écrire des images.
Capturez toujours l’état actuel avant de faire des changements. Enregistrez la sortie de docker inspect, le fichier de configuration et les journaux dans un répertoire temporaire. Cela vous donne un point de restauration et aide à l’analyse post-mortem. Par exemple :
mkdir -p /tmp/registry-debug-$(date +%Y%m%d-%H%M%S)
docker inspect <conteneur-registre> > /tmp/registry-debug-*/inspect.json
docker logs <conteneur-registre> --tail 200 > /tmp/registry-debug-*/logs.txt
Utilisez des espaces réservés pour les secrets dans toute commande que vous partagez ou documentez. Ne collez pas de mots de passe ou de jetons réels.
Chemin de configuration sûr
De nombreuses erreurs de registre proviennent d’une mauvaise configuration. Le registre utilise un fichier YAML, généralement config.yml. Examinons une configuration minimale, puis discutons des erreurs courantes.
Une configuration de base qui utilise le système de fichiers local pour le stockage et permet les pulls anonymes pourrait ressembler à ceci :
version: 0.1
log:
level: info
fields:
service: registry
storage:
filesystem:
rootdirectory: /var/lib/registry
delete:
enabled: true
http:
addr: :5000
Si vous avez besoin d’une authentification, vous ajouteriez une section auth, souvent en utilisant htpasswd :
auth:
htpasswd:
realm: basic-realm
path: /auth/htpasswd
Mais une erreur courante est la non-concordance des chemins entre le fichier de configuration et les montages de volumes. Par exemple, si vous définissez rootdirectory sur /var/lib/registry mais que le volume est monté à /var/lib/registry, assurez-vous que le montage est correct. Si vous utilisez un chemin différent, comme /data, mais que le montage est à /var/lib/registry, le registre écrit dans la couche du conteneur et les données disparaissent lors de la recréation du conteneur.
Pour modifier la configuration en toute sécurité :
- Copiez le fichier de configuration actuel depuis le conteneur ou l’hôte.
docker cp <conteneur-registre>:/etc/docker/registry/config.yml /tmp/config.yml.backup
- Apportez vos modifications dans un environnement de test. Si vous utilisez Docker Compose, vous pouvez créer un fichier compose séparé pour les tests avec un port et un stockage différents.
- Validez la syntaxe YAML. Utilisez
docker run --rm -v /tmp/config.yml:/config.yml -it registry:2 registry serve /config.ymlmais cela commencera à servir ; à la place, vous pouvez utiliser un linter YAML commeyamllintsur l’hôte. À l’intérieur du conteneur, vous pouvez utiliserpython -c 'import yaml, sys; yaml.safe_load(sys.stdin)' < config.ymlsi Python est disponible. - Appliquez le changement en recréant le conteneur avec la nouvelle configuration (montez le fichier en lecture seule).
- Surveillez les journaux :
docker logs -f <conteneur-registre>.
Pour les changements de configuration, gardez toujours le rayon d’impact petit. Modifiez un paramètre à la fois et documentez le résultat attendu. Si le registre ne démarre pas, revenez à la configuration de sauvegarde et enquêtez.
Un exemple pratique : activer l’API de suppression pour permettre de supprimer des images. De nombreux utilisateurs rencontrent des erreurs « Method Not Allowed » lorsqu’ils tentent de supprimer une image car la fonctionnalité de suppression n’est pas activée par défaut dans la configuration. Le message d’erreur d’un client comme docker push ou curl pourrait être :
HTTP 405 Method Not Allowed
La correction consiste à définir delete.enabled: true sous storage comme montré ci-dessus. Après modification, redémarrez le registre et testez avec une requête curl -X DELETE vers un manifeste d’image. Notez que l’activation de la suppression ne libère pas immédiatement l’espace disque ; vous devez exécuter le ramasse-miettes (voir section Stockage).
Vérification et diagnostics
Après tout changement, vous devez vérifier que le registre se comporte comme prévu. Commencez par les vérifications de santé. L’image du registre inclut un healthcheck si configuré, mais vous pouvez aussi utiliser curl vers l’endpoint /v2/.
Exécutez depuis l’hôte ou à l’intérieur du conteneur :
curl -v http://localhost:5000/v2/
Réponse réussie attendue :
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Docker-Distribution-Api-Version: registry/2.0
{}
Si vous obtenez une erreur 404 ou un refus de connexion, le registre n’écoute pas correctement ou le mappage de port est incorrect. Vérifiez docker port <conteneur-registre> et docker logs pour des erreurs comme listen tcp :5000: bind: address already in use.
Un autre diagnostic courant est de vérifier le push et le pull d’images. Utilisez une petite image de test, taguez-la vers votre registre local, puis poussez-la :
docker pull alpine:latest
docker tag alpine:latest localhost:5000/alpine:test
docker push localhost:5000/alpine:test
Observez la sortie pour les erreurs. Un push réussi se termine par une ligne de digest. Si l’authentification est activée, vous devez d’abord exécuter docker login localhost:5000.
Pour des diagnostics plus approfondis, inspectez l’API du registre avec curl pour lister les dépôts et les tags :
curl -s http://localhost:5000/v2/_catalog
curl -s http://localhost:5000/v2/alpine/tags/list
Sortie attendue :
{"repositories":["alpine"]}
{"name":"alpine","tags":["test"]}
Si vous voyez des erreurs, consultez les journaux du registre. Augmentez temporairement le niveau de journalisation à debug dans la configuration pour une sortie plus verbeuse. N’oubliez pas de revenir à info après le dépannage.
Modes de défaillance et récupération
Voici des modes de défaillance spécifiques avec leurs correctifs.
1. « dial tcp: lookup registry on 127.0.0.53:53: no such host » lors d’un pull depuis un registre distant
Cette erreur se produit lors de l’utilisation d’un registre comme cache pull-through ou lorsque le registre tente de contacter un registre distant mais que la résolution DNS échoue. Vérifiez la configuration réseau du registre, en particulier les paramètres DNS. Si vous l’exécutez dans Docker, assurez-vous que le conteneur a un DNS correct. Vous pouvez spécifier le DNS dans la commande docker run avec --dns. Alternativement, si vous utilisez un cache proxy, assurez-vous que le paramètre remoteurl dans la configuration est correct et accessible.
2. Erreur « manifest unknown » lors du pull
Lorsque vous poussez une image et que quelqu’un d’autre essaie de la tirer, il peut obtenir « manifest unknown ». Cela se produit souvent lorsque le registre est configuré avec plusieurs backends de stockage (comme S3 et filesystem) et que le manifeste est stocké dans l’un mais pas dans l’autre, ou lorsque le même nom de dépôt est utilisé avec une casse ou des tags différents. Vérifiez la cohérence : vérifiez docker tag et assurez-vous que le nom du dépôt correspond exactement. Vérifiez également si le registre est derrière un équilibreur de charge qui route vers différentes instances sans stockage partagé.
3. « blob upload unknown » pendant un push
Cette erreur suggère que le registre ne peut pas trouver la session de téléversement, peut-être parce que la session a expiré ou que le registre a redémarré en plein téléversement. Augmentez les délais d’attente http dans la configuration ou assurez-vous que le client réessaie. Une correction typique consiste à définir des valeurs plus grandes pour la section http :
http:
addr: :5000
headers:
X-Content-Type-Options: [nosniff]
timeouts:
read: 900
write: 900
idle: 900
Redémarrez et réessayez le push.
4. « denied: requested access to the resource is denied »
Il s’agit d’une erreur d’authentification ou d’autorisation. Vérifiez :
- Si vous êtes connecté (
docker login). - Si les informations d’identification sont correctes (fichier htpasswd).
- Si l’utilisateur a la permission si vous utilisez une authentification plus complexe basée sur des jetons.
Utilisez curl -u username:password https://registry.example.com/v2/ pour tester. Si les informations d’identification sont incorrectes, le serveur renvoie 401. Vérifiez que le fichier htpasswd est correctement monté et que l’utilisateur existe : docker exec <conteneur-registre> htpasswd -B -C 10 /auth/htpasswd username (note : htpasswd peut ne pas être dans l’image ; vous pouvez utiliser registry:2 avec htpasswd installé séparément ou utiliser un outil sur l’hôte).
5. Espace disque insuffisant sur l’hôte du registre
Il s’agit d’une défaillance silencieuse : les pushes peuvent se bloquer ou échouer avec io timeout. Vérifiez l’utilisation du disque : df -h sur l’hôte. Si le répertoire de stockage du registre est sur une partition pleine, vous devez libérer de l’espace. Souvent, le coupable est d’anciens blobs non référencés. Exécutez le ramasse-miettes (voir section Stockage). Envisagez également de mettre en place une surveillance et des alertes pour l’utilisation du disque.
Liste de contrôle opérationnelle
Utilisez cette liste de contrôle pour dépanner et maintenir systématiquement votre registre Docker. Elle suit le cycle observer-modifier-vérifier.
| Étape | Action | Commande/Exemple | Résultat attendu | Responsable | Fréquence |
|---|---|---|---|---|---|
| 1 | Vérifier l’état du conteneur de registre | docker ps -f name=registry | Conteneur en cours d’exécution, sain | Ingénieur DevOps | Quotidien (automatisé) |
| 2 | Vérifier les journaux pour les erreurs | docker logs registry --since 1h | Aucune erreur critique | Ingénieur DevOps | Réponse aux incidents |
| 3 | Vérifier le montage de stockage | docker inspect registry --format '{{ .Mounts }}' | Montage bind ou volume correct, RW | Ingénieur DevOps | Mensuel |
| 4 | Tester la santé de l’API | curl -f http://localhost:5000/v2/ | HTTP 200 | Système de surveillance | Toutes les 5 minutes |
| 5 | Test push/pull d’une image | docker push/pull | Succès | Pipeline CI/CD | Après chaque changement |
| 6 | Vérifier l’utilisation du disque | df -h /var/lib/registry | En dessous de 80 % de capacité | Administrateur infrastructure | Hebdomadaire |
| 7 | Examiner la configuration d’authentification | cat /etc/docker/registry/config.yml | Pas de secrets codés en dur, chemins corrects | Agent de sécurité | Trimestriel |
| 8 | Exécuter le ramasse-miettes (si nécessaire) | docker exec registry bin/registry garbage-collect /etc/docker/registry/config.yml | Blobs supprimés, espace libéré | Ingénieur DevOps | Selon besoin |
| 9 | Sauvegarder les données du registre | tar -czf registry-backup-$(date +%F).tar.gz /var/lib/registry | Fichier de sauvegarde créé, testé | Ingénieur DevOps | Quotidien |
| 10 | Examiner les mises à jour de sécurité | docker pull registry:2 | Dernière image stable | Ingénieur DevOps | Mensuel |
Chaque élément a un seul responsable (pas une équipe) pour garantir la responsabilisation. Revisitez cette liste de contrôle trimestriellement ou lorsque la version du registre change.
Stockage et intégrité des données
Les problèmes de stockage sont parmi les plus courants et les plus dangereux. Le registre stocke les images sous forme de blobs (couches) et de manifestes. Si le stockage devient corrompu ou mal configuré, vous pouvez perdre des données.
Système de fichiers vs stockage d’objets : Le défaut est un système de fichiers local, mais pour la production, le stockage d’objets comme S3, GCS ou Azure Blob est recommandé pour la durabilité et l’évolutivité. Mélanger les types de stockage ou changer de backend de stockage sans migrer les données conduit à des erreurs « manifest unknown ».
Permissions : Le processus du registre s’exécute en tant qu’utilisateur root dans le conteneur par défaut, mais si vous l’exécutez avec un utilisateur non-root, assurez-vous que le répertoire de stockage est accessible en écriture. Une erreur courante est open /var/lib/registry/docker/registry/v2/repositories: permission denied dans les journaux. Corrigez-la en changeant la propriété sur le répertoire hôte : sudo chown -R 1000:1000 /opt/registry/data (en supposant que l’UID 1000 est l’utilisateur du conteneur). Ajustez l’UID/GID selon votre configuration.
Ramasse-miettes : Au fil du temps, surtout si vous supprimez des images ou écrasez des tags, des blobs non référencés s’accumulent. Exécutez le ramasse-miettes périodiquement. Le registre doit être en mode lecture seule pendant la collecte pour éviter la corruption. Voici une procédure sûre :
- Arrêtez le conteneur du registre ou mettez-le en mode lecture seule. Vous pouvez le faire en définissant
storage.maintenance.readonly.enabled: truedans la configuration et en redémarrant, ou simplement arrêter le conteneur. - Exécutez le ramasse-miettes à partir de la même image, en montant la même configuration et les données :
docker run --rm -v /opt/registry/data:/var/lib/registry -v /opt/registry/config.yml:/etc/docker/registry/config.yml registry:2 bin/registry garbage-collect /etc/docker/registry/config.yml
La sortie attendue liste les blobs marqués pour suppression.
- Redémarrez le registre normalement.
Sauvegarde : Sauvegardez toujours les données du registre avant d’exécuter le ramasse-miettes ou d’apporter des modifications importantes. La sauvegarde doit inclure le répertoire de stockage et le fichier de configuration. Testez régulièrement les restaurations.
Sécurité et contrôle d’accès
Un registre mal configuré peut exposer des images privées ou permettre des pushes non autorisés. Voici les principales erreurs et leurs corrections :
- Fonctionnement sans TLS : En production, utilisez toujours HTTPS. Un registre sans TLS nécessite que les clients Docker soient configurés avec
insecure-registries, ce qui est un risque de sécurité. Utilisez un proxy inverse comme Nginx ou Caddy pour terminer TLS et transférer vers le registre. Une configuration Nginx de base :
server {
listen 443 ssl;
server_name registry.example.com;
ssl_certificate /etc/ssl/certs/registry.crt;
ssl_certificate_key /etc/ssl/private/registry.key;
location / {
proxy_pass http://127.0.0.1:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
- Authentification faible : Si vous utilisez htpasswd, générez des hachages bcrypt. Évitez SHA ou MD5. Utilisez
htpasswd -B -C 12pour un coût élevé. Ne stockez jamais de mots de passe en clair. - Exposer le registre à Internet sans authentification : Cela permet à quiconque de pousser et de tirer. Activez toujours au moins l’authentification de base, et envisagez une authentification basée sur des jetons pour un contrôle plus granulaire.
- Utiliser des secrets par défaut dans la configuration : Évitez de coder en dur des jetons ; utilisez des variables d’environnement ou des montages de secrets.
Pièges courants et comment les éviter
Voici les erreurs fréquentes qui conduisent à des défaillances du registre :
- Ne pas persister le stockage - Utiliser le système de fichiers par défaut du conteneur et perdre ensuite toutes les images lorsque le conteneur est recréé. Montez toujours un volume pour
/var/lib/registryet assurez-vous qu’il est sauvegardé. - Mal configurer le chemin
rootdirectory- Définir un chemin dans la configuration qui ne correspond pas au point de montage, ce qui fait que les données sont écrites dans un stockage éphémère. - Ignorer les messages de journal - Les journaux du registre sont détaillés et indiquent souvent l’erreur exacte. Réglez le niveau de journalisation sur
infooudebuget vérifiez les journaux avant de deviner. - Changer de backend de stockage sans migration - Passer du système de fichiers à S3 et s’attendre à ce que les anciennes images soient disponibles. Vous devez migrer les données ou repartir de zéro.
- Exécuter incorrectement le ramasse-miettes - Le faire pendant que le registre est accessible en écriture ou utiliser une configuration différente peut corrompre les données. Suivez toujours la procédure sûre.
- Ne pas surveiller le disque et la santé - Un disque plein peut silencieusement casser les pushes. Mettez en place une surveillance avec Prometheus et alertez en cas d’utilisation élevée.
- Négliger les mises à jour de sécurité - L’image du registre peut avoir des vulnérabilités. Mettez régulièrement à jour vers la dernière version de correctif.
Conclusion
Les erreurs du registre Docker peuvent être frustrantes, mais avec une approche systématique, elles sont gérables. Commencez par comprendre votre environnement, apportez de petits changements réversibles et vérifiez après chaque étape. Utilisez les commandes et les exemples de ce guide pour diagnostiquer et corriger les problèmes courants. Gardez votre configuration sous contrôle de version, surveillez le registre et pratiquez la reprise après sinistre. En suivant ces pratiques, vous maintiendrez un registre d’images de conteneurs fiable et sécurisé qui soutient votre flux de travail de développement.
Comme prochaine étape, choisissez une vérification à faible risque de ce guide, comme tester l’endpoint de santé ou pousser une image de test. Enregistrez l’état actuel, exécutez la vérification et comparez le résultat avec la sortie attendue. Ensuite, examinez votre stratégie de stockage et de sauvegarde pour vous assurer que votre registre peut survivre aux défaillances.