Um registro de contentores é um catálogo de armazenamento de onde você pode enviar e buscar imagens de contentores.

Existem muitos registros públicos e privados disponíveis para os desenvolvedores, como o Docker Hub, o Amazon ECR e o Google Cloud Artifact Registry. Mas às vezes, em vez de confiar em um fornecedor externo, você pode querer hospedar suas imagens sozinho. Isso dá mais controle sobre como o registro é configurado e onde os imagens de contentores estão hospedadas.

Este artigo é um tutorial prático que vai ensiná-lo a hospedar seu próprio registro de contentores.

Tabela de Conteúdos

Você conseguirá muito mais deste artigo se estiver familiarizado com ferramentas como Docker e NGINX, e tiver um entendimento geral de que é um container.

O que é uma Imagem de Container?

Antes de falarmos sobre registros de containers, vamos primeiro entender o que é uma imagem de container. Em resumo, uma imagem de container é um pacote que inclui todos os arquivos, bibliotecas e configurações necessários para executar um container. Eles são compostos de camadas onde cada camada representa um conjunto de mudanças no sistema de arquivos que adicionam, removem ou modificam arquivos.

A maneira mais comum de criar uma imagem de container é usando um Dockerfile.

# build an image
docker build -t pliutau/hello-world:v0 .

# check the images locally
docker images
# REPOSITORY    TAG       IMAGE ID       CREATED          SIZE
# hello-world   latest    9facd12bbcdd   22 seconds ago   11MB

Este processo cria uma imagem de recipiente que é armazenada em sua máquina local. Mas e se você quiser compartilhar essa imagem com outras pessoas ou usá-la em uma máquina diferente? É aqui que entram os registros de recipientes.

O que é um Registro de Container?

Um registro de container é um catálogo de armazenamento onde você pode enviar (push) e baixar (pull) imagens de containers. As imagens são agrupadas em repositórios, que são coleções de imagens relacionadas com o mesmo nome. Por exemplo, no registro Docker Hub, nginx é o nome do repositório que contém diferentes versões das imagens NGINX.

Alguns registros são públicos, o que significa que as imagens hospedadas neles estão acessíveis a qualquer pessoa na Internet. Registros públicos como o Docker Hub são boas opções para hospedar projetos open-source.

Por outro lado, registros privados fornecem uma maneira de integrar segurança e privacidade ao armazenamento de imagens de recipientes em empresas, tanto hospedados em nuvem quanto em localizações próprias. Estes registros privados frequentemente vem com funcionalidades de segurança avançadas e suporte técnico.

Há uma lista crescente de registros privados disponíveis, como o Amazon ECR, GCP Artifact Registry, GitHub Container Registry, e o Docker Hub também oferece uma funcionalidade de repositório privado.

Como desenvolvedor, você interage com um registro de contêineres quando usa os comandos docker push e docker pull.

docker push docker.io/pliutau/hello-world:v0

# Caso do Docker Hub, podemos também pular a parte do registro
docker push pliutau/hello-world:v0

Vamos olhar na anatomia de uma URL de imagem de contêiner:

docker pull docker.io/pliutau/hello-world:v0@sha256:dc11b2...
                |            |            |          |
                ↓            ↓            ↓          ↓
             registry    repository      tag       digest

Por que você pode querer hospedar um registro de contêineres de forma independente

Algumas vezes, em vez de confiar em um fornecedor como AWS ou GCP, você pode querer hospedar suas imagens por conta própria. Isso mantém sua infraestrutura interna e torna você menos dependente de fornecedores externos. Em algumas indústrias altamente regulamentadas, isso até é uma exigência.

Um registro de contêineres hospedado de forma independente executa em seus próprios servidores, dando-lhe mais controle sobre como o registro é configurado e onde as imagens de contêiner estão hospedadas. Ao mesmo tempo, isso vem com o custo de manutenção e de segurança do registro.

Como hospedar um registro de contêineres de forma independente

Existem várias soluções de registro de contêineres de código aberto disponíveis. A mais popular é oficialmente apoiada por Docker, chamada registry, com sua implementação para armazenamento e distribuição de imagens e artefatos de contêineres. Isso significa que você pode executar seu próprio registro dentro de um contêiner.

Aqui estão os principais passos para executar um registro em um servidor:

  • Instale o Docker e o Docker Compose no servidor.

  • Configure e execute o contêiner registry.

  • Execute NGINX para lidar com TLS e encaminhar solicitações para o recipiente de registro.

  • Configure certificados SSL e configure um domínio.

Passo 1: Instale o Docker e o Docker Compose no servidor

Você pode usar qualquer servidor que suporte o Docker. Por exemplo, você pode usar um Droplet DigitalOcean com o Ubuntu. Para esta demonstração, eu usei o Google Cloud Compute para criar uma VM com o Ubuntu.

neofetch

# Sistema Operacional: Ubuntu 20.04.6 LTS x86_64
# CPU: Intel Xeon (2) @ 2.200GHz
# Memória: 3908MiB

Uma vez dentro de nossa VM, devemos instalar o Docker e o Docker Compose. O Docker Compose é opcional, mas torna melhor a gerenciamento de aplicações de múltiplos recipientes.

