- Unregistry est un registre d’images de conteneurs léger qui stocke et sert directement les images depuis le magasin du démon Docker, et la commande
docker pussh permet d’envoyer une image directement à un serveur Docker distant via SSH
- Les options existantes sont Docker Hub/GitHub Container Registry, un registre auto-hébergé,
docker save | ssh... docker load ou une reconstruction à distance, mais chacune pose des problèmes de dépôt public ou payant, de charge d’exploitation, de transfert de l’image entière ou de gaspillage des ressources serveur
docker pussh myapp:latest user@server crée un tunnel SSH, lance un conteneur unregistry temporaire sur le serveur distant, puis exécute docker push via un port localhost redirigé afin de ne transférer que les couches absentes à distance
- Le serveur distant doit disposer d’un environnement d’exécution Docker, des droits pour utiliser la commande
docker, et au premier lancement d’un accès à ghcr.io/psviderski/unregistry:latest ; le conteneur unregistry s’exécute en root car il doit accéder à /run/containerd/containerd.sock
- L’activation du containerd image store de Docker rend l’image transférée immédiatement utilisable dans Docker et évite le stockage en double, mais les images et conteneurs créés avec l’ancien classic storage driver peuvent temporairement ne plus apparaître
Le problème de déploiement que résout Unregistry
- Unregistry est un registre d’images de conteneurs léger conçu pour transférer des images Docker vers un serveur distant sans registre externe
- La commande du plugin Docker CLI incluse est
docker pussh, le s supplémentaire signifiant SSH
- Lorsqu’on veut transférer vers un serveur une image Docker construite localement, les options habituelles ont les limites suivantes
- Docker Hub / GitHub Container Registry : il faut soit rendre le code public, soit payer pour des dépôts privés
- Self-hosted registry : cela ajoute un service distinct avec maintenance, sécurité et coûts de stockage
- Save/Load :
docker save | ssh <remote server> docker load transfère l’image entière même si 90 % est déjà présent sur le serveur
- Remote rebuild : cela consomme du temps et des ressources serveur, et il peut falloir déboguer des échecs de build en production
Fonctionnement de docker pussh
- L’usage de base tient en une seule ligne
docker pussh myapp:latest user@server
- Cette commande envoie uniquement les couches manquantes directement via SSH, sans configuration de registre, sans abonnement, sans stockage intermédiaire et sans port exposé publiquement
- En interne, elle suit les étapes suivantes
- Création d’un tunnel SSH vers le serveur distant
- Démarrage sur le serveur d’un conteneur unregistry temporaire
- Redirection d’un port localhost aléatoire à travers le tunnel vers le port d’unregistry
- Exécution de
docker push via le port redirigé afin de ne transférer que les couches absentes à distance
- L’image transférée est immédiatement utilisable par le démon Docker distant
- Arrêt du conteneur unregistry et fermeture du tunnel SSH
- Le projet vise un transfert simple et efficace, comparable à
rsync pour les images Docker
- Unregistry a été créé pour Uncloud, un outil léger de déploiement de conteneurs sur plusieurs hôtes Docker, qui avait besoin d’une approche plus simple qu’un registre complet et plus efficace que save/load
Exigences d’exécution et limites
- La machine locale doit prendre en charge les plugins Docker CLI et nécessite Docker 19.03 ou plus ainsi qu’un client OpenSSH
- Le serveur distant doit avoir Docker installé et en cours d’exécution
- L’utilisateur SSH doit avoir le droit d’exécuter la commande
docker
- Soit l’utilisateur est
root, soit un utilisateur non root doit appartenir au groupe docker
- Voir la documentation Docker Manage Docker as a non-root user
- Si
sudo est requis, il doit être possible d’exécuter sudo docker sans invite de mot de passe
- Lors du premier lancement de
docker pussh, le serveur distant doit pouvoir récupérer l’image ghcr.io/psviderski/unregistry:latest depuis ghcr.io
- Si le serveur a besoin d’un proxy, il faut le configurer selon la documentation Docker Daemon proxy configuration
- Dans un environnement air-gapped ou restreint vis-à-vis de
ghcr.io, il est possible de précharger manuellement la version requise de l’image unregistry après l’avoir identifiée
- Le conteneur unregistry doit accéder à
/run/containerd/containerd.sock et s’exécute donc en root avec les privilèges nécessaires
Installation et plateformes prises en charge
- Sur macOS/Linux,
docker-pussh peut être installé avec Homebrew
brew install psviderski/tap/docker-pussh
- Après une installation Homebrew, pour utiliser
docker pussh comme plugin Docker CLI, il faut créer un lien symbolique ~/.docker/cli-plugins/docker-pussh
- Une méthode par téléchargement direct est aussi proposée pour macOS/Linux
- L’exemple de version actuelle consiste à télécharger le script
docker-pussh de v0.4.3 dans le répertoire des plugins Docker puis à lui donner les droits d’exécution
- Une méthode est aussi fournie pour télécharger le script le plus récent depuis la branche main
- Sur Debian, l’installation est possible via le dépôt de paquets non officiel unregistry-debian, créé et maintenu par @dariogriffo
- Windows n’est pas pris en charge pour le moment, mais il est possible d’essayer WSL 2 et la procédure d’installation Linux
- La vérification de l’installation s’effectue avec la commande suivante
docker pussh --help
Configuration du containerd image store
Exemples d’utilisation
- Pour un transfert de base, il suffit d’indiquer le nom de l’image et la cible SSH distante
docker pussh myapp:latest user@server.example.com
- Si aucune clé privée n’est enregistrée dans l’agent SSH, on peut spécifier une clé avec
-i
docker pussh myapp:latest ubuntu@192.168.1.100 -i ~/.ssh/id_rsa
- Un port SSH personnalisé s’indique en l’ajoutant après la cible
docker pussh myapp:latest user@server:2222
- Un fichier de configuration SSH personnalisé peut être indiqué avec
-F
docker pussh myapp:latest prod-server -F ~/.ssh/config.prod
- Pour ne pousser qu’une plateforme précise d’une image multi-plateforme, utiliser
--platform
- Pour que Docker local prenne en charge les images multi-plateforme, il faut utiliser le containerd image store
docker pussh myapp:latest user@server --platform linux/amd64
- Pour utiliser une version précise de l’image unregistry sur l’hôte distant, définir la variable d’environnement
UNREGISTRY_IMAGE
UNREGISTRY_IMAGE=ghcr.io/psviderski/unregistry:A.B.C docker pussh myapp:latest user@server.example.com
Cas d’usage représentatifs
- Pour un déploiement sur un serveur de production, on peut pousser directement sur le serveur puis lancer l’image construite localement, sans registre intermédiaire
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
- Dans un pipeline CI/CD, on peut envoyer l’image directement vers la cible de déploiement sans la complexité d’un registre
- name: Build and deploy
run: |
docker build -t myapp:${{ github.sha }} .
docker pussh myapp:${{ github.sha }} deploy@staging-server
- Dans un homelab ou un environnement air-gapped, il est possible de déployer des images sur un réseau isolé sans accès Internet à un registre public
Usage avancé et projets liés
- Unregistry peut aussi être utilisé comme registre local autonome
- Il suffit de monter
/run/containerd/containerd.sock et d’exécuter le conteneur ghcr.io/psviderski/unregistry
- Ensuite,
localhost:5000 peut être utilisé comme un registre classique avec docker tag et docker push
- La configuration SSH peut s’appuyer sur le fichier standard SSH config ou sur un fichier distinct fourni avec
-F
- Des projets tiers liés sont disponibles
- L’implémentation mentionne Spegel et Docker Distribution
- Spegel est un registre d’images de conteneurs P2P qui a inspiré l’implémentation d’un registre utilisant le containerd image store comme backend
- Docker Distribution est l’implémentation de registre Docker sur laquelle unregistry s’appuie
1 commentaires
Avis sur Hacker News
En tant que créateur de Docker, j’aime bien. La conception idéale aurait sans doute été un serveur unique sans distinction entre le moteur Docker et le registre.
Si l’on avait pu stocker, transférer et exécuter des conteneurs selon les besoins, cela aurait donné un composant bien plus robuste, et on aurait évité cette évolution regrettable où le moteur et le registre divergent dans leur façon de stocker les images.
Je pense aussi que tous les clusters de production devraient disposer d’un stockage d’images distribué, et que pousser une image vers ce stockage devrait déclencher le déploiement. La méthode actuelle — pousser vers un registre, configurer le cluster, puis faire tirer l’image par chaque nœud depuis le registre — est fragile et inefficace. J’ai défendu une meilleure conception, mais l’inertie était déjà trop forte, et la communauté Kubernetes des débuts était hostile aux idées venues de Docker.
Le déploiement par push vers le cluster paraît astucieux. Je réfléchis à un stockage d’images distribué où l’on placerait unregistry sur tous les nœuds afin qu’ils récupèrent et partagent les images entre eux, mais il faut que je creuse davantage l’idée d’un push qui déclenche le déploiement.
Sympa. La commande
pusshmérite vraiment d’être saluée comme un jeu de mots élégant. Facile à retenir, son sens est immédiatement visible, et elle ne diffère de la commande standard sœur que d’une seule lettre.docker push-over-ssh.Dans une automatisation développée en collaboration,
pusshpeut ressembler à une faute de frappe pour quelqu’un qui ne connaît pas la fonctionnalité, créant une confusion inutile. À l’inverse,push-over-sshindique clairement que le nom est intentionnel. On peut voir ça comme des options courtes et longues.sajouté est lesdesssh.« C’est quoi ce
sen plus ? »« Une faute de frappe »
En 2015, j’ai naïvement envoyé une PR[1] pour essayer d’intégrer cette fonctionnalité dans Docker upstream, puis on m’a rapidement réorienté vers l’aide sur d’autres sujets. Rendre possible de se passer du registre bousculait peut-être trop le modèle économique de Docker.
[1]: https://github.com/richardcrichardc/docker2docker
Je pense qu’à terme le plan sera de basculer le stockage d’images par défaut vers celui de containerd. Une fois le stockage d’images containerd utilisé à la fois en local et à distance, il devrait être possible de faire ce que vous aviez implémenté à l’origine, sans wrapper de registre.
C’est une excellente idée, qui semble bien s’intégrer aux systèmes utilisant déjà des outils de déploiement par push comme Ansible. Dans les entreprises où le registre Docker n’a pas de support 24/7, cela pourrait aussi servir de bon mécanisme de déploiement de hotfix.
Je me demande si cela s’intègre proprement avec des outils OCI comme buildah, ou s’il faut une installation Docker complète aux deux extrémités. Je n’ai pas encore regardé en détail, mais dans cette configuration, faire fonctionner skopeo semble nécessiter comme pièce manquante le bootstrap d’un mini-registre sur le serveur distant.
Unregistry réutilise le code officiel du registre Docker au niveau de la couche API, donc il ressemble à https://hub.docker.com/_/registry et se comporte de manière similaire.
Côté client, on peut utiliser skopeo, crane, regclient, BuildKit, etc., bref des outils qui parlent registre OCI. Mais pour les utiliser, il faut lancer manuellement unregistry sur l’hôte distant. La commande
docker pusshne fait qu’automatiser ce flux en utilisant le Docker local.On peut la voir comme un simple script Bash : https://github.com/psviderski/unregistry/blob/main/docker-pu...
On peut facilement l’adapter directement comme on le souhaite.
C’est comme ça que cela aurait dû fonctionner depuis le début. Excellent.
Les registres Docker ont leur utilité, mais globalement ils sont trop conçus et se situent à l’opposé de l’esprit hacker.
Il m’a fallu environ 20 minutes pour configurer un workflow
.yamlqui construit et pousse l’image vers un registre privé ghcr.io, puis environ 5 minutes pour autoriser le serveur à récupérer l’image à partir de là. C’est une configuration assez pratique.Je regarde un pipeline qui construit les images dans GitLab et les pousse vers Artifactory, puis où un déploiement est déclenché, récupère depuis Artifactory pour repousser vers AWS ECR, met à jour le template de déploiement dans EKS, puis ECR est utilisé pour tirer l’image vers les nœuds et lancer les conteneurs des Pods.
J’ai besoin de ça dans ma vie.
C’est en voyant ça que j’ai découvert uncloud. Je cherchais quelque chose comme dokku, mais un peu plus costaud, pour configurer le serveur de mes side projects, et c’est exactement l’impression que ça donne.
La fonctionnalité de stacks est vraiment bonne aussi ; en pratique, c’est du Docker Compose. Sur une instance EC2, Portainer Agent lance Caddy dans un conteneur, et Caddy sert de répartiteur de charge et de reverse proxy.
C’est assez étrange que Docker n’ait pas fonctionné comme ça dès le départ. Ça a l’air sympa.
Pour enregistrer l’archive, on fait par exemple
docker save -o may-app.tar my-app:latest, et pour la charger,docker load -i /path/to/my-app.tar.Avec un outil comme Ansible, on peut facilement obtenir ce qu’« Unregistry » automatise. D’après le dépôt GitHub, l’inconvénient de l’approche save/load est qu’elle transfère toute l’image sur le réseau, ce qui peut effectivement poser problème. Gérer l’image elle-même plutôt qu’un fichier d’archive semble aussi plus pratique.
Projet et approche élégants. Lassé des registres coûteux, j’ai fini par auto-héberger Zot[1], mais pour certains usages, ceci semble beaucoup plus simple.
Je me demande si d’autres aimeraient disposer d’un service de registre privé facile à configurer, bon marché et facturé à l’usage.
[1]: https://zotregistry.dev
Bonne idée. Cela dit, il peut y avoir l’inconvénient de coupler le déploiement au service. Par exemple, je ne sais pas comment on gérerait le scale-out ou les déploiements red/green, et il me semble que le composant qui s’en charge devrait être au courant du push.
Édit : c’est uncloud qui fait ça. Je viens de m’en rendre compte.
Ça reste un compromis. Si l’échelle est modeste, que vous utilisez une seule VM Hetzner, que la simplicité vous convient et que ça ne vous dérange pas de construire les images en local, c’est excellent.