Docker · Registry · Image-Versionierung · DevOps
Docker Registry aufsetzen und Images versionieren
von der privaten Registry bis zum Image-Lifecycle

Eine unkontrollierte Flut aus latest-Tags und anonymen Docker-Hub-Pulls gefährdet jede Produktionsumgebung. Wer eine private Docker Registry betreibt, sinnvolle Image-Versionen einführt und Retention-Policies definiert, schafft nachvollziehbare, reproduzierbare Builds und reduziert Ausfallrisiken erheblich.

12 Min. Lesezeit Registry · Tags · Semantic Versioning · Harbor · GHCR Docker Engine 26+ · Compose v2

1. Warum eine eigene Docker Registry sinnvoll ist

Wer alle Images direkt von Docker Hub bezieht, akzeptiert mehrere versteckte Risiken gleichzeitig. Docker Hub drosselt anonyme Pulls auf 100 Requests pro sechs Stunden – in größeren Teams oder CI-Umgebungen mit vielen parallelen Builds führt das zu zufälligen Buildfehlern, die schwer zu diagnostizieren sind. Eine private Docker Registry beseitigt diese Abhängigkeit vollständig, weil alle Images lokal vorgehalten werden und jeder Pull innerhalb der eigenen Infrastruktur stattfindet.

Darüber hinaus bietet eine eigene Docker Registry volle Kontrolle darüber, welche Images im Umlauf sind. In regulierten Umgebungen – etwa mit Datenschutzanforderungen oder Compliance-Vorgaben – dürfen keine beliebigen Base-Images aus dem Internet verwendet werden. Die Registry wird zum Single Point of Trust: Jedes Image, das in die Produktion gelangt, muss aus dem eigenen Repository stammen, ist geprüft und versioniert. Das macht Audits deutlich einfacher und Sicherheitslücken besser nachverfolgbar.

2. Distribution Registry in fünf Minuten starten

Die offizielle Distribution Registry (früher bekannt als Docker Registry v2) ist ein schlankes Go-Programm, das als Docker Image auf Docker Hub verfügbar ist. Sie benötigt keine Datenbank, speichert alle Image-Layer als Dateien und ist damit trivial zu betreiben. Für interne Entwicklungsumgebungen reicht ein einziger docker compose up-Befehl, um eine funktionsfähige Docker Registry zu starten, die sofort für Push- und Pull-Operationen bereit ist.

Die Registry horcht standardmäßig auf Port 5000. Um ein Image dorthin zu pushen, muss der Imagename den Registry-Host als Präfix enthalten: registry.local:5000/meinprojekt/api:1.2.0. Docker unterscheidet Registries anhand dieses Präfixes – fehlt es, nimmt Docker Hub an. Mit einem lokalen DNS-Eintrag oder einem Eintrag in /etc/hosts lässt sich ein sprechender Hostname wie registry.local vergeben, statt immer die IP-Adresse zu tippen. Das spart Tipp-Fehler und macht die Konfiguration lesbarer.


# compose.registry.yml — Local Docker Registry with persistent storage
services:
  registry:
    image: registry:2.8
    container_name: docker-registry
    restart: unless-stopped
    ports:
      - "5000:5000"
    environment:
      # Store images in a named volume for persistence
      REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /var/lib/registry
      # Enable deletion API (needed for garbage collection later)
      REGISTRY_STORAGE_DELETE_ENABLED: "true"
      # Log level: debug, info, warn, error
      REGISTRY_LOG_LEVEL: info
    volumes:
      - registry-data:/var/lib/registry
      - ./registry/config.yml:/etc/docker/registry/config.yml:ro

volumes:
  registry-data:
    driver: local

# Push an image to the local registry:
# docker tag myapp:latest registry.local:5000/myapp:1.0.0
# docker push registry.local:5000/myapp:1.0.0
# List repositories via API:
# curl http://registry.local:5000/v2/_catalog

Die Registry-API folgt der OCI Distribution Specification und ist vollständig dokumentiert. Mit einem einfachen curl-Aufruf lassen sich alle vorhandenen Repositories auflisten und die verfügbaren Tags eines Images abfragen. Das ist nützlich für Monitoring-Skripte, die prüfen, ob ein bestimmtes Image in der erwarteten Version vorhanden ist, bevor ein Deployment gestartet wird.

