Betrieb einer privaten Docker-Registry

Betrieb einer privaten Docker-Registry

Betrieb einer privaten Docker-Registry

Docker-Images können in eine zentrale Registry hochgeladen und von dort aus von sämtlichen Nutzern heruntergeladen werden. Die größte öffentliche Image-Registry ist Docker Hub. Jeder kann eine solche Registry aber auch in einem privaten Netzwerk betreiben, um Images nur Netzwerk-intern verfügbar zu machen.

Warum?

Die Motivationen hinter einer privaten Registry sind sicherlich vielfältig. Ein Grund wäre beispielsweise, dass man nicht unbedingt jedes Image auf Docker Hub aller Welt zur Verfügung stellen möchte, zumal für kostenlose Accounts aktuell nur ein privates Repository möglich ist.

Ansonsten ist eine private Registry auch für Firmen und Selfhosting-Freunde interessant. Firmen müssen abwägen, ob die einfachere Standard-Registry ausreicht - oder ob sie sich mit Docker EE die Docker Trusted Registry samt Image-Signing und automatischen Sicherheitsscans leisten möchten.

Eine lokale Registry starten

Die besagte Registry wird von Docker selbst mit dem Image registry zur Verfügung gestellt, d. h. die Registry ist selbst ein Docker-Container. Inzwischen sollte Version 2 verwendet werden. Starten kann man den Registry-Container dann folgendermaßen:

Bash:
$ docker container run -d -p 5000:5000 --restart always --name private-registry registry:2

Der gezeigte Befehl startet eine Registry-Instanz mit dem Namen private-registry, die unter localhost:5000 auf dem Host erreichbar ist. Für erste Tests reicht dieses Setup aus.

Images hoch- und herunterladen

Für die Befehle docker image push zum Hochladen und docker image pull zum Herunterladen eines Images gibt es eine Konvention: Startet ein Image-Tag mit <Host>:<Port>/, handelt es sich dabei um die Adresse einer Registry als Ziel bzw. Quelle. Für unsere Registry bedeutet das, dass wir jedes Image mit localhost:5000/ als Prefix taggen müssen.

Im folgenden Beispiel lade ich ein Alpine-Image von Docker Hub herunter, erstelle einen neuen Tag mit dem genannten Prefix und lade es in meine private Registry hoch.

Bash:
$ docker image pull alpine:3.9
$ docker image tag alpine:3.9 localhost:5000/alpine:3.9
$ docker image push localhost:5000/alpine:3.9

Das Alpine-Image mit dem neu erstellten Tag ist ab sofort in der lokalen Registry verfügbar. Lokal kann ich das Image also löschen.

Bash:
$ docker image rm alpine:3.9
$ docker image rm localhost:5000/alpine:3.9

Nun kann Alpine-Linux aus der privaten Registry heruntergeladen werden. Um docker image pull mitzuteilen, dass die Quelle von Docker Hub abweicht, verwende ich wieder die Adresse meiner Registry als Prefix.

Bash:
$ docker image pull localhost:5000/alpine:3.9

Den Storage auslagern

Standardmäßig wird das Verzeichnis /var/lib/registry, in dem der Registry-Storage liegt, automatisch als anonymes Volume eingebunden. Um die Storage-Verwaltung zu erleichtern, bietet es sich an, einen Bind Mount oder ein Named Volume dafür zu erstellen.

Bash:
$ docker volume create registry-data
$ docker container run -d \
  -p 5000:5000
  --restart=always
  --name private-registry
  --mount type=volume,source=registry-data,destination=/var/lib/registry
  registry:2

Registry im Netzwerk verfügbar machen

Bisher handelt es sich bei unserer privaten Registry um eine lokale Registry. Um sie öffentlich im Netzwerk zugänglich zu machen, verlangt Docker eine Absicherung per TLS, womit also ein TLS-Zertifikat erforderlich ist. Für dieses Beispiel habe ich ein Verzeichnis certs erstellt, in welchem sich das TLS-Zertifikat domain.crt und der TLS-Schlüssel domain.key befinden.

