4 puntos por GN⁺ 2025-06-19 | 1 comentarios | Compartir por WhatsApp
  • Unregistry es un registro ligero de imágenes de contenedor que guarda y sirve imágenes directamente desde el almacén del daemon de Docker, y con el comando docker pussh envía imágenes directamente a un servidor Docker remoto por SSH
  • Las opciones existentes son Docker Hub/GitHub Container Registry, un registro autoalojado, docker save | ssh... docker load y reconstrucción remota, pero cada una tiene problemas de repositorios públicos o de pago, carga operativa, transferencia de la imagen completa o desperdicio de recursos del servidor
  • docker pussh myapp:latest user@server crea un túnel SSH, levanta un contenedor unregistry temporal en el servidor remoto y luego ejecuta docker push hacia un puerto localhost reenviado, transfiriendo solo las capas que no existen en el destino
  • En el servidor remoto se necesita un entorno de ejecución de Docker, permiso para ejecutar el comando docker y, en la primera ejecución, acceso a ghcr.io/psviderski/unregistry:latest; el contenedor de unregistry se ejecuta como root porque necesita acceso a /run/containerd/containerd.sock
  • Si se activa el containerd image store de Docker, la imagen transferida puede usarse de inmediato desde Docker y se evita el almacenamiento duplicado, aunque las imágenes y contenedores creados con el classic storage driver podrían dejar de verse temporalmente

El problema de despliegue que resuelve Unregistry

  • Unregistry es un registro ligero de imágenes de contenedor para mover imágenes de Docker a servidores remotos sin usar un registro externo
  • El comando del plugin de Docker CLI incluido es docker pussh, donde la s extra significa SSH
  • Al mover a un servidor una imagen de Docker creada localmente, las opciones habituales tienen estas limitaciones
    • Docker Hub / GitHub Container Registry: el código debe ser público o hay que pagar por repositorios privados
    • Self-hosted registry: aparece un servicio adicional que requiere mantenimiento, seguridad y costo de almacenamiento
    • Save/Load: docker save | ssh <remote server> docker load transfiere la imagen completa aunque el servidor ya tenga el 90%
    • Remote rebuild: consume tiempo y recursos del servidor, y puede obligarte a depurar fallas de build en producción

Cómo funciona docker pussh

  • El uso básico es una sola línea
docker pussh myapp:latest user@server
  • Este comando transfiere solo las capas faltantes directamente por SSH, sin configurar un registro, pagar una suscripción, usar almacenamiento intermedio ni abrir puertos públicos
  • Internamente funciona en este orden
    • Crea un túnel SSH hacia el servidor remoto
    • Inicia un contenedor temporal de unregistry en el servidor
    • Reenvía un puerto localhost aleatorio por el túnel hacia el puerto de unregistry
    • Ejecuta docker push contra el puerto reenviado para transferir solo las capas ausentes en el remoto
    • La imagen transferida queda disponible de inmediato en el daemon Docker remoto
    • Detiene el contenedor de unregistry y cierra el túnel SSH
  • El proyecto busca una forma simple y eficiente, similar a rsync, para transferir imágenes de Docker
  • Unregistry fue creado para Uncloud, una herramienta ligera para desplegar contenedores en varios hosts Docker, porque se necesitaba algo más simple que un registro completo y más eficiente que save/load

Requisitos y limitaciones de ejecución

  • La máquina local necesita soporte para plugins de Docker CLI, además de Docker 19.03 o superior y un cliente OpenSSH
  • El servidor remoto debe tener Docker instalado y en ejecución
  • El usuario SSH debe tener permiso para ejecutar el comando docker
    • El usuario debe ser root o un usuario no root que pertenezca al grupo docker
    • La documentación relacionada está en Docker: Manage Docker as a non-root user
    • Si se requiere sudo, debe poder ejecutarse sudo docker sin pedir contraseña
  • En la primera ejecución de docker pussh, el servidor remoto debe poder descargar la imagen ghcr.io/psviderski/unregistry:latest desde ghcr.io
    • Si el servidor necesita proxy, debe configurarse siguiendo la guía de Docker Daemon proxy configuration
    • En entornos air-gapped o donde el acceso a ghcr.io esté restringido, se puede verificar la versión necesaria de la imagen de unregistry y precargarla manualmente
  • El contenedor de unregistry se ejecuta como root porque necesita acceder a /run/containerd/containerd.sock

Instalación y plataformas compatibles

  • En macOS/Linux se puede instalar docker-pussh con Homebrew