3. TLS und Basic-Auth absichern

Eine Docker Registry ohne TLS akzeptiert Docker nur als explizit konfigurierte "insecure registry". Das ist für Laptops und lokale Tests akzeptabel, für geteilte Infrastruktur aber ein ernsthaftes Problem: Credentials und Image-Layer werden im Klartext übertragen. TLS lässt sich entweder direkt in der Registry konfigurieren oder – was flexibler ist – durch einen vorgelagerten Reverse-Proxy wie Nginx oder Traefik bereitstellen. Dieser Ansatz hat den Vorteil, dass die Registry selbst einfach konfiguriert bleibt und der Proxy TLS-Termination für mehrere Services übernehmen kann.

Basic-Auth für die Registry wird ebenfalls am bequemsten im Proxy konfiguriert. Das htpasswd-Format kennt Docker nativ: Mit htpasswd -Bc /auth/htpasswd username wird ein Benutzer angelegt, die Datei in den Proxy-Container gemountet. Für feingranularere Zugriffssteuerung – bestimmte Benutzer dürfen nur bestimmte Repositories lesen – ist die offizielle Registry etwas eingeschränkt. Harbor oder die GitHub Container Registry bieten hier deutlich mehr Möglichkeiten. Für Teams ab fünf Personen lohnt der Wechsel zu einer vollständigen Registry-Plattform meistens mehr als das Selbst-Konfigurieren von Autorisierungs-Plugins.


# nginx-registry.conf — TLS termination and Basic-Auth for Docker Registry
# Place in /etc/nginx/conf.d/registry.conf

server {
    listen 443 ssl http2;
    server_name registry.example.com;

    # TLS certificates (use mkcert for local dev or Let's Encrypt for production)
    ssl_certificate     /etc/nginx/certs/registry.crt;
    ssl_certificate_key /etc/nginx/certs/registry.key;

    # Increase max body size — Docker layers can be several hundred MB
    client_max_body_size 2000m;

    # Basic-Auth protection
    auth_basic           "Docker Registry";
    auth_basic_user_file /etc/nginx/auth/htpasswd;

    location / {
        # Proxy to the registry container (must be on same Docker network)
        proxy_pass          http://registry:5000;
        proxy_set_header    Host              $host;
        proxy_set_header    X-Real-IP         $remote_addr;
        proxy_set_header    X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header    X-Forwarded-Proto $scheme;

        # Chunked transfer for large uploads
        proxy_request_buffering off;
        proxy_read_timeout      600;
    }
}

4. Sinnvolle Tags und Semantic Versioning

Das latest-Tag ist in der Produktion ein Anti-Pattern. Es gibt keine Auskunft darüber, wann das Image gebaut wurde, welchen Code-Stand es enthält oder ob es sich seit dem letzten Deployment verändert hat. Ein Deployment mit latest ist nicht reproduzierbar, weil ein späterer Pull eine andere Version liefern kann als der ursprüngliche. Die Lösung ist konsequentes Image-Versionieren nach Semantic Versioning: 1.2.3 für stabile Releases, 1.2.3-rc.1 für Release Candidates und 1.2.3-dev.abc1234 für Feature-Branches.

Zusätzlich zu Semantic-Version-Tags empfehlen sich unveränderliche Content-Hash-Tags auf Basis des Git-Commits: sha-abc1234. Dieses Tag verändert sich nie und identifiziert exakt, welchen Commit das Image enthält. In CI-Pipelines baut man üblicherweise beides gleichzeitig: ein sprechendes Versions-Tag und ein Git-SHA-Tag. Das Versions-Tag zeigt auf das aktuellste Image einer Version, das SHA-Tag macht das Image dauerhaft über seinen Ursprung auffindbar. Kubernetes und andere Orchestratoren sollten immer SHA-Tags verwenden, um versehentliches Überschreiben bei Rollouts zu verhindern.

5. Images in der CI-Pipeline taggen und pushen

