Docker & Kubernetes

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

14 min de leitura

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

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.

<h2>Introdução: Por Que Um Container Registry Privado?</h2>

<p>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.</p>

<p>Existem três principais opções no mercado atualmente: <strong>Harbor</strong> (open-source, self-hosted), <strong>GitHub Container Registry — GHCR</strong> (integrado ao GitHub, cloud-based) e <strong>AWS ECR</strong> (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.</p>

<h2>Harbor: Container Registry Privado Self-Hosted</h2>

<h3>O Que é Harbor e Por Que Escolhê-lo</h3>

<p>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.</p>

<p>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.</p>

<h3>Instalando Harbor com Docker Compose</h3>

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

<pre><code class="language-bash">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</code></pre>

<p>Agora, edite o arquivo <code>harbor.yml</code>. Este é o arquivo de configuração central:</p>

<pre><code class="language-yaml"># 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</code></pre>

<p>Para gerar certificados SSL autoassinados (apenas para desenvolvimento):</p>

<pre><code class="language-bash">openssl req -x509 -newkey rsa:4096 -keyout private.key -out certificate.crt -days 365 -nodes</code></pre>

<p>Agora execute a instalação:</p>

<pre><code class="language-bash">./prepare

docker-compose up -d</code></pre>

<p>Verifique se todos os containers estão rodando:</p>

<pre><code class="language-bash">docker-compose ps</code></pre>

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

<h3>Integrando Harbor com Docker CLI</h3>

<p>Para fazer push de imagens ao Harbor, primeiro você precisa fazer login:</p>

<pre><code class="language-bash">docker login registry.seudominio.com.br

Username: seu_usuario

Password: sua_senha</code></pre>

<p>Agora crie uma imagem de exemplo e faça push:</p>

<pre><code class="language-bash"># Crie um Dockerfile simples

cat &gt; Dockerfile &lt;&lt; &#039;EOF&#039;

FROM python:3.11-slim

WORKDIR /app

COPY . .

RUN pip install flask

EXPOSE 5000

CMD [&quot;python&quot;, &quot;app.py&quot;]

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</code></pre>

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

<h3>Replicação de Imagens</h3>

<p>Harbor permite replicar imagens automaticamente entre registries. Vá em <strong>Administration → Registries</strong> 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.</p>

<h2>GitHub Container Registry (GHCR): Integração Nativa com GitHub</h2>

<h3>Entendendo GHCR e Quando Usá-lo</h3>

<p>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.</p>

<p>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.</p>

<h3>Autenticação e Push com GitHub Actions</h3>

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

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

<pre><code class="language-yaml"># .github/workflows/docker-publish.yml

name: Docker Publish

on:

push:

branches:

  • main

tags:

  • &#039;v*&#039;

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 }}</code></pre>

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

<h3>Usando Imagens do GHCR</h3>

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

<pre><code class="language-yaml">apiVersion: v1

kind: Secret

metadata:

name: ghcr-secret

type: kubernetes.io/dockercfg

data:

.dockercfg: &lt;BASE64_ENCODED_DOCKER_CONFIG&gt;

---

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</code></pre>

<p>Para gerar o secret, você pode usar:</p>

<pre><code class="language-bash">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 &gt; ghcr-secret.yaml</code></pre>

<h2>AWS ECR: Container Registry Gerenciado</h2>

<h3>Arquitetura e Benefícios do ECR</h3>

<p>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.</p>

<p>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.</p>

<h3>Criando Repositório e Fazendo Push</h3>

<p>Primeiro, crie um repositório ECR via AWS CLI:</p>

<pre><code class="language-bash">aws ecr create-repository \

--repository-name meu-projeto/app \

--region us-east-1 \

--image-scanning-configuration scanOnPush=true \

--encryption-configuration encryptionType=AES</code></pre>

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

<pre><code class="language-bash"># Obter URI do ECR

ECR_URI=$(aws ecr describe-repositories \

--repository-names meu-projeto/app \

--region us-east-1 \

--query &#039;repositories[0].repositoryUri&#039; \

--output text)

Fazer login

aws ecr get-login-password --region us-east-1 | \

docker login --username AWS --password-stdin $ECR_URI</code></pre>

<p>Build e push da imagem:</p>

<pre><code class="language-bash"># 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</code></pre>

<h3>Integração com ECS e EKS</h3>

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