# instale o motor de docker e docker-compose
sudo snap install docker

# verifique a instalação
docker --version
docker-compose --version

Passo 2: Configure e execute o recipiente de registro

Aqui, precisamos configurar o nosso recipiente de registro. O arquivo compose.yaml a seguir criará um recipiente de registro com um volume para armazenar as imagens e um volume para armazenar o arquivo de senha.

services:
  registry:
    image: registry:latest
    environment:
      REGISTRY_AUTH: htpasswd
      REGISTRY_AUTH_HTPASSWD_REALM: Registry Realm
      REGISTRY_AUTH_HTPASSWD_PATH: /auth/registry.password
      REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /data
    volumes:
      # Montar o arquivo de senhas
      - ./registry/registry.password:/auth/registry.password
      # Montar o diretório de dados
      - ./registry/data:/data
    ports:
      - 5000

O arquivo de senhas definido em REGISTRY_AUTH_HTPASSWD_PATH é usado para autenticar usuários quando eles enviarem ou baixarem imagens do registro. Deveríamos criar um arquivo de senhas usando o comando htpasswd. Também deveríamos criar uma pasta para armazenar as imagens.

mkdir -p ./registry/data

# Instalar htpasswd
sudo apt install apache2-utils

# Criar um arquivo de senhas. nome de usuário: busy, senha: bee
htpasswd -Bbn busy bee > ./registry/registry.password

Agora podemos iniciar o contêiner do registro. Se você ver essa mensagem, tudo está funcionando como deveria:

docker-compose up

# Execução bem-sucedida deveria exibir algo como isso:
# registry | level=info msg="listening on [::]:5000"

Passo 3: Executar NGINX para lidar com TLS

Como mencionado anteriormente, podemos usar NGINX para lidar com TLS e encaminhar pedidos para o contêiner do registro.

O Registro Docker requer um certificado SSL válido e confiável para funcionar. Você pode usar algo como Let’s Encrypt ou obter manualmente. Certifique-se de ter um nome de domínio apontando para seu servidor (registry.pliutau.com no meu caso). Para esta demonstração, eu já obtive os certificados usando certbot e coloquei-os na pasta ./nginx/certs.

since estamos executando o nosso Docker Registry em um contêiner, podemos também executar o NGINX em um contêiner adicionando o seguinte serviço ao arquivo compose.yaml:

services:
  registry:
    # ...
  nginx:
    image: nginx:latest
    depends_on:
      - registry
    volumes:
      # montar a configuração do nginx
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      # montar os certificados obtidos do Let's Encrypt
      - ./nginx/certs:/etc/nginx/certs
    ports:
      - "443:443"

O nosso arquivo nginx.conf poderia parecer com isso:

worker_processes auto;

events {
    worker_connections 1024;
}

http {
    upstream registry {
        server registry:5000;
    }

    server {
        server_name registry.pliutau.com;
        listen 443 ssl;

        ssl_certificate /etc/nginx/certs/fullchain.pem;
        ssl_certificate_key /etc/nginx/certs/privkey.pem;

        location / {
            # configuração importante para imagens grandes
            client_max_body_size                1000m;

            proxy_pass                          http://registry;
            proxy_set_header  Host              $http_host;
            proxy_set_header  X-Real-IP         $remote_addr;
            proxy_set_header  X-Forwarded-For   $proxy_add_x_forwarded_for;
            proxy_set_header  X-Forwarded-Proto $scheme;
            proxy_read_timeout                  900;
        }
    }
}

Pronto para começar!

Depois destes passos, podemos executar os contêineres de registro e Nginx.

docker-compose up

Agora, do lado do cliente, você pode enviar e baixar imagens do seu registro. Mas antes, precisamos logar no registro.

docker login registry.pliutau.com

# Usuário: busy
# Senha: bee
# Login bem-sucedido

É hora de construir e enviar nossa imagem para o nosso registro auto-hospedado:

docker build -t registry.pliutau.com/pliutau/hello-world:v0 .

docker push registry.pliutau.com/pliutau/hello-world:v0
# v0: digest: sha256:a56ea4... size: 738

No seu servidor, você pode ver as imagens enviadas na pasta de dados:

ls -la ./registry/data/docker/registry/v2/repositories/

Outras opções

Seguindo o exemplo acima, você também pode executar o registro no Kubernetes. Ou você pode usar um serviço de registro gerenciado, como o Harbor, que é um registro de código aberto que oferece funcionalidades de segurança avançadas e é compatible com Docker e Kubernetes.

Também, se você quiser ter uma IU para seu registro hospedado localmente, você poderia usar um projeto como joxit/docker-registry-ui e executá-lo em um container separado.

Conclusão

Registros de Container Hospedados Localmente permitem que você tenha controle total sobre seu registro e a maneira como é implantado. Ao mesmo tempo, isso vem com o custo de manutenção e segurança do registro.

Qualquer das suas razões para executar um registro hospedado localmente, agora sabe como é feito. A partir daqui, você pode comparar as diferentes opções e escolher aquele que melhor se adapta às suas necessidades.

Você pode encontrar o código fonte completo para este demo em GitHub. Também, pode assistir a ele como um vídeo no noss canal do YouTube.