Mit einem Bind Mount kann das Verzeichnis nun in den Container eingehängt werden:

Bash:
$ docker container run -d \
  --restart=always \
  --name private-registry \
  --mount type=bind,source=/pfad/zu/certs,destination=/certs \
  -e REGISTRY_HTTP_ADDR=0.0.0.0:443 \
  -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
  -e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
  -p 443:443
  registry:2

Die -e-Optionen legen die Umgebungsvariablen fest, die von der Registry zur TLS-Konfiguration herangezogen werden. Außerdem ändern sich die Ports nun zu 443.

Authentifizierung für die Registry

Die einfachste Authentifizierungsmethode für die private Registry ist htpasswd, die ich hier demonstrieren werde. Für ernsthafte Anwendungsfälle sollte aber auch nginx als Authentifizierungs-Proxy in Erwägung gezogen werden.

Zuerst lege ich ein lokales Verzeichnis auth an und erstelle eine htpasswd-Datei mit Zugangsdaten.

Bash:
$ mkdir auth
$ echo "dominik passwort123" >> auth/htpasswd

Beim Start des Containers lege erstelle ich nun einen Bind Mount, mit dem ich das auth-Verzeichnis an der Stelle /auth im Container einhänge. Außerdem setze ich zwei Umgebungsvariablen, welche ebenfalls von der Registry verwendet werden.

Bash:
$ docker container run -d \
  --restart=always \
  --name private-registry \
  \
  --mount type=bind,source=/pfad/zu/auth,destination=/auth \
  -e "REGISTRY_AUTH=htpasswd" \
  -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
  \
  --mount type=bind,source=/pfad/zu/certs,destination=/certs \
  -e REGISTRY_HTTP_ADDR=0.0.0.0:443 \
  -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
  -e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
  -p 443:443
  registry:2

Der mittlere Teil stellt die Änderung im Vergleich zum vorherigen Befehl dar. Nun ist ein Login mit docker login localhost:443 erforderlich, um Images hoch- und herunterladen zu können.

Erweiterte Konfiguration

Alle konfigurierbaren Eigenschaften der Registry befinden sich in der Datei /etc/docker/registry/config.yml. Zwar sind diese Eigenschaften mit sinnvollen Standardwerten versehen, wer seine Registry aber im produktiven Einsatz betreiben möchte, sollte diese Werte unbedingt überprüfen. Bei Bedarf gibt es zwei Möglichkeiten, die Konfigurationswerte anzupassen.

Einzelne Werte überschreiben: Jeder Konfigurationswert kann mit einer Umgebungsvariable als -e-Option beim Start des Containers überschrieben werden. Der Name der Umgebungsvariable hat immer die Form REGISTRY_<EIGENSCHAFT>, wobei <EIGENSCHAFT> der Name des YAML-Keys ist.

YAML:
storage:
  filesystem:
    rootdirectory: /var/lib/registry

Dabei wird immer der gesamte "Pfad" zum Key angegeben. Die Eigenschaft rootdirectory ließe sich beispielsweise mit folgender Option überschreiben:

Bash:
-e REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY=/mein/pfad

Gesamte Konfiguration überschreiben: Wem das zu viele einzelne Umgebungsvariablen sind, kann auch die gesamte Standard-Konfiguration überschreiben, indem er einfach eine eigene YAML-Datei mountet. Zur besseren Übersichtlichkeit lasse hier die oben aufgeführten Optionen weg:

Bash:
$ docker container run -d \
  -p 5000:5000 \
  --restart=always \
  --name private-registry \
  --mount type=bind,source=/pfad/zur/eigenen/config.yml,destination=/etc/docker/registry/config.yml \
  registry:2

Welche Konfigurationswerte verfügbar sind, ist in der entsprechenden Referenz aufgeführt.
Autor
dominik
Aufrufe
495
Erstellt am
Letzte Bearbeitung
Bewertung
0,00 Stern(e) 0 Bewertung(en)

Weitere Ressourcen von dominik

Oben Unten