brew install psviderski/tap/docker-pussh
  • Después de instalar con Homebrew, para usar docker pussh como plugin de Docker CLI hay que crear un enlace simbólico ~/.docker/cli-plugins/docker-pussh
  • En macOS/Linux también se ofrece descarga directa
    • El ejemplo de versión actual usa el script docker-pussh de v0.4.3, descargándolo al directorio de plugins de Docker y dándole permisos de ejecución
    • También se ofrece descargar el script más reciente de la rama main
  • En Debian se puede instalar mediante el repositorio de paquetes no oficial unregistry-debian, creado y mantenido por @dariogriffo
  • Windows no es compatible por ahora, pero se puede intentar con WSL 2 y el procedimiento de instalación de Linux
  • La instalación se verifica con el siguiente comando
docker pussh --help

Configuración de containerd image store

  • Unregistry guarda imágenes directamente en el image store de containerd, el runtime de contenedores subyacente que usa Docker
  • En el comportamiento predeterminado de Docker, este mantiene una capa de almacenamiento separada y no usa directamente las imágenes de containerd
  • Si se habilita containerd image store en Docker, este puede usar directamente las imágenes almacenadas por unregistry y eliminar la duplicación
  • Al habilitar containerd image store

    • Las imágenes enviadas con unregistry quedan disponibles de inmediato en Docker
    • Las imágenes se guardan una sola vez en containerd, sin usar espacio adicional
    • Como no hace falta un docker pull adicional desde unregistry al classic Docker image store, pussh se vuelve más rápido
  • Al mantener el comportamiento predeterminado de Docker

    • Después del push, pussh ejecuta un docker pull adicional en el host remoto para que la imagen pueda usarse desde Docker
    • La imagen se guarda tanto en containerd como en el classic Docker image store, así que se almacena dos veces
    • Las imágenes no gestionadas de containerd pueden ir llenando espacio en disco con el tiempo
    • La gestión manual se hace con estos comandos
    sudo ctr -n moby images ls
    sudo ctr -n moby images rm <image>
    
  • Puntos a tener en cuenta al configurar

    • Para activar containerd image store en Docker Engine, se siguen las instrucciones oficiales de Docker
    • Al cambiar a containerd image store, las imágenes y contenedores creados con el classic storage driver pueden dejar de verse temporalmente
    • Esos recursos siguen en el sistema de archivos y se pueden recuperar desactivando la función de containerd image store

Ejemplos de uso

  • La transferencia básica solo requiere el nombre de la imagen y el destino SSH remoto
docker pussh myapp:latest user@server.example.com
  • Si la clave privada no está cargada en el agente SSH, se puede indicar con -i
docker pussh myapp:latest ubuntu@192.168.1.100 -i ~/.ssh/id_rsa
  • Un puerto SSH personalizado se indica agregándolo al destino
docker pussh myapp:latest user@server:2222
  • Un archivo de configuración SSH personalizado se indica con -F
docker pussh myapp:latest prod-server -F ~/.ssh/config.prod
  • Para hacer push de una sola plataforma específica dentro de una imagen multi-plataforma, usa --platform
docker pussh myapp:latest user@server --platform linux/amd64
  • Para usar una versión específica de la imagen de unregistry en el host remoto, define la variable de entorno UNREGISTRY_IMAGE
UNREGISTRY_IMAGE=ghcr.io/psviderski/unregistry:A.B.C docker pussh myapp:latest user@server.example.com

Casos de uso representativos

  • En despliegues a servidores de producción, se puede hacer push directamente al servidor y ejecutar la imagen construida localmente, sin un registro intermedio
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
  • En pipelines de CI/CD, se puede enviar la imagen directamente al destino de despliegue y evitar la complejidad de un registro
- name: Build and deploy
  run: |
    docker build -t myapp:${{ github.sha }} .
    docker pussh myapp:${{ github.sha }} deploy@staging-server
  • En homelabs y entornos air-gapped, se pueden desplegar imágenes en redes aisladas sin acceso a registros públicos por Internet

Uso avanzado y proyectos relacionados

  • Unregistry también puede usarse como un registro local independiente
    • Monta /run/containerd/containerd.sock y ejecuta el contenedor ghcr.io/psviderski/unregistry
    • Luego se puede usar localhost:5000 como un registro normal con docker tag y docker push
  • La configuración SSH puede usar el archivo estándar de configuración de SSH o pasarse con -F un archivo distinto
  • Hay proyectos de terceros relacionados
  • En la implementación se mencionan Spegel y Docker Distribution
    • Spegel es un registro P2P de imágenes de contenedor que inspiró la implementación de un registro con containerd image store como backend
    • Docker Distribution es la implementación de registro Docker en la que se basa unregistry

1 comentarios

 
GN⁺ 2025-06-19
Opiniones de Hacker News
  • Como alguien que creó Docker, me gusta. Creo que el diseño ideal habría sido un único servidor sin distinción entre el motor de Docker y el registro.
    Si hubiera podido almacenar, transferir y ejecutar contenedores según hiciera falta, habría sido un componente mucho más robusto, y también se habría evitado esa desafortunada divergencia en la forma en que el motor y el registro almacenan imágenes.
    Además, creo que todo clúster de producción debería tener un almacén distribuido de imágenes, y que hacer push de una imagen a ese almacén debería disparar el despliegue. El modelo actual —hacer push al registro, configurar el clúster y que cada nodo haga pull desde el registro— es frágil e ineficiente. Defendí un diseño mejor, pero la inercia ya era demasiado grande, y la comunidad inicial de Kubernetes era hostil a las ideas que venían de Docker.

    • Definitivamente es desordenado que haya al menos tres disposiciones de sistema de archivos para las imágenes y hasta dos almacenes de imágenes dentro del motor. Aun así, creo que todavía no es tarde para que Docker logre esa dirección sin romper el modelo actual. Aunque no sé si a Docker le importará, y últimamente parece estar pasando por tiempos difíciles.
      El despliegue haciendo push al clúster suena ingenioso. Estoy pensando en un almacén distribuido de imágenes donde se ponga un unregistry en todos los nodos para que obtengan y compartan imágenes entre sí, pero el enfoque en el que el push dispara el despliegue requiere pensarlo un poco más.
  • Me gusta. El comando pussh realmente merece reconocimiento como un juego de palabras elegante. Es fácil de recordar, su significado se ve de inmediato y solo difiere en una letra de su comando estándar hermano.

    • No está mal, pero también estaría bueno tener un alias más oficial como docker push-over-ssh.
      En automatizaciones desarrolladas de forma colaborativa, pussh puede parecer un typo para alguien que no conoce la función y generar confusión innecesaria. En cambio, push-over-ssh deja claro que es un nombre intencional. Se puede pensar como opciones cortas y opciones largas.
    • La s agregada es la s de sssh.
      “¿Qué es esa s extra?”
      “Un typo”.
    • También es fácil que haya conflictos.
  • En 2015 envié ingenuamente un PR[1] para intentar meter esta función en la línea principal de Docker, pero rápidamente me redirigieron a ayudar en otras áreas. Tal vez permitir no usar el registro sacudía demasiado el modelo de negocio de Docker.
    [1]: https://github.com/richardcrichardc/docker2docker

    • Así que usted fue el original. Es una lástima que Docker todavía no tenga una API para explorar capas de imágenes.
      Creo que, al final, el plan será cambiar el valor predeterminado al almacén de imágenes de containerd. Cuando se use el almacén de imágenes de containerd tanto en local como en remoto, parece que se podrá hacer lo que originalmente se implementó, sin un wrapper de registro.
  • Es una idea genial que parece encajar bien con sistemas que ya usan herramientas de despliegue por push como Ansible. En empresas que no tienen soporte 24/7 para el registro de Docker, también parece un buen mecanismo para desplegar hotfixes.
    Me pregunto si se integra limpiamente con herramientas OCI como buildah, o si requiere una instalación completa de Docker en ambos extremos. Todavía no lo miré en profundidad, pero en esta configuración parece que la pieza que falta para que skopeo funcione es arrancar un mini registro en el servidor remoto.

    • Del lado remoto se necesita containerd. Docker y Kubernetes también usan containerd. Del lado cliente basta con cualquier herramienta que hable la API de registro, es decir, la especificación OCI Distribution (https://github.com/opencontainers/distribution-spec).
      Unregistry reutiliza el código oficial del registro de Docker en la capa de API, así que se ve y se comporta de forma parecida a https://hub.docker.com/_/registry.
      En el cliente se pueden usar herramientas que hablen registros OCI, como skopeo, crane, regclient, BuildKit, etc. Eso sí, para usarlas hay que ejecutar unregistry manualmente en el host remoto. El comando docker pussh solo automatiza ese flujo usando el Docker local.
      Piénselo simplemente como un script Bash: https://github.com/psviderski/unregistry/blob/main/docker-pu...
      Se puede adaptar fácilmente como se quiera.
    • Estoy de acuerdo. En varios servicios que administro, compilo las imágenes localmente, las guardo, subo el archivo con Ansible y luego restauro las imágenes, y normalmente tarda mucho más de lo que me gustaría.
    • Se necesita un daemon de Docker en ambos extremos. Es una forma ingeniosa de compartir capas entre los dos daemons a través de SSH.
  • Así es como debería haber sido desde el principio. Excelente.
    Los registros de Docker tienen sus usos, pero en general están sobrediseñados y van en contra del espíritu hacker.

    • Era una empresa financiada con capital de riesgo, así que Docker tenía que ganar dinero de alguna forma.
    • Recomiendo usar ghcr.io, el registro de GitHub, junto con GitHub Actions.
      Me tomó unos 20 minutos configurar un workflow .yaml que construye imágenes y las sube a un registro privado de ghcr.io, y unos 5 minutos permitir que el servidor las obtenga desde ahí. Es una configuración bastante práctica.
    • La complejidad parece estar en el procedimiento para hacer push de blobs al registro. Alguna vez hice un registro de solo lectura compatible con OCI, y no era tan complicado.
  • Estoy viendo un pipeline que construye imágenes en GitLab y las sube a Artifactory; luego se dispara el despliegue, se obtienen desde Artifactory y se vuelven a subir a AWS ECR; después se actualiza la plantilla de despliegue en EKS, y entonces se obtienen desde ECR hacia los nodos para levantar los contenedores del Pod.
    Necesito esto en mi vida.

    • Pregunto por curiosidad: ¿por qué usan tanto Artifactory como ECR? Nosotros estamos evaluando migrar de Artifactory a ECR para reducir costos.
    • En el pipeline de mi último proyecto, el tiempo de hacer pull y push de contenedores era mayor que el de compilar la app real. Y aun así todo ese tiempo era poco comparado con la espera de los health checks, cuando en realidad se podía saber si estaba sano o no en menos de 1 segundo después de arrancar.
  • Al ver esto conocí uncloud. Estaba buscando algo parecido a dokku, pero más potente, para configurar el servidor de un proyecto paralelo, y se siente justo así.

    • También está https://skateco.github.io/. A simple vista parece similar.
    • Si no has usado o evaluado Portainer, lo recomiendo. En AWS estoy corriendo Portainer Community Edition y Portainer Agent en dos instancias EC2, y funciona bien.
      La función de stacks también es muy buena; en la práctica es Docker Compose. En una instancia EC2, Portainer Agent ejecuta Caddy dentro de un contenedor, y Caddy actúa como balanceador de carga y proxy inverso.
    • Me alegra que te haya llegado la idea de uncloud. Si tienes preguntas o necesitas ayuda, puedes entrar a Discord.
  • Es bastante raro que Docker no haya funcionado así desde el principio. Se ve genial.

    • Ya se puede hacer lo mismo creando un archivo de la imagen, enviándolo al servidor y luego ejecutándolo desde ese archivo en el servidor.
      Para guardar el archivo se usa algo como docker save -o may-app.tar my-app:latest, y para cargarlo algo como docker load -i /path/to/my-app.tar.
      Con herramientas como Ansible se puede lograr fácilmente lo que “Unregistry” automatiza. Según el repositorio de GitHub, la desventaja del enfoque save/load es que transfiere toda la imagen por la red, y eso puede ser un problema real. También parece más cómodo gestionar la imagen en sí en lugar de un archivo comprimido.
  • Es un proyecto y un enfoque prolijos. Me cansé de los registros caros y terminé autoalojando Zot[1], pero para algunos usos esto parece mucho más fácil.
    Me pregunto si hay más gente que sienta que estaría bueno tener un servicio de registro privado fácil de configurar, barato y con cobro según uso.
    [1]: https://zotregistry.dev

    • Por si no lo sabías, el certificado SSL de zothub.io venció.
  • Es una buena idea. Aunque puede tener la desventaja de acoplar el despliegue al servicio. Por ejemplo, no sé cómo manejaría el escalado horizontal o despliegues red/green, y parece que quien haga ese trabajo tendría que conocer el push.
    Edit: resultó que uncloud es lo que hace eso. Me acabo de enterar.
    Aun así, es un trade-off. Si la escala es pequeña, usas una sola VM de Hetzner, estás conforme con la simplicidad y también te parece bien construir las imágenes localmente, es excelente.

    • Sin duda siempre hay trade-offs. Es bueno tener opciones para poder elegir la herramienta más adecuada para cada trabajo.