Registries

Distribution

Implémentation de référence de l'OCI Distribution Spec (ex docker/distribution). Registry minimaliste, socle de Docker Hub et Harbor. Backends S3, GCS, Azure. Apache 2.0.

Distribution (anciennement docker/distribution) est l'implémentation de référence de la spécification OCI Distribution. C'est un registry de conteneurs minimaliste : il stocke et distribue des images OCI/Docker, sans interface web, sans RBAC avancé, sans scan de vulnérabilités. C'est le socle sur lequel sont construits Docker Hub, Harbor, et la plupart des registries du marché.

À utiliser quand les besoins sont simples : un registry privé pour une équipe, un registry interne pour un cluster isolé, ou comme brique de base dans une architecture custom.

Idéal pour : registry privé léger sans infrastructure complexe, environnements air-gapped, laboratoires et CI/CD internes, socle d'une solution custom.


Informations essentielles

Origine : Docker → CNCF (distribution/distribution)  ·  Licence : Apache 2.0  ·  Architectures : x86_64, ARM64, ARM

Liens : GitHub  ·  Releases  ·  Image Docker

Support : Projet actif. La v3.x est la branche stable depuis avril 2026 (v3.0.0 GA), avec nettoyage du code legacy. L'image Docker registry:2 (v2.8.x) reste très répandue en production.

Backends de stockage

BackendUsage
filesystemStockage local (défaut)
S3 / S3-compatible (MinIO)Cloud ou on-prem objet
Google Cloud StorageGCP
Azure Blob StorageAzure
SwiftOpenStack

Démarrage rapide (Docker)

# Registry local sur le port 5000 (sans TLS, dev uniquement)
docker run -d \
  --name registry \
  -p 5000:5000 \
  -v /data/registry:/var/lib/registry \
  registry:2

# Pousser une image
docker tag nginx:alpine localhost:5000/nginx:alpine
docker push localhost:5000/nginx:alpine

# Vérifier via l'API
curl http://localhost:5000/v2/_catalog
# {"repositories":["nginx"]}

curl http://localhost:5000/v2/nginx/tags/list
# {"name":"nginx","tags":["alpine"]}

Sans TLS, Docker refuse de pousser vers des registries non-localhost par défaut. Ajouter le registry en insecure-registries dans /etc/docker/daemon.json pour les IPs non-locales (voir Configuration avancée).


Déploiement avec TLS et authentification

1. Générer les credentials htpasswd

# Créer un fichier htpasswd (bcrypt obligatoire)
docker run --rm \
  --entrypoint htpasswd \
  httpd:2 -Bbn monuser monpassword > auth/htpasswd

2. Configurer avec TLS

# Structure
mkdir -p /data/registry/{data,auth,certs}

# Certificat TLS (Let's Encrypt ou self-signed)
# Placer registry.crt et registry.key dans /data/registry/certs/

# Lancer avec TLS + auth
docker run -d \
  --name registry \
  -p 443:443 \
  -v /data/registry/data:/var/lib/registry \
  -v /data/registry/auth:/auth \
  -v /data/registry/certs:/certs \
  -e REGISTRY_HTTP_ADDR=0.0.0.0:443 \
  -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/registry.crt \
  -e REGISTRY_HTTP_TLS_KEY=/certs/registry.key \
  -e REGISTRY_AUTH=htpasswd \
  -e REGISTRY_AUTH_HTPASSWD_REALM="Registry Realm" \
  -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
  registry:2

Configuration via fichier YAML

Pour les configurations complexes, un fichier config.yml est plus lisible que les variables d'environnement.

# /etc/distribution/config.yml
version: 0.1

log:
  level: info

storage:
  filesystem:
    rootdirectory: /var/lib/registry
  # Ou backend S3 :
  # s3:
  #   region: eu-west-1
  #   bucket: mon-registry
  #   encrypt: true
  #   secure: true
  delete:
    enabled: true   # Permet la suppression d'images via API

http:
  addr: 0.0.0.0:5000
  tls:
    certificate: /certs/registry.crt
    key: /certs/registry.key

auth:
  htpasswd:
    realm: "Registry"
    path: /auth/htpasswd
docker run -d \
  --name registry \
  -p 5000:5000 \
  -v /etc/distribution/config.yml:/etc/distribution/config.yml \
  -v /var/lib/registry:/var/lib/registry \
  registry:2 /etc/distribution/config.yml

