- Unregistry ist eine leichtgewichtige Container-Image-Registry, die Images direkt aus dem Docker-Daemon-Speicher speichert und bereitstellt; mit dem Befehl
docker pussh werden Images per SSH direkt an einen entfernten Docker-Server übertragen
- Bisherige Optionen sind Docker Hub/GitHub Container Registry, eine selbst gehostete Registry,
docker save | ssh... docker load oder ein Remote-Rebuild – jeweils mit Problemen wie öffentlichen bzw. kostenpflichtigen Repositories, Betriebsaufwand, Übertragung des gesamten Images oder verschwendeten Serverressourcen
docker pussh myapp:latest user@server erstellt einen SSH-Tunnel, startet auf dem entfernten Server einen temporären unregistry-Container und führt dann über einen weitergeleiteten localhost-Port docker push aus, sodass nur Layer übertragen werden, die auf dem Ziel fehlen
- Auf dem entfernten Server werden eine laufende Docker-Umgebung, Berechtigungen für den
docker-Befehl sowie beim ersten Start Zugriff auf ghcr.io/psviderski/unregistry:latest benötigt; der unregistry-Container läuft wegen des Zugriffs auf /run/containerd/containerd.sock als root
- Wenn der containerd image store von Docker aktiviert ist, sind die übertragenen Images sofort in Docker nutzbar und doppelte Speicherung wird vermieden; Images und Container, die mit dem bisherigen classic storage driver erstellt wurden, können jedoch vorübergehend unsichtbar sein
Welches Deployment-Problem Unregistry löst
- Unregistry ist eine leichtgewichtige Container-Image-Registry, um Docker-Images ohne externe Registry auf entfernte Server zu übertragen
- Der enthaltene Docker-CLI-Plugin-Befehl heißt
docker pussh; das zusätzliche s steht für SSH
- Beim Übertragen lokal gebauter Docker-Images auf einen Server haben die üblichen Optionen folgende Einschränkungen
- Docker Hub / GitHub Container Registry: Der Code wird öffentlich oder es fallen Kosten für private Repositories an
- Self-hosted registry: Es entsteht ein zusätzlicher Dienst mit Wartungs-, Sicherheits- und Storage-Aufwand
- Save/Load:
docker save | ssh <remote server> docker load überträgt das gesamte Image, selbst wenn 90 % davon bereits auf dem Server vorhanden sind
- Remote rebuild: Verbraucht Zeit und Serverressourcen; in der Produktion müssen unter Umständen Build-Fehler debuggt werden
Funktionsweise von docker pussh
- Die Grundnutzung besteht aus einer einzigen Zeile
docker pussh myapp:latest user@server
- Dieser Befehl überträgt nur fehlende Layer direkt per SSH, ohne Registry-Konfiguration, Abonnement, Zwischenspeicher oder offene Ports
- Intern läuft der Vorgang in folgender Reihenfolge ab
- Ein SSH-Tunnel zum entfernten Server wird erstellt
- Auf dem Server wird ein temporärer unregistry-Container gestartet
- Ein beliebiger localhost-Port wird über den Tunnel auf den unregistry-Port weitergeleitet
- Über den weitergeleiteten Port wird
docker push ausgeführt, sodass nur Layer übertragen werden, die auf dem Ziel fehlen
- Das übertragene Image ist im entfernten Docker-Daemon sofort nutzbar
- Der unregistry-Container wird gestoppt und der SSH-Tunnel geschlossen
- Das Projekt zielt auf eine einfache und effiziente Übertragung nach Art von
rsync für Docker-Images
- Unregistry wurde für das leichtgewichtige Tool Uncloud entwickelt, das Container auf mehrere Docker-Hosts verteilt; benötigt wurde ein Ansatz, der einfacher als eine vollständige Registry und effizienter als save/load ist
Laufzeitvoraussetzungen und Einschränkungen
- Auf dem lokalen Rechner wird Docker-CLI-Plugin-Support benötigt, außerdem Docker 19.03 oder neuer und ein OpenSSH-Client
- Auf dem entfernten Server muss Docker installiert sein und laufen
- Der SSH-Benutzer muss berechtigt sein, den Befehl
docker auszuführen
- Der Benutzer ist entweder
root oder ein non-root-Benutzer in der Gruppe docker
- Siehe dazu die Docker-Dokumentation Manage Docker as a non-root user
- Falls
sudo erforderlich ist, muss sudo docker ohne Passwort-Prompt ausführbar sein
- Beim ersten Ausführen von
docker pussh muss der entfernte Server das Image ghcr.io/psviderski/unregistry:latest von ghcr.io abrufen können
- Server, die einen Proxy benötigen, müssen gemäß Dockers Anleitung Daemon proxy configuration konfiguriert werden
- In air-gapped Umgebungen oder Umgebungen mit eingeschränktem Zugriff auf
ghcr.io kann die benötigte Version des unregistry-Images ermittelt und manuell vorgeladen werden
- Der unregistry-Container benötigt Zugriff auf
/run/containerd/containerd.sock und wird daher mit den nötigen Berechtigungen als root ausgeführt
Installation und unterstützte Plattformen
- Unter macOS/Linux kann
docker-pussh per Homebrew installiert werden
brew install psviderski/tap/docker-pussh
- Nach der Homebrew-Installation muss ein symbolischer Link
~/.docker/cli-plugins/docker-pussh erstellt werden, damit docker pussh als Docker-CLI-Plugin nutzbar ist
- Unter macOS/Linux steht außerdem ein Direktdownload bereit
- Das aktuelle Versionsbeispiel ist
v0.4.3, bei dem das Skript docker-pussh in das Docker-Plugin-Verzeichnis heruntergeladen und ausführbar gemacht wird
- Auch das Herunterladen des neuesten Skripts aus dem main-Branch wird angeboten
- Debian kann über das inoffizielle Paket-Repository unregistry-debian installiert werden, das von @dariogriffo erstellt wurde und gepflegt wird
- Windows wird derzeit nicht unterstützt, aber WSL 2 und die Linux-Installationsschritte können ausprobiert werden
- Die Installation wird mit folgendem Befehl geprüft
docker pussh --help
Konfiguration des containerd image store
Nutzungsbeispiele
- Für eine einfache Übertragung werden nur der Image-Name und das entfernte SSH-Ziel angegeben
docker pussh myapp:latest user@server.example.com
- Wenn kein Private Key im SSH-Agent registriert ist, kann der Key mit
-i angegeben werden
docker pussh myapp:latest ubuntu@192.168.1.100 -i ~/.ssh/id_rsa
- Ein benutzerdefinierter SSH-Port wird angegeben, indem der Port an das Ziel angehängt wird
docker pussh myapp:latest user@server:2222
- Eine benutzerdefinierte SSH-Config-Datei wird mit
-F angegeben
docker pussh myapp:latest prod-server -F ~/.ssh/config.prod
- Um bei einem Multi-Plattform-Image nur eine bestimmte Plattform zu pushen, wird
--platform verwendet
docker pussh myapp:latest user@server --platform linux/amd64
- Um auf dem entfernten Host eine bestimmte Version des unregistry-Images zu verwenden, wird die Umgebungsvariable
UNREGISTRY_IMAGE gesetzt
UNREGISTRY_IMAGE=ghcr.io/psviderski/unregistry:A.B.C docker pussh myapp:latest user@server.example.com
Typische Anwendungsfälle
- Bei Deployments auf Produktionsservern können lokal gebaute Images ohne Zwischen-Registry direkt auf den Server gepusht und dort ausgeführt werden
docker build --platform linux/amd64 -t myapp:1.2.3 .
docker pussh myapp:1.2.3 deploy@prod-server
ssh deploy@prod-server docker run -d myapp:1.2.3
- In CI/CD-Pipelines lässt sich die Komplexität einer Registry überspringen, indem Images direkt an das Deployment-Ziel gesendet werden
- name: Build and deploy
run: |
docker build -t myapp:${{ github.sha }} .
docker pussh myapp:${{ github.sha }} deploy@staging-server
- In Homelab- und air-gapped Umgebungen können Images in isolierte Netzwerke deployed werden, die keinen Internetzugang zu öffentlichen Registries haben
Fortgeschrittene Nutzung und verwandte Projekte
- Unregistry kann auch als eigenständige lokale Registry verwendet werden
- Dazu wird
/run/containerd/containerd.sock gemountet und der Container ghcr.io/psviderski/unregistry ausgeführt
- Anschließend kann
localhost:5000 wie eine normale Registry mit docker tag und docker push verwendet werden
- Für SSH-Konfigurationen kann die Standard-SSH-Config-Datei genutzt oder mit
-F eine separate Config-Datei übergeben werden
- Verwandte Third-Party-Projekte werden angeboten
- Für die Implementierung werden Spegel und Docker Distribution erwähnt
- Spegel ist eine P2P-Container-Image-Registry, die als Inspiration für eine Registry-Implementierung mit containerd image store als Backend diente
- Docker Distribution ist die Docker-Registry-Implementierung, auf der unregistry basiert
1 Kommentare
Meinungen auf Hacker News
Als jemand, der Docker entwickelt hat, gefällt mir das. Das ideale Design wäre wohl ein einzelner Server gewesen, ohne Trennung zwischen Docker Engine und Registry.
Wenn er Container je nach Bedarf hätte speichern, übertragen und ausführen können, wäre daraus eine deutlich robustere Komponente geworden; außerdem hätte man die unglückliche Entwicklung vermeiden können, dass Engine und Registry Images unterschiedlich speichern.
Außerdem sollte meiner Ansicht nach jeder Produktions-Cluster einen verteilten Image-Speicher haben, und das Pushen eines Images in diesen Speicher sollte das Deployment auslösen. Die heutige Vorgehensweise – in eine Registry pushen, den Cluster konfigurieren und dann jeden Node aus der Registry pullen lassen – ist fragil und ineffizient. Ich habe für ein besseres Design argumentiert, aber die Trägheit war schon zu groß, und die frühe Kubernetes-Community stand Ideen aus Docker feindselig gegenüber.
Deployment per Push in den Cluster klingt clever. Ich denke über einen verteilten Image-Speicher nach, bei dem unregistry auf allen Nodes läuft, sodass sie Images voneinander holen und teilen können; aber darüber, dass ein Push das Deployment auslöst, muss ich noch etwas länger nachdenken.
Gefällt mir. Der Befehl
pusshverdient wirklich Anerkennung als elegantes Wortspiel. Leicht zu merken, die Bedeutung ist sofort erkennbar, und er unterscheidet sich vom verwandten Standardbefehl nur um einen Buchstaben.docker push-over-sshwäre auch gut.In gemeinsam entwickelter Automatisierung kann
pusshfür jemanden, der die Funktion nicht kennt, wie ein Tippfehler aussehen und unnötige Verwirrung stiften.push-over-sshmacht dagegen klar, dass der Name beabsichtigt ist. Man kann es wie kurze und lange Optionen betrachten.sist dassaussssh.„Was ist dieses zusätzliche
s?“„Ein Tippfehler.“
2015 habe ich naiv versucht, diese Funktion per PR[1] in den Docker-Mainline-Zweig zu bringen, wurde aber schnell darauf umgelenkt, in anderen Bereichen zu helfen. Etwas, das die Registry überflüssig macht, hätte Dockers Geschäftsmodell vielleicht zu stark erschüttert.
[1]: https://github.com/richardcrichardc/docker2docker
Ich vermute, der Plan ist letztlich, den Standard auf den containerd-Image-Speicher umzustellen. Wenn lokal wie remote der containerd-Image-Speicher genutzt wird, sollte man das, was ursprünglich implementiert wurde, auch ohne Registry-Wrapper umsetzen können.
Eine tolle Idee, die gut zu Systemen passen dürfte, die bereits Push-Deployment-Tools wie Ansible verwenden. In Unternehmen ohne 24/7-Support für die Docker Registry könnte das auch ein guter Mechanismus für Hotfix-Deployments sein.
Ich frage mich, ob es sich sauber in OCI-Tools wie buildah integrieren lässt oder ob an beiden Enden eine vollständige Docker-Installation nötig ist. Ich habe noch nicht tiefer hineingeschaut, aber damit skopeo in so einer Konfiguration funktioniert, scheint das Bootstrappen einer Mini-Registry auf dem Remote-Server das fehlende Puzzleteil zu sein.
Unregistry verwendet auf der API-Schicht den offiziellen Docker-Registry-Code wieder und sieht daher ähnlich aus und verhält sich ähnlich wie https://hub.docker.com/_/registry.
Auf dem Client kann man Tools verwenden, die eine OCI Registry sprechen, etwa skopeo, crane, regclient, BuildKit usw. Um diese zu nutzen, muss man unregistry allerdings manuell auf dem Remote-Host starten. Der Befehl
docker pusshautomatisiert diesen Ablauf lediglich mithilfe des lokalen Docker.Man kann es einfach als Bash-Skript betrachten: https://github.com/psviderski/unregistry/blob/main/docker-pu...
Es lässt sich leicht nach eigenen Vorstellungen anpassen.
So hätte es von Anfang an sein sollen. Hervorragend.
Docker Registries haben zwar ihre Einsatzbereiche, aber insgesamt sind sie überdesignt und stehen dem Hacker-Geist eher entgegen.
Es dauerte etwa 20 Minuten, einen
.yaml-Workflow einzurichten, der Images baut und in eine private ghcr.io-Registry pusht, und etwa 5 Minuten, dem Server zu erlauben, Images von dort abzurufen. Eine ziemlich pragmatische Konfiguration.Ich sehe mir gerade eine Pipeline an, die Images in GitLab baut und nach Artifactory pusht; dann wird ein Deployment ausgelöst, das sie aus Artifactory holt und erneut nach AWS ECR pusht, anschließend die Deployment-Templates in EKS aktualisiert, woraufhin die Nodes die Images aus ECR ziehen und Pod-Container starten.
Ich brauche das in meinem Leben.
Dadurch bin ich auf uncloud aufmerksam geworden. Ich suchte für den Server-Aufbau eines Nebenprojekts nach etwas wie dokku, nur etwas leistungsfähiger – und genau danach fühlt es sich an.
Die Stack-Funktion ist ebenfalls wirklich gut; im Grunde ist sie Docker Compose. Auf einer EC2-Instanz startet Portainer Agent Caddy in einem Container, und Caddy dient als Load Balancer und Reverse Proxy.
Es ist ziemlich seltsam, dass Docker nicht von Anfang an so funktioniert hat. Sieht cool aus.
Speichern lässt sich das Archiv etwa mit
docker save -o may-app.tar my-app:latest, Laden mitdocker load -i /path/to/my-app.tar.Mit Tools wie Ansible lässt sich leicht erreichen, was „Unregistry“ automatisiert. Laut GitHub-Repository ist der Nachteil des save/load-Ansatzes, dass das gesamte Image über das Netzwerk übertragen wird, was in der Praxis ein Problem sein kann. Außerdem scheint es bequemer, das Image selbst statt einer Archivdatei zu verwalten.
Ein sauberes Projekt und ein sauberer Ansatz. Ich hatte genug von teuren Registries und hoste deshalb Zot[1] selbst, aber für manche Einsatzzwecke wirkt das hier deutlich einfacher.
Ich frage mich, ob es noch andere gibt, die sich einen privaten Registry-Service wünschen, der einfach einzurichten, günstig und nutzungsbasiert abgerechnet ist.
[1]: https://zotregistry.dev
Eine gute Idee. Allerdings könnte es den Nachteil geben, dass das Deployment an den Service gekoppelt wird. Zum Beispiel ist mir nicht klar, wie Scale-out oder Red/Green-Deployments funktionieren sollen; wer so etwas übernimmt, müsste wohl vom Push wissen.
Nachtrag: Das macht offenbar uncloud. Habe ich gerade erst erfahren.
Trotzdem ist es ein Trade-off. Wenn der Umfang klein ist, man eine einzelne Hetzner-VM nutzt, mit Einfachheit zufrieden ist und es in Ordnung findet, Images lokal zu bauen, ist es großartig.