In modernen CI/CD-Systemen wie GitHub Actions, GitLab CI oder Drone ist das Bauen und Pushen von Docker Images eine Standard-Operation. Die Herausforderung liegt im konsequenten Tagging: Das Image soll sowohl mit einem sprechenden Versions-Tag als auch mit dem Git-SHA getaggt werden. Docker ermöglicht es, einem Image beliebig viele Tags zu geben – alle zeigen auf denselben Layer-Stack und verursachen keinen zusätzlichen Speicher in der Registry. Das Taggen in der CI-Pipeline kostet also nichts außer ein paar Millisekunden für die Push-Operationen.

Eine wichtige Praxis ist das Multi-Platform-Building mit docker buildx. Wer Images sowohl für linux/amd64 als auch für linux/arm64 benötigt – etwa weil Entwickler auf Apple-Silicon-Macs arbeiten und die Produktion auf x86-Servern läuft – baut beide Varianten in einer einzigen Pipeline und pusht sie als Multi-Arch-Manifest. Der Pull-Client bekommt dann automatisch das passende Image für seine Architektur geliefert, ohne dass eine Unterscheidung im Imagenahmen nötig ist.


#!/usr/bin/env bash
# ci-build-push.sh — Build, tag and push Docker image in CI
set -euo pipefail

# Read version from git or environment variable
GIT_SHA="$(git rev-parse --short HEAD)"
GIT_TAG="${CI_TAG:-}"
REGISTRY="${REGISTRY:-registry.example.com}"
IMAGE_NAME="${IMAGE_NAME:-myapp}"

# Determine version tag
if [[ -n "$GIT_TAG" ]]; then
  VERSION_TAG="$GIT_TAG"
else
  # Feature branch: use branch name + sha
  BRANCH="${CI_BRANCH:-$(git rev-parse --abbrev-ref HEAD)}"
  SAFE_BRANCH="${BRANCH//\//-}"
  VERSION_TAG="${SAFE_BRANCH}-${GIT_SHA}"
fi

FULL_IMAGE="${REGISTRY}/${IMAGE_NAME}"

# Build multi-platform image with buildx
docker buildx build \
  --platform linux/amd64,linux/arm64 \
  --tag "${FULL_IMAGE}:${VERSION_TAG}" \
  --tag "${FULL_IMAGE}:sha-${GIT_SHA}" \
  --cache-from "type=registry,ref=${FULL_IMAGE}:buildcache" \
  --cache-to   "type=registry,ref=${FULL_IMAGE}:buildcache,mode=max" \
  --push \
  .

echo "Pushed: ${FULL_IMAGE}:${VERSION_TAG}"
echo "Pushed: ${FULL_IMAGE}:sha-${GIT_SHA}"

6. Image-Retention und Garbage Collection

Ohne aktives Management wächst eine Docker Registry unbegrenzt. Jeder Build fügt neue Layer hinzu, alte Tags werden selten manuell gelöscht, und nach einem Jahr hat die Registry mehrere Hundert Gigabyte belegt. Image-Retention-Policies definieren, wie viele Versionen eines Images behalten werden und ab wann alte Tags gelöscht werden dürfen. Die Distribution Registry selbst bietet keine eingebauten Retention-Policies – das Löschen von Tags muss über die API oder externe Tools wie docker-registry-pruner gesteuert werden.

Wichtig: In der Distribution Registry sind gelöschte Tags zunächst nur als Manifest-Einträge entfernt; die eigentlichen Layer-Daten (Blobs) bleiben auf der Festplatte. Erst die Garbage Collection – registry garbage-collect /etc/docker/registry/config.yml – entfernt nicht mehr referenzierte Blobs und gibt Speicher frei. Dieser Prozess läuft idealerweise nachts als Cronjob und sollte während der Laufzeit im Read-Only-Modus ausgeführt werden, um Datenkonsistenz zu wahren. Harbor automatisiert diese Schritte vollständig und bietet eine Web-UI zur Konfiguration von Retention-Regeln.

7. Harbor als Enterprise-Alternative

Harbor ist eine CNCF-Projekt-graduierte Open-Source-Registry-Plattform, die weit über die Funktionen der Distribution Registry hinausgeht. Sie bietet rollenbasierte Zugriffssteuerung auf Projekt-Ebene, integriertes Vulnerability-Scanning mit Trivy oder Clair, Image-Signierung mit Notary, automatische Retention-Policies und eine vollständige Web-Oberfläche. Für Teams, die mehrere Projekte mit unterschiedlichen Zugriffsberechtigungen verwalten, ist Harbor die überzeugendste Self-Hosted-Option.

