Como Usar Container Registry Privado: Harbor, GHCR e AWS ECR na Prática em Produção Já leu

Introdução: Por Que Um Container Registry Privado? Quando você trabalha com containerização em produção, armazenar imagens Docker em repositórios públicos (como Docker Hub) pode ser uma prática arriscada. Dados sensíveis, propriedade intelectual e conformidade regulatória são questões críticas. Um container registry privado é exatamente uma solução que permite manter suas imagens de forma segura, com controle total sobre acesso, versionamento e distribuição. Existem três principais opções no mercado atualmente: Harbor (open-source, self-hosted), GitHub Container Registry — GHCR (integrado ao GitHub, cloud-based) e AWS ECR (serviço gerenciado da Amazon). Cada uma tem seu lugar na arquitetura de uma empresa. Neste artigo, você aprenderá não apenas como configurar cada uma, mas também quando usá-las e como integrá-las ao seu pipeline de CI/CD. Harbor: Container Registry Privado Self-Hosted O Que é Harbor e Por Que Escolhê-lo Harbor é um container registry de código aberto, desenvolvido pela Cloud Native Computing Foundation (CNCF). Ele oferece controle total sobre sua infraestrutura, sem depender de provedores cloud.

Introdução: Por Que Um Container Registry Privado?

Quando você trabalha com containerização em produção, armazenar imagens Docker em repositórios públicos (como Docker Hub) pode ser uma prática arriscada. Dados sensíveis, propriedade intelectual e conformidade regulatória são questões críticas. Um container registry privado é exatamente uma solução que permite manter suas imagens de forma segura, com controle total sobre acesso, versionamento e distribuição.

Existem três principais opções no mercado atualmente: Harbor (open-source, self-hosted), GitHub Container Registry — GHCR (integrado ao GitHub, cloud-based) e AWS ECR (serviço gerenciado da Amazon). Cada uma tem seu lugar na arquitetura de uma empresa. Neste artigo, você aprenderá não apenas como configurar cada uma, mas também quando usá-las e como integrá-las ao seu pipeline de CI/CD.

Harbor: Container Registry Privado Self-Hosted

O Que é Harbor e Por Que Escolhê-lo

Harbor é um container registry de código aberto, desenvolvido pela Cloud Native Computing Foundation (CNCF). Ele oferece controle total sobre sua infraestrutura, sem depender de provedores cloud. Com features como replicação de imagens, verificação de vulnerabilidades (Trivy integrado), RBAC (Role-Based Access Control) e suporte a múltiplos protocolos, Harbor é ideal para empresas que precisam de customização completa.

A principal vantagem é a autonomia: você não paga por requisições ou armazenamento, apenas mantém a infraestrutura. A desvantagem é que você é responsável por backup, segurança e escalabilidade. Para organizações médias a grandes, especialmente em ambientes on-premise, Harbor é praticamente obrigatório.

Instalando Harbor com Docker Compose

Vou mostrar como instalar Harbor de forma prática usando Docker Compose. Primeiro, baixe o arquivo de configuração oficial:

wget https://github.com/goharbor/harbor/releases/download/v2.8.2/harbor-offline-installer-v2.8.2.tgz
tar xzvf harbor-offline-installer-v2.8.2.tgz
cd harbor

Agora, edite o arquivo harbor.yml. Este é o arquivo de configuração central:

# harbor.yml
hostname: registry.seudominio.com.br
http:
  port: 80
https:
  port: 443
  certificate: /path/to/certificate.crt
  private_key: /path/to/private.key

harbor_admin_password: SenhaForte123!@#
database:
  password: DbPassword123!@#

data_volume: /data

trivy:
  ignore_unfixed: false
  severity: HIGH,CRITICAL

Para gerar certificados SSL autoassinados (apenas para desenvolvimento):

openssl req -x509 -newkey rsa:4096 -keyout private.key -out certificate.crt -days 365 -nodes

Agora execute a instalação:

./prepare
docker-compose up -d

Verifique se todos os containers estão rodando:

docker-compose ps

Acesse via navegador em https://registry.seudominio.com.br (aceite o aviso de certificado auto-assinado). Login padrão: admin / Harbor12345.

Integrando Harbor com Docker CLI

Para fazer push de imagens ao Harbor, primeiro você precisa fazer login:

docker login registry.seudominio.com.br
# Username: seu_usuario
# Password: sua_senha

Agora crie uma imagem de exemplo e faça push:

# Crie um Dockerfile simples
cat > Dockerfile << 'EOF'
FROM python:3.11-slim
WORKDIR /app
COPY . .
RUN pip install flask
EXPOSE 5000
CMD ["python", "app.py"]
EOF

# Build da imagem
docker build -t registry.seudominio.com.br/meu-projeto/app:v1.0 .

# Push para Harbor
docker push registry.seudominio.com.br/meu-projeto/app:v1.0

Acesse o dashboard do Harbor e você verá o projeto meu-projeto com a imagem app armazenada. Harbor automaticamente verifica vulnerabilidades usando Trivy — você pode consultar relatórios de segurança diretamente na interface.

Replicação de Imagens

Harbor permite replicar imagens automaticamente entre registries. Vá em Administration → Registries e adicione um novo registry de destino. Depois, crie uma regra de replicação que sincronize suas imagens com um segundo Harbor ou até com ECR como backup.

GitHub Container Registry (GHCR): Integração Nativa com GitHub

Entendendo GHCR e Quando Usá-lo

GitHub Container Registry é a solução de registro de containers do GitHub. Diferentemente do Docker Hub, ele está intimamente integrado com repositórios GitHub e ações CI/CD. É a escolha natural se você já hospeda seu código no GitHub e quer minimizar configurações extras.

Vantagens incluem: não requer setup adicional, integração nativa com GitHub Actions, suporte automático a OIDC (OpenID Connect) para deployments seguros e preços razoáveis. A desvantagem é que você fica amarrado ao ecossistema GitHub. Se sua organização usa GitLab ou Gitea, essa não é a melhor opção.

Autenticação e Push com GitHub Actions

Para usar GHCR, você precisa de um personal access token (PAT) do GitHub. Acesse Settings → Developer settings → Personal access tokens → Tokens (classic) e crie um token com permissão write:packages e delete:packages.

Agora vou mostrar um workflow GitHub Actions que faz build e push de imagem automaticamente:

# .github/workflows/docker-publish.yml
name: Docker Publish

on:
  push:
    branches:
      - main
    tags:
      - 'v*'

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  build:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Log in to Container Registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract metadata
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          tags: |
            type=ref,event=branch
            type=semver,pattern={{version}}
            type=semver,pattern={{major}}.{{minor}}

      - name: Build and push Docker image
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}

Este workflow faz build e push automaticamente quando você faz push na branch main ou cria uma tag. O GITHUB_TOKEN é injetado automaticamente pelo GitHub, sem necessidade de configuração manual.

Usando Imagens do GHCR

Para usar uma imagem hospedada no GHCR em um deployment, você precisa se autenticar primeiro. Em um cluster Kubernetes:

apiVersion: v1
kind: Secret
metadata:
  name: ghcr-secret
type: kubernetes.io/dockercfg
data:
  .dockercfg: <BASE64_ENCODED_DOCKER_CONFIG>
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      imagePullSecrets:
        - name: ghcr-secret
      containers:
        - name: app
          image: ghcr.io/seuusername/seu-repo:latest
          ports:
            - containerPort: 5000

Para gerar o secret, você pode usar:

kubectl create secret docker-registry ghcr-secret \
  --docker-server=ghcr.io \
  --docker-username=seu_username \
  --docker-password=seu_pat_token \
  --docker-email=seu_email@example.com \
  -o yaml > ghcr-secret.yaml

AWS ECR: Container Registry Gerenciado

Arquitetura e Benefícios do ECR

AWS Elastic Container Registry é o serviço gerenciado de container registry da Amazon. Integra perfeitamente com EC2, ECS, EKS e Lambda, oferecendo escalabilidade automática, criptografia nativa e suporte completo a IAM para controle de acesso granular.

A principal vantagem é simplicidade operacional: AWS cuida de patching, backups, redundância e escalabilidade. Você paga por armazenamento (USD 0,07 por GB/mês no início de 2024) e requisições. Para empresas já na AWS, ECR é praticamente transparente — não requer setup dedicado além de permissões IAM.

Criando Repositório e Fazendo Push

Primeiro, crie um repositório ECR via AWS CLI:

aws ecr create-repository \
  --repository-name meu-projeto/app \
  --region us-east-1 \
  --image-scanning-configuration scanOnPush=true \
  --encryption-configuration encryptionType=AES

Agora, faça login no ECR. Note que o token de login expira em 12 horas:

