Docker Registry: hospedando suas próprias imagens

1. Por que rodar seu próprio Registry?

Em pipelines DevOps que utilizam Docker e Kubernetes, o Docker Registry é o componente central para armazenamento e distribuição de imagens de contêiner. Embora serviços como Docker Hub e Amazon ECR sejam amplamente utilizados, cenários específicos exigem uma solução auto-hospedada.

Controle e privacidade dos artefatos
Empresas que desenvolvem software proprietário ou lidam com dados sensíveis não podem depender exclusivamente de registries públicos. Hospedar seu próprio registry garante que imagens nunca saiam do perímetro da rede corporativa.

Redução de latência em ambientes locais/on-premise
Em clusters Kubernetes on-premise ou em ambientes de desenvolvimento, um registry local reduz drasticamente o tempo de pull. Em vez de baixar camadas de centenas de megabytes da internet, as imagens trafegam na rede interna.

Cenários de air-gapped e compliance
Ambientes militares, financeiros ou de infraestrutura crítica frequentemente operam em redes isoladas (air-gapped). Nessas situações, o registry auto-hospedado não é uma opção — é um requisito obrigatório.

2. Instalação e configuração básica do Registry

A maneira mais rápida de iniciar é usando a imagem oficial registry:2:

docker run -d -p 5000:5000 --name registry registry:2

Para persistir dados, monte um volume bind:

docker run -d -p 5000:5000 --name registry \
  -v /data/registry:/var/lib/registry \
  registry:2

Agora você pode fazer push de uma imagem:

docker pull alpine:latest
docker tag alpine:latest localhost:5000/alpine:latest
docker push localhost:5000/alpine:latest

Para configurações avançadas, crie um arquivo config.yml:

version: 0.1
storage:
  filesystem:
    rootdirectory: /var/lib/registry
  delete:
    enabled: true
http:
  addr: :5000

Execute com configuração personalizada:

docker run -d -p 5000:5000 --name registry \
  -v /data/registry:/var/lib/registry \
  -v /data/config.yml:/etc/docker/registry/config.yml \
  registry:2

Para armazenamento em nuvem, substitua a seção storage:

storage:
  s3:
    accesskey: "AKIA..."
    secretkey: "..."
    region: us-east-1
    bucket: meu-registry
    rootdirectory: /registry

3. Autenticação e autorização

Habilitar autenticação básica com htpasswd é o primeiro passo para proteger o registry:

# Instalar htpasswd (se necessário)
apt-get install apache2-utils

# Criar arquivo de senhas
htpasswd -Bc /data/auth/htpasswd admin
# Digite a senha quando solicitado

# Executar registry com autenticação
docker run -d -p 5000:5000 --name registry \
  -v /data/registry:/var/lib/registry \
  -v /data/auth:/auth \
  -e "REGISTRY_AUTH=htpasswd" \
  -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
  -e "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd" \
  registry:2

Para fazer login:

docker login localhost:5000 -u admin -p "sua-senha"

Para integração com LDAP ou OAuth, utilize um proxy reverso (Nginx ou Traefik) que faça a autenticação externa antes de encaminhar para o registry. O controle de acesso por namespace pode ser implementado com políticas no proxy ou usando soluções como Harbor, que oferece RBAC nativo.

4. TLS e segurança na comunicação

Sem TLS, as credenciais e imagens trafegam em texto puro. Para testes, use certificados auto-assinados:

# Gerar certificado auto-assinado
mkdir -p /data/certs
openssl req -newkey rsa:4096 -nodes -sha256 \
  -keyout /data/certs/domain.key \
  -x509 -days 365 \
  -out /data/certs/domain.crt \
  -subj "/CN=meuregistry.local"

# Executar registry com TLS
docker run -d -p 443:5000 --name registry \
  -v /data/registry:/var/lib/registry \
  -v /data/certs:/certs \
  -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
  -e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
  registry:2

Para produção, use Let's Encrypt com Nginx como proxy reverso. Exemplo de configuração Nginx:

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

    ssl_certificate /etc/letsencrypt/live/registry.exemplo.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/registry.exemplo.com/privkey.pem;

    location / {
        proxy_pass http://localhost:5000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

Para que o Docker client confie em um CA privado, copie o certificado para /etc/docker/certs.d/meuregistry.local:5000/ca.crt em cada node.

5. Gerenciamento de imagens e limpeza

Comandos essenciais via Docker CLI:

# Listar tags de uma imagem (via API)
curl -X GET https://registry.exemplo.com/v2/alpine/tags/list

# Remover um manifesto (marca para garbage collection)
docker manifest rm registry.exemplo.com/alpine:old-tag

Para executar garbage collection e remover blobs órfãos:

docker exec registry /bin/registry garbage-collect \
  /etc/docker/registry/config.yml

Políticas de retenção podem ser implementadas com scripts que consultam a API e removem tags antigas. Ferramentas como docker-registry-web ou cr-cleaner automatizam esse processo.

6. Integração com Kubernetes

Para que o Kubernetes possa fazer pull de imagens do registry privado, crie um Secret:

kubectl create secret docker-registry regcred \
  --docker-server=registry.exemplo.com \
  --docker-username=admin \
  --docker-password=senha123 \
  --docker-email=admin@exemplo.com

Utilize o Secret nos Pods:

apiVersion: v1
kind: Pod
metadata:
  name: meu-app
spec:
  containers:
  - name: app
    image: registry.exemplo.com/meu-app:latest
  imagePullSecrets:
  - name: regcred

Para deploy do registry no próprio cluster Kubernetes, use um StatefulSet com PVC:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: docker-registry
spec:
  serviceName: registry
  replicas: 1
  selector:
    matchLabels:
      app: registry
  template:
    metadata:
      labels:
        app: registry
    spec:
      containers:
      - name: registry
        image: registry:2
        env:
        - name: REGISTRY_HTTP_TLS_CERTIFICATE
          value: /certs/tls.crt
        - name: REGISTRY_HTTP_TLS_KEY
          value: /certs/tls.key
        ports:
        - containerPort: 5000
        volumeMounts:
        - name: data
          mountPath: /var/lib/registry
        - name: certs
          mountPath: /certs
          readOnly: true
  volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 100Gi

7. Monitoramento e boas práticas

O registry expõe métricas no formato Prometheus via endpoint /v2/_catalog e /v2/<name>/blobs/<digest>. Para habilitar métricas completas, configure:

REGISTRY_STORAGE_CACHE_BLOBDESCRIPTOR: inmemory
REGISTRY_HTTP_DEBUG_ADDR: :5001

Configure o Prometheus para coletar métricas do registry e crie dashboards no Grafana para monitorar:

  • Número de pulls/pushes por segundo
  • Tamanho total do armazenamento
  • Latência de requisições

Para logs e auditoria, configure o registry para enviar logs estruturados em JSON:

REGISTRY_LOG_LEVEL: info
REGISTRY_LOG_FORMATTER: json

Backup e restore são simples quando se usa armazenamento filesystem: basta copiar o diretório /var/lib/registry. Para S3, utilize snapshots nativos do provedor.

Boas práticas finais:
- Sempre use TLS em produção
- Implemente autenticação desde o início
- Configure políticas de retenção para evitar crescimento descontrolado
- Monitore o uso de disco e estabeleça alertas
- Faça backup regular do armazenamento e da configuração

Referências