Der Betrieb von Harbor erfordert mehr Infrastruktur als die schlichte Distribution Registry: Harbor benötigt eine PostgreSQL-Datenbank, einen Redis-Cache und mehrere eigene Microservices. Die offizielle harbor-installer-Distribution bringt ein Compose-Setup mit, das alle Komponenten zusammenfasst. Für Produktionsumgebungen empfiehlt sich ein Kubernetes-Deployment per Helm-Chart, das Rolling Updates ohne Downtime ermöglicht. Das Vulnerability-Scanning läuft asynchron nach jedem Push und blockiert Deployments von Images mit kritischen CVEs, wenn die entsprechende Policy aktiv ist.

8. GitHub Container Registry als leichtgewichtige Option

Die GitHub Container Registry (GHCR) ist für Teams, die GitHub für Source-Control und CI verwenden, die naheliegendste private Docker Registry-Alternative ohne eigenen Infrastrukturaufwand. Images werden unter ghcr.io/organisation/imagename:tag gespeichert und teilen die Zugriffsberechtigungen des GitHub-Repositories. Ein Repository-Maintainer kann automatisch Images pushen, während externe Contributor nur Pull-Zugriff haben – ohne zusätzliche Konfiguration.

GHCR unterstützt OCI-Artifacts, was bedeutet, dass nicht nur Docker Images, sondern auch Helm-Charts, WASM-Module und andere Artefakte in derselben Registry gespeichert werden können. Für Open-Source-Projekte sind public Packages kostenlos, für private Packages ist Speicherplatz im GitHub-Plan enthalten. Der einzige relevante Nachteil gegenüber einer selbst gehosteten Registry ist die Abhängigkeit von der GitHub-Infrastruktur – bei GitHub-Ausfällen sind auch die eigenen Images nicht erreichbar.

9. Registries im Vergleich

Die Wahl der richtigen Docker Registry hängt von Teamgröße, Compliance-Anforderungen und vorhandener Infrastruktur ab. Es gibt keine universell beste Lösung – jede Option hat klare Stärken und Einschränkungen.

Registry Hosting Zugriffssteuerung Besonderheit
Distribution Registry Self-Hosted Basic-Auth via Proxy Minimal, kein UI, kein Scanning
Harbor Self-Hosted RBAC, OIDC, LDAP Scanning, Signierung, Retention-UI
GHCR GitHub-Managed GitHub-Berechtigungen OCI-Artifacts, kein Infrastruktur-Aufwand
AWS ECR AWS-Managed IAM-Policies Native ECS/EKS-Integration, Lifecycle-Policies
Docker Hub Docker-Managed Teams, Organisationen Pull-Rate-Limit bei anonymen Requests

Für Einzelentwickler und kleine Teams ohne Compliance-Anforderungen ist GHCR die einfachste Wahl, sofern GitHub bereits genutzt wird. Mittlere Teams mit eigenem Server und dem Wunsch nach voller Kontrolle greifen zu Harbor. Wer bereits in AWS-Infrastruktur investiert hat, sollte ECR wegen der nativen IAM-Integration bevorzugen. Die Distribution Registry eignet sich hauptsächlich als Cache oder für vollständig airgapped Umgebungen ohne Internetzugang.

Mironsoft

Docker-Infrastruktur, Registry-Setup und CI/CD-Integration

Eigene Docker Registry aufsetzen und Images sauber versionieren?

Wir richten private Registries ein, definieren Tagging-Strategien, integrieren Vulnerability-Scanning und automatisieren den gesamten Image-Lifecycle in eurer CI/CD-Pipeline.

Registry-Setup

Distribution Registry, Harbor oder GHCR – je nach Anforderung aufsetzen und absichern

Tagging-Strategie

Semantic Versioning und Git-SHA-Tags konsequent in alle CI-Pipelines integrieren

Lifecycle-Management

Retention-Policies, Garbage Collection und Monitoring für die Registry automatisieren

10. Zusammenfassung