# Obter URI do ECR
ECR_URI=$(aws ecr describe-repositories \
  --repository-names meu-projeto/app \
  --region us-east-1 \
  --query 'repositories[0].repositoryUri' \
  --output text)

# Fazer login
aws ecr get-login-password --region us-east-1 | \
  docker login --username AWS --password-stdin $ECR_URI

Build e push da imagem:

# Build
docker build -t $ECR_URI:v1.0 .

# Push
docker push $ECR_URI:v1.0

# Verificar imagens no repositório
aws ecr describe-images \
  --repository-name meu-projeto/app \
  --region us-east-1

Integração com ECS e EKS

Para usar imagens ECR em ECS, a configuração é direta. Aqui está uma task definition exemplo:

{
  "family": "meu-app-task",
  "networkMode": "awsvpc",
  "requiresCompatibilities": ["FARGATE"],
  "cpu": "256",
  "memory": "512",
  "containerDefinitions": [
    {
      "name": "meu-app",
      "image": "123456789012.dkr.ecr.us-east-1.amazonaws.com/meu-projeto/app:v1.0",
      "portMappings": [
        {
          "containerPort": 5000,
          "hostPort": 5000,
          "protocol": "tcp"
        }
      ],
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/meu-app",
          "awslogs-region": "us-east-1",
          "awslogs-stream-prefix": "ecs"
        }
      }
    }
  ],
  "executionRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole"
}

Para EKS, você precisará configurar um ImagePullSecret com credenciais ECR:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: default
  namespace: default

---
apiVersion: v1
kind: Secret
metadata:
  name: ecr-secret
  namespace: default
type: kubernetes.io/dockercfg
data:
  .dockercfg: <BASE64_DOCKER_AUTH>

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      serviceAccountName: default
      imagePullSecrets:
        - name: ecr-secret
      containers:
        - name: app
          image: 123456789012.dkr.ecr.us-east-1.amazonaws.com/meu-projeto/app:v1.0
          ports:
            - containerPort: 5000

Policies IAM para Segurança

Configure políticas IAM granulares para seus usuários e roles. Aqui está um exemplo que permite push/pull apenas para repositórios específicos:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "ecr:GetDownloadUrlForLayer",
        "ecr:BatchGetImage",
        "ecr:PutImage",
        "ecr:InitiateLayerUpload",
        "ecr:UploadLayerPart",
        "ecr:CompleteLayerUpload"
      ],
      "Resource": "arn:aws:ecr:us-east-1:123456789012:repository/meu-projeto/*"
    },
    {
      "Effect": "Allow",
      "Action": "ecr:GetAuthorizationToken",
      "Resource": "*"
    }
  ]
}

Comparação Prática e Seleção da Melhor Opção

Agora que você conhece os três, precisamos entender como escolher. A decisão não é sobre qual é "melhor", mas qual se adequa melhor ao seu contexto.

Harbor é sua escolha se: você precisa de máxima autonomia, trabalha em ambiente on-premise, tem dados regulados (LGPD, HIPAA), ou quer replicação distribuída entre datacenters. Desvantagem: você gerencia a infraestrutura e é responsável por patches de segurança.

GHCR é sua escolha se: você já usa GitHub como repositório principal, prefere não configurar coisas extras e quer CI/CD integrada. Desvantagem: você fica preso ao ecossistema GitHub e não tem as features avançadas de Harbor como replicação pull-based.

AWS ECR é sua escolha se: você já está investido na AWS, usa ECS ou EKS, e quer gerenciamento mínimo. Desvantagem: custa dinheiro por armazenamento/requisições e você fica amarrado à AWS.

Uma estratégia comum em grandes organizações é usar dois registries: ECR como sistema primário em produção (gerenciado, confiável, integrado) e Harbor como backup/desenvolvimento (controle total, sem custos variáveis). Imagens são replicadas do Harbor para ECR antes do deploy.

Conclusão

Você aprendeu que não existe uma solução única para todos: Harbor oferece controle máximo em troca de responsabilidade operacional; GHCR integra perfeitamente com GitHub eliminando complexidade; ECR fornece gerenciabilidade em ambientes AWS. A segunda lição crítica é que container registries privados não são apenas armazenamento — eles são pontos críticos de segurança que precisam de autenticação forte, RBAC bem definido, e verificação de vulnerabilidades ativa. A terceira é que a escolha influencia seu pipeline inteiro: um bom registry economiza horas em troubleshooting de pulls falhos, autenticação quebrada e imagens obsoletas.

Referências


Artigos relacionados