Backend S3 (MinIO ou AWS S3)

storage:
  s3:
    region: us-east-1
    bucket: mon-registry-bucket
    regionendpoint: http://minio.example.com:9000   # Omit pour AWS S3
    accesskey: AKIAIOSFODNN7EXAMPLE
    secretkey: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
    encrypt: false
    secure: true
    v4auth: true
  delete:
    enabled: true

Déploiement sur Kubernetes

# registry-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: registry
  namespace: registry
spec:
  replicas: 1
  selector:
    matchLabels:
      app: registry
  template:
    spec:
      containers:
      - name: registry
        image: registry:2
        ports:
        - containerPort: 5000
        env:
        - name: REGISTRY_STORAGE_DELETE_ENABLED
          value: "true"
        - name: REGISTRY_AUTH
          value: htpasswd
        - name: REGISTRY_AUTH_HTPASSWD_PATH
          value: /auth/htpasswd
        - name: REGISTRY_AUTH_HTPASSWD_REALM
          value: "Registry"
        volumeMounts:
        - name: registry-data
          mountPath: /var/lib/registry
        - name: auth
          mountPath: /auth
      volumes:
      - name: registry-data
        persistentVolumeClaim:
          claimName: registry-pvc
      - name: auth
        secret:
          secretName: registry-auth
---
apiVersion: v1
kind: Service
metadata:
  name: registry
  namespace: registry
spec:
  selector:
    app: registry
  ports:
  - port: 5000

Registries insecure (sans TLS)

Pour autoriser Docker/containerd à utiliser un registry sans TLS ou avec un certificat self-signed :

// /etc/docker/daemon.json
{
  "insecure-registries": ["192.168.1.100:5000", "registry.interne:5000"]
}
# /etc/containerd/config.toml - pour Kubernetes
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."192.168.1.100:5000"]
  endpoint = ["http://192.168.1.100:5000"]

[plugins."io.containerd.grpc.v1.cri".registry.configs."192.168.1.100:5000".tls]
  insecure_skip_verify = true

Garbage collection

Distribution ne supprime pas automatiquement les layers orphelins. La garbage collection doit être lancée manuellement.

# Exécuter la GC (en mode dry-run d'abord)
docker exec registry registry garbage-collect --dry-run /etc/distribution/config.yml

# GC effective
docker exec registry registry garbage-collect /etc/distribution/config.yml

# Note : arrêter les writes pendant la GC pour éviter la corruption
docker stop registry
docker run --rm \
  -v /data/registry/data:/var/lib/registry \
  registry:2 garbage-collect /etc/distribution/config.yml
docker start registry

API OCI Distribution Spec

Distribution implémente l'API standard, utilisable directement :

# Lister les repositories
curl -u user:pass https://registry.example.com/v2/_catalog

# Lister les tags d'une image
curl -u user:pass https://registry.example.com/v2/<image>/tags/list

# Récupérer le manifest d'une image
curl -u user:pass \
  -H "Accept: application/vnd.oci.image.manifest.v1+json" \
  https://registry.example.com/v2/<image>/manifests/<tag>

# Supprimer un tag (DELETE, nécessite storage.delete.enabled: true)
DIGEST=$(curl -I -u user:pass \
  -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
  https://registry.example.com/v2/<image>/manifests/<tag> \
  | grep -i docker-content-digest | awk '{print $2}' | tr -d '\r')

curl -u user:pass -X DELETE \
  https://registry.example.com/v2/<image>/manifests/$DIGEST

Mise à jour

# Arrêter et remplacer le conteneur (les données sont dans le volume)
docker stop registry
docker rm registry
docker pull registry:2
docker run -d --name registry [... mêmes options ...]

Commandes utiles

# Vérifier que le registry répond
curl https://registry.example.com/v2/

# Lister les images
curl -u user:pass https://registry.example.com/v2/_catalog

# Lister les tags
curl -u user:pass https://registry.example.com/v2/<image>/tags/list

# Inspecter les logs
docker logs registry -f

# Espace utilisé
du -sh /data/registry/data

Ressources

Newsletter · 2 000+ abonnés

Reste au courant de ce qui bouge en prod

RudeOps veille devops hebdo, droit au but.

Gratuit · Sans spam · Désinscription en un clic