Eine eigene Docker Registry löst drei Kernprobleme gleichzeitig: Rate-Limits von Docker Hub entfallen, alle Images sind intern versioniert und nachvollziehbar, und Compliance-Anforderungen hinsichtlich Datenhaltung lassen sich erfüllen. Die Distribution Registry ist der schnellste Einstieg, Harbor bietet Enterprise-Features für größere Teams, GHCR ist die reibungsloseste Option für GitHub-Nutzer. Die Wahl der Plattform ist zweitrangig – wichtiger ist die konsequente Einführung einer Tagging-Strategie.

Semantic-Version-Tags kombiniert mit Git-SHA-Tags ergeben eine vollständig nachvollziehbare Image-Historie. Jedes Deployment lässt sich auf einen konkreten Git-Commit zurückführen. Garbage Collection und Retention-Policies verhindern unkontrolliertes Registry-Wachstum. Mit diesen drei Bausteinen – sinnvolle Registry, klare Tags, aktives Lifecycle-Management – ist die Docker Registry kein Flaschenhals mehr, sondern ein zuverlässiges Fundament der Deployment-Pipeline.

Docker Registry und Image-Versionierung — Das Wichtigste auf einen Blick

Registry-Wahl

Distribution Registry für minimale Setups, Harbor für RBAC und Scanning, GHCR für GitHub-Teams, ECR für AWS-native Stacks.

Tagging-Strategie

Kein latest in der Produktion. Semantic Versioning (1.2.3) kombiniert mit Git-SHA-Tags (sha-abc1234) für vollständige Nachvollziehbarkeit.

Absicherung

TLS per Reverse-Proxy, Basic-Auth oder OIDC. Keine Registry ohne Authentifizierung im Netzwerk exponieren.

Lifecycle

Retention-Policies und Garbage Collection als Cronjob. Ohne aktives Management wächst die Registry unkontrolliert auf mehrere Hundert GB.

11. FAQ: Docker Registry aufsetzen und Images versionieren

1Warum kein latest-Tag in der Produktion?
latest gibt keinen Code-Stand an und kann bei erneutem Pull eine andere Version liefern. Semantic Versioning und Git-SHA-Tags machen den Image-Stand eindeutig und Deployments reproduzierbar.
2Was kostet eine private Docker Registry?
Distribution Registry ist kostenlos und Open Source – nur Server und Speicher kosten Geld. GHCR ist für GitHub-Nutzer im Plan enthalten. Harbor ebenfalls Open Source, benötigt aber mehr Ressourcen.
3Mehrere Tags auf dasselbe Image setzen?
Ja, ohne zusätzlichen Speicherverbrauch. Mehrere Tags können auf denselben Image-Digest zeigen – 1.2.3, latest-stable und sha-abc1234 können gleichzeitig aktiv sein.
4Wie lösche ich alte Images?
Manifest über die Registry-API löschen, dann registry garbage-collect ausführen. Der Storage-Delete-Mode muss in der Registry-Konfiguration aktiviert sein.
5Docker Hub vs. private Registry?
Docker Hub hat Rate-Limits für anonyme Pulls. Eine private Registry hat keine Rate-Limits, liegt in der eigenen Infrastruktur und unterliegt keinen externen Datenschutzfragen.
6Wann lohnt sich Harbor?
Ab ca. fünf Entwicklern oder bei Compliance-Anforderungen. Harbor bietet RBAC, Scanning, Signierung und automatische Retention-Policies – deutlich mehr als die Distribution Registry.
7TLS für die Registry Pflicht?
Ja, für jede Registry, auf die mehrere Rechner zugreifen. Docker akzeptiert HTTP-Registries nur explizit als insecure-registries – nur für rein lokale Setups akzeptabel.
8Wie funktionieren Multi-Arch-Images?
docker buildx build mit --platform linux/amd64,linux/arm64 pusht ein OCI-Manifest-List. Der Client bekommt automatisch die zur Architektur passende Variante geliefert.
9Was ist Garbage Collection?
Beim Tag-Löschen bleiben Layer-Daten auf der Festplatte. registry garbage-collect entfernt nicht mehr referenzierte Blobs und gibt Speicher frei – am besten nachts als Cronjob.
10Private Registry in GitHub Actions integrieren?
docker/login-action mit Registry-Credentials als GitHub Secrets. Für GHCR reicht der automatische GITHUB_TOKEN. Danach funktionieren docker build und docker push direkt auf die private Registry.