<pre><code class="language-json">{

&quot;family&quot;: &quot;meu-app-task&quot;,

&quot;networkMode&quot;: &quot;awsvpc&quot;,

&quot;requiresCompatibilities&quot;: [&quot;FARGATE&quot;],

&quot;cpu&quot;: &quot;256&quot;,

&quot;memory&quot;: &quot;512&quot;,

&quot;containerDefinitions&quot;: [

{

&quot;name&quot;: &quot;meu-app&quot;,

&quot;image&quot;: &quot;123456789012.dkr.ecr.us-east-1.amazonaws.com/meu-projeto/app:v1.0&quot;,

&quot;portMappings&quot;: [

{

&quot;containerPort&quot;: 5000,

&quot;hostPort&quot;: 5000,

&quot;protocol&quot;: &quot;tcp&quot;

}

],

&quot;logConfiguration&quot;: {

&quot;logDriver&quot;: &quot;awslogs&quot;,

&quot;options&quot;: {

&quot;awslogs-group&quot;: &quot;/ecs/meu-app&quot;,

&quot;awslogs-region&quot;: &quot;us-east-1&quot;,

&quot;awslogs-stream-prefix&quot;: &quot;ecs&quot;

}

}

}

],

&quot;executionRoleArn&quot;: &quot;arn:aws:iam::123456789012:role/ecsTaskExecutionRole&quot;

}</code></pre>

<p>Para EKS, você precisará configurar um ImagePullSecret com credenciais ECR:</p>

<pre><code class="language-yaml">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: &lt;BASE64_DOCKER_AUTH&gt;

---

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</code></pre>

<h3>Policies IAM para Segurança</h3>

<p>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:</p>

<pre><code class="language-json">{

&quot;Version&quot;: &quot;2012-10-17&quot;,

&quot;Statement&quot;: [

{

&quot;Effect&quot;: &quot;Allow&quot;,

&quot;Action&quot;: [

&quot;ecr:GetDownloadUrlForLayer&quot;,

&quot;ecr:BatchGetImage&quot;,

&quot;ecr:PutImage&quot;,

&quot;ecr:InitiateLayerUpload&quot;,

&quot;ecr:UploadLayerPart&quot;,

&quot;ecr:CompleteLayerUpload&quot;

],

&quot;Resource&quot;: &quot;arn:aws:ecr:us-east-1:123456789012:repository/meu-projeto/*&quot;

},

{

&quot;Effect&quot;: &quot;Allow&quot;,

&quot;Action&quot;: &quot;ecr:GetAuthorizationToken&quot;,

&quot;Resource&quot;: &quot;*&quot;

}

]

}</code></pre>

<h2>Comparação Prática e Seleção da Melhor Opção</h2>

<p>Agora que você conhece os três, precisamos entender como escolher. A decisão não é sobre qual é &quot;melhor&quot;, mas qual se adequa melhor ao seu contexto.</p>

<p><strong>Harbor</strong> é 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.</p>

<p><strong>GHCR</strong> é 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.</p>

<p><strong>AWS ECR</strong> é 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.</p>

<p>Uma estratégia comum em grandes organizações é usar <strong>dois registries</strong>: 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.</p>

<h2>Conclusão</h2>

<p>Você aprendeu que <strong>não existe uma solução única para todos</strong>: 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 <strong>container registries privados não são apenas armazenamento</strong> — 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 <strong>a escolha influencia seu pipeline inteiro</strong>: um bom registry economiza horas em troubleshooting de pulls falhos, autenticação quebrada e imagens obsoletas.</p>

<h2>Referências</h2>

<ul>

<li><a href="https://goharbor.io/docs/" target="_blank" rel="noopener noreferrer">Documentação Oficial do Harbor</a></li>

<li><a href="https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry" target="_blank" rel="noopener noreferrer">GitHub Container Registry Documentation</a></li>

<li><a href="https://docs.aws.amazon.com/ecr/" target="_blank" rel="noopener noreferrer">AWS Elastic Container Registry Documentation</a></li>

<li><a href="https://github.com/opencontainers/distribution-spec" target="_blank" rel="noopener noreferrer">CNCF Container Registry Specification</a></li>

<li><a href="https://docs.docker.com/engine/security/" target="_blank" rel="noopener noreferrer">Docker Security Best Practices</a></li>

</ul>

<p>&lt;!-- FIM --&gt;</p>

Comentários

Mais em Docker & Kubernetes

O que Todo Dev Deve Saber sobre Gateway API em Kubernetes: O Futuro do Ingress
O que Todo Dev Deve Saber sobre Gateway API em Kubernetes: O Futuro do Ingress

O Que é Gateway API e Por Que Ela é o Futuro A Gateway API é uma evolução sig...

Como Usar Chaos Engineering em Kubernetes: LitmusChaos e Testes de Resiliência em Produção
Como Usar Chaos Engineering em Kubernetes: LitmusChaos e Testes de Resiliência em Produção

O que é Chaos Engineering e por que é Crítico em Kubernetes Chaos Engineering...

Guia Completo de CIS Benchmark para Kubernetes: Hardening e Auditoria de Cluster
Guia Completo de CIS Benchmark para Kubernetes: Hardening e Auditoria de Cluster

O que é CIS Benchmark para Kubernetes O CIS Benchmark (Center for Internet Se...