- Unregistry é um registro leve de imagens de contêiner que armazena e serve imagens diretamente do image store do daemon Docker, e o comando
docker pussh envia imagens diretamente para um servidor Docker remoto via SSH
- As opções existentes eram Docker Hub/GitHub Container Registry, um registro self-hosted,
docker save | ssh... docker load ou rebuild remoto, mas cada uma tem problemas como repositórios públicos ou pagos, carga operacional, transferência da imagem inteira ou desperdício de recursos do servidor
docker pussh myapp:latest user@server cria um túnel SSH, inicia um contêiner unregistry temporário no servidor remoto e então executa docker push por uma porta localhost encaminhada, enviando apenas as camadas que não existem no destino
- No servidor remoto, é necessário um ambiente Docker em execução, permissão para usar o comando
docker e, na primeira execução, acesso a ghcr.io/psviderski/unregistry:latest; o contêiner unregistry é executado como root por causa do acesso a /run/containerd/containerd.sock
- Ao ativar o containerd image store do Docker, a imagem transferida fica imediatamente disponível no Docker e evita armazenamento duplicado, mas imagens e contêineres criados com o classic storage driver podem ficar temporariamente invisíveis
O problema de deploy que o Unregistry resolve
- Unregistry é um registro leve de imagens de contêiner para mover imagens Docker para servidores remotos sem depender de um registro externo
- O comando incluído como plugin da CLI do Docker é
docker pussh, em que o s extra significa SSH
- Ao mover para um servidor uma imagem Docker criada localmente, as opções comuns têm as seguintes limitações
- Docker Hub / GitHub Container Registry: é preciso tornar o código público ou pagar por repositórios privados
- Self-hosted registry: cria um serviço separado que exige manutenção, segurança e custo de armazenamento
- Save/Load:
docker save | ssh <remote server> docker load transfere a imagem inteira, mesmo que 90% dela já exista no servidor
- Remote rebuild: consome tempo e recursos do servidor, e pode exigir depuração de falhas de build em produção
Como o docker pussh funciona
- O uso básico é esta única linha
docker pussh myapp:latest user@server
- Esse comando envia apenas as camadas ausentes diretamente por SSH, sem configurar registro, assinatura, armazenamento intermediário ou portas públicas
- O funcionamento interno segue esta ordem
- Cria um túnel SSH para o servidor remoto
- Inicia um contêiner unregistry temporário no servidor
- Encaminha uma porta localhost aleatória pelo túnel até a porta do unregistry
- Executa
docker push pela porta encaminhada, enviando apenas as camadas que não existem no destino
- A imagem transferida fica imediatamente disponível no daemon Docker remoto
- Para o contêiner unregistry e fecha o túnel SSH
- O projeto busca uma forma simples e eficiente de transferência, como um
rsync para imagens Docker
- O Unregistry foi criado para o Uncloud, uma ferramenta leve para implantar contêineres em vários hosts Docker, pois era necessário algo mais simples que um registro completo e mais eficiente que save/load
Requisitos de execução e limitações
- Na máquina local, é necessário suporte a plugins da Docker CLI, além de Docker 19.03 ou superior e um cliente OpenSSH
- No servidor remoto, o Docker deve estar instalado e em execução
- O usuário SSH precisa ter permissão para executar o comando
docker
- O usuário deve ser
root ou um usuário não root pertencente ao grupo docker
- A documentação relacionada é Manage Docker as a non-root user
- Se for necessário
sudo, deve ser possível executar sudo docker sem prompt de senha
- Na primeira execução de
docker pussh, o servidor remoto precisa conseguir baixar a imagem ghcr.io/psviderski/unregistry:latest a partir de ghcr.io
- Servidores que exigem proxy devem ser configurados conforme Daemon proxy configuration
- Em ambientes air-gapped ou com acesso restrito a
ghcr.io, é possível verificar a versão necessária da imagem unregistry e pré-carregá-la manualmente
- Como o contêiner unregistry precisa acessar
/run/containerd/containerd.sock, ele é executado como root para ter as permissões necessárias
Instalação e plataformas compatíveis
- Em macOS/Linux, é possível instalar
docker-pussh com Homebrew
brew install psviderski/tap/docker-pussh
- Depois da instalação via Homebrew, para usar
docker pussh como plugin da Docker CLI é necessário criar o link simbólico ~/.docker/cli-plugins/docker-pussh
- Em macOS/Linux, também existe instalação por download direto
- O exemplo da versão atual usa o script
docker-pussh da versão v0.4.3, baixado para o diretório de plugins do Docker e com permissão de execução
- Também é oferecida a opção de baixar o script mais recente da branch main
- No Debian, a instalação pode ser feita pelo repositório não oficial unregistry-debian, criado e mantido por @dariogriffo
- Windows não é compatível no momento, mas é possível tentar com WSL 2 e o procedimento de instalação para Linux
- A verificação da instalação é feita com o comando abaixo
docker pussh --help
Configuração do containerd image store
Exemplos de uso
- Na transferência básica, basta informar o nome da imagem e o destino SSH remoto
docker pussh myapp:latest user@server.example.com
- Se a private key não estiver carregada no SSH agent, é possível informar a chave com
-i
docker pussh myapp:latest ubuntu@192.168.1.100 -i ~/.ssh/id_rsa
- Uma porta SSH personalizada pode ser informada acrescentando a porta ao destino
docker pussh myapp:latest user@server:2222
- Um arquivo de configuração SSH personalizado pode ser informado com
-F
docker pussh myapp:latest prod-server -F ~/.ssh/config.prod
- Para enviar apenas uma plataforma específica de uma imagem multi-plataforma, use
--platform
docker pussh myapp:latest user@server --platform linux/amd64
- Para usar uma versão específica da imagem unregistry no host remoto, defina a variável de ambiente
UNREGISTRY_IMAGE
UNREGISTRY_IMAGE=ghcr.io/psviderski/unregistry:A.B.C docker pussh myapp:latest user@server.example.com
Casos de uso representativos
- Em deploy para servidores de produção, é possível fazer push direto da imagem criada localmente para o servidor e executá-la sem um registro intermediário
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
- Em pipelines de CI/CD, é possível enviar a imagem diretamente ao destino do deploy, pulando a complexidade de um registro
- name: Build and deploy
run: |
docker build -t myapp:${{ github.sha }} .
docker pussh myapp:${{ github.sha }} deploy@staging-server
- Em ambientes homelab e air-gapped, é possível implantar imagens em redes isoladas sem acesso à internet para registros públicos
Uso avançado e projetos relacionados
- O Unregistry também pode ser usado como um registro local standalone
- Monte
/run/containerd/containerd.sock e execute o contêiner ghcr.io/psviderski/unregistry
- Depois disso,
localhost:5000 pode ser usado como um registro comum com docker tag e docker push
- A configuração SSH pode usar o arquivo padrão de config do SSH ou um arquivo separado via
-F
- Existem projetos de terceiros relacionados
- A implementação menciona Spegel e Docker Distribution
- Spegel é um registro P2P de imagens de contêiner que inspirou a implementação de um registro usando o containerd image store como backend
- Docker Distribution é a implementação de registry Docker que serve de base para o unregistry
1 comentários
Opiniões no Hacker News
Como alguém que criou o Docker, gostei. Acho que o design ideal teria sido um único servidor sem distinção entre o engine do Docker e o registry
Se ele pudesse armazenar, transferir e executar contêineres conforme necessário, teria se tornado um componente muito mais robusto, e também teria evitado o rumo infeliz em que o engine e o registry armazenam imagens de maneiras divergentes
Também acho que todo cluster de produção deveria ter um armazenamento distribuído de imagens, e fazer push de imagens para esse armazenamento deveria acionar o deploy. O modelo atual — fazer push para um registry, configurar o cluster e fazer cada nó puxar do registry — é frágil e ineficiente. Defendi um design melhor, mas a inércia já era grande demais, e a comunidade inicial do Kubernetes era hostil a ideias vindas do Docker
Deploy por push para o cluster parece uma ideia inteligente. Estou pensando em um armazenamento distribuído de imagens em que se coloca o unregistry em todos os nós para que eles busquem e compartilhem imagens entre si, mas ainda preciso pensar melhor no modelo em que o push aciona o deploy
Muito bom. O comando
pusshrealmente merece reconhecimento como um trocadilho elegante. É fácil de lembrar, o significado fica claro de imediato e difere do comando padrão irmão por apenas uma letradocker push-over-sshEm automações desenvolvidas em colaboração,
pusshpode parecer um typo para alguém que não conhece a funcionalidade, criando confusão desnecessária. Jápush-over-sshdeixa claro que é um nome intencional. É como pensar em opções curtas e opções longassextra é osdesssh“O que é esse
sextra?”“É um typo”
Em 2015, ingenuamente enviei um PR[1] tentando colocar esse recurso no Docker principal, mas logo fui redirecionado para ajudar em outras áreas. Tornar possível não usar um registry talvez abalasse demais o modelo de negócios do Docker
[1]: https://github.com/richardcrichardc/docker2docker
Imagino que o plano seja, no fim, mudar o padrão para o armazenamento de imagens do containerd. Quando tanto o lado local quanto o remoto usarem o armazenamento de imagens do containerd, deve ser possível fazer o que você implementou originalmente sem um wrapper de registry
É uma ideia ótima que parece combinar bem com sistemas que já usam ferramentas de deploy por push, como Ansible. Para empresas que não têm suporte 24/7 para um Docker registry, também parece um bom mecanismo de deploy de hotfixes
Fico curioso se isso se integra de forma limpa com ferramentas OCI como buildah, ou se exige uma instalação completa do Docker nas duas pontas. Ainda não olhei a fundo, mas para o skopeo funcionar nesse tipo de configuração, inicializar um mini-registry no servidor remoto parece ser a peça que faltava
O Unregistry reutiliza o código oficial do Docker registry na camada de API, então ele se parece e se comporta de forma semelhante a https://hub.docker.com/_/registry
No cliente, é possível usar skopeo, crane, regclient, BuildKit e outras ferramentas que falem OCI registry. Porém, para usá-las, é preciso executar manualmente o unregistry no host remoto. O comando
docker pusshapenas automatiza esse fluxo usando o Docker localDá para pensar nele apenas como um script Bash: https://github.com/psviderski/unregistry/blob/main/docker-pu...
É fácil adaptá-lo diretamente do jeito que você quiser
Sempre deveria ter sido assim desde o começo. Excelente
Docker registries têm seus usos, mas, no geral, foram superprojetados e estão no lado oposto do espírito hacker
Levei uns 20 minutos para configurar um workflow
.yamlque constrói e faz push da imagem para um registry privado no ghcr.io, e mais uns 5 minutos para permitir que o servidor puxe a imagem de lá. É uma configuração bem práticaEstou vendo um pipeline em que a imagem é construída no GitLab e enviada para o Artifactory; então um deploy é acionado, a imagem é puxada do Artifactory e enviada de novo para o AWS ECR; aí o template de deploy no EKS é atualizado, os nós puxam a imagem do ECR e sobem os contêineres dos Pods
Eu preciso disso na minha vida
Ao ver isso, acabei conhecendo o uncloud. Eu estava procurando algo parecido com o dokku, mas um pouco mais robusto, para montar servidores de projetos paralelos, e a sensação é exatamente essa.
O recurso de stacks também é muito bom; na prática, é Docker Compose. Em uma instância EC2, o Portainer Agent executa o Caddy dentro de um contêiner, e o Caddy atua como balanceador de carga e proxy reverso.
É bem estranho que o Docker não tenha funcionado assim desde o começo. Parece legal.
Para salvar o arquivo, use algo como
docker save -o may-app.tar my-app:latest; para carregar, algo comodocker load -i /path/to/my-app.tar.Com ferramentas como Ansible, dá para conseguir facilmente o que o “Unregistry” automatiza. Segundo o repositório no GitHub, a desvantagem do método save/load é que ele transfere a imagem inteira pela rede, e isso pode de fato ser um problema. Gerenciar a própria imagem, em vez de um arquivo de archive, também parece mais conveniente.
É um projeto e uma abordagem elegantes. Cansei de registries caros e acabei auto-hospedando o Zot[1], mas para alguns usos isso parece muito mais fácil.
Fico curioso se há mais alguém que gostaria de um serviço de registry privado fácil de configurar, barato e cobrado conforme o uso.
[1]: https://zotregistry.dev
É uma boa ideia. Mas pode haver a desvantagem de o deploy ficar acoplado ao serviço. Por exemplo, não sei como ficariam scale-out ou deploy red/green, e imagino que o componente que faz isso teria que conhecer o push.
Edit: quem faz isso era o uncloud. Acabei de descobrir.
Ainda assim, é um trade-off. Se a escala for pequena, você usa uma única VM na Hetzner, está satisfeito com a simplicidade e não se importa de buildar a imagem localmente, é excelente.