# ECR por IPv6: puxe uma imagem Docker numa rede dual stack

> Puxe uma imagem do ECR por IPv6 numa instância sem IPv4 e rode o contêiner na porta 80: endpoint dual stack, login e docker pull.

- Autor: Henrylle Maia, consultor AWS
- Publicado em: 2026-10-15
- Assuntos: Rede, Containers
- URL: https://pages.formacaoaws.com.br/blog/ecr-por-ipv6-docker-rede-dual-stack/
- Aula de origem: "Rede dual stack na AWS + IPV6 para uso com  ECR  + lançando aplicação com Docker em rede IPV6" (https://www.youtube.com/watch?v=fp4eonOtBTs)

Uma instância sem nenhum IPv4 consegue puxar uma imagem do Amazon ECR e rodar o contêiner? Consegue, desde que a AWS liberou o ECR para IPv6, e eu testei. Abaixo estão as duas mudanças que o login e o `docker pull` pedem e o teste que prova que o tráfego foi por IPv6.

No teste do ano passado o ECR não respondeu numa instância só com IPv6. A montagem da VPC, das subnets e do Egress-only Internet Gateway está no post sobre [IPv6 na AWS, dual stack e egress-only](https://pages.formacaoaws.com.br/blog/ipv6-na-aws-dual-stack/). Aqui eu não repito esse básico: parto dele e foco no que mudou.

## O que mudou: o ECR passou a falar IPv6

Na aula, mostrei a notícia de 2 de maio de 2025: o Amazon ECR adicionou suporte ao IPv6. Isso tira o bloqueio que eu tinha encontrado antes. Uma instância que só tem IPv6 pode conversar com o registro de imagens Docker.

O cenário do teste, em resumo:

- Uma VPC dual stack, com IPv4 e IPv6.
- Uma subnet pública e uma privada na zona A, as duas configuradas só com IPv6. Eu não queria que um IPv4 escondido fizesse o teste "funcionar por acaso".
- Na privada, a saída para a internet é o Egress-only Internet Gateway, que não tem custo e só deixa o tráfego sair.
- Duas EC2 `t3.micro` com Amazon Linux 2023, uma em cada subnet, com uma role que tem a policy do ECR (usei a Container Registry Power User).

A subnet privada não recebe entrada da internet. Por isso eu entro nela pela instância pública.

## Passo 1: ajuste o user data para IPv6

Eu uso um script de user data que instala Docker e outras coisas na EC2 (o do projeto BIA). Uma das etapas baixa o Docker Compose a partir do GitHub, e o GitHub não tem suporte a IPv6, então essa etapa não funciona numa instância só com IPv6.

Tirei essa parte e deixei a instalação do Docker. No fim, o Docker estava rodando nas duas instâncias, o que mostra que o user data funcionou em cima de IPv6.

> **Importante:** numa instância sem IPv4, tudo o que o script baixa precisa de suporte a IPv6. Revise o user data antes de lançar.

## Passo 2: entre nas instâncias e leve a chave junto

Usei SSH e não o Session Manager porque, quando gravei a aula, o SSM ainda não tinha suporte a IPv6. Com SSM não seria preciso abrir regra de entrada. Aqui abri a porta 22 e a porta 80 para IPv6 no Security Group da instância pública, só como prova de conceito. Na privada, a entrada de SSH vem apenas do Security Group da pública.

Para chegar à privada sem copiar a chave `.pem` para dentro de outra máquina, carrego a chave na sessão e uso o encaminhamento do agente (`-A`):

```bash
ssh-add <chave>.pem
ssh -A <usuário>@<IPv6 da instância pública>
ssh <usuário>@<IPv6 da instância privada>
```

O primeiro `ssh` leva a chave junto. O segundo, já dentro da pública, não precisa do `-i`. O `ifconfig` da instância pública, logo depois de entrar, mostra só o endereço IPv6.

## Passo 3: teste o ECR e prove que é IPv6

A [documentação do ECR sobre IPv6](https://docs.aws.amazon.com/AmazonECR/latest/userguide/ecr-requests.html) traz um comando de teste que lista os repositórios pela AWS CLI, já com o `--endpoint-url` do endpoint dual stack. Eu só troquei a região para a Virgínia e rodei de dentro da instância privada:

```bash
aws ecr describe-repositories --region us-east-1 --endpoint-url https://ecr.us-east-1.api.aws
```

Listou o repositório `bia`.

![A saída do describe-repositories na instância privada: o repositório bia, com o repositoryUri no formato dkr-ecr.us-east-1.on.aws/bia (conta borrada)](https://pages.formacaoaws.com.br/blog/assets/posts/ecr-por-ipv6-docker-rede-dual-stack/listagem-endpoint-dual-stack.webp)

Para provar que a chamada foi por IPv6, removi o Egress-only da route table da subnet privada. O comando parou de funcionar, porque a subnet ficou sem saída. Recoloquei a rota e a comunicação voltou quase na hora.

![A edição de rotas da route table privada: o destino ::/0 apontando para o Egress Only Internet Gateway, a rota que tirei e recoloquei no teste (prefixo IPv6 borrado)](https://pages.formacaoaws.com.br/blog/assets/posts/ecr-por-ipv6-docker-rede-dual-stack/rota-egress-only.webp)

## Passo 4: faça o login e o pull com o endpoint dual stack

Aqui está a mudança que importa. O comando de login do `View push commands` do ECR usa o endpoint padrão, que fala IPv4. Se você usar o padrão, a conexão tenta sair por IPv4 e não funciona. A documentação manda trocar por um endpoint dual stack em dois lugares:

1. No `aws ecr get-login-password`, com `--endpoint-url` apontando para o endpoint dual stack da região.
2. No endereço do registro, tanto no `docker login` quanto no `docker pull`.

```bash
aws ecr get-login-password --region us-east-1 --endpoint-url https://ecr.us-east-1.api.aws | docker login --username AWS --password-stdin <ID da conta>.dkr-ecr.us-east-1.on.aws
docker pull <ID da conta>.dkr-ecr.us-east-1.on.aws/<repositório>:<tag>
```

Os dois formatos vêm da [documentação do ECR](https://docs.aws.amazon.com/AmazonECR/latest/userguide/ecr-requests.html): `ecr.<região>.api.aws` para a API e `<ID da conta>.dkr-ecr.<região>.on.aws` para o registro. Troque a região pela sua. O login funcionou e o `docker pull` baixou a imagem do meu repositório privado nas duas instâncias: primeiro na privada, depois na pública.

![A documentação do ECR com os exemplos de docker pull: o endpoint IPv4 (dkr.ecr...amazonaws.com) e o dual stack (dkr-ecr.us-west-1.on.aws), com o trecho do dual stack selecionado](https://pages.formacaoaws.com.br/blog/assets/posts/ecr-por-ipv6-docker-rede-dual-stack/docs-endpoints-ecr.webp)

O `View push commands` ensina o `push`. Como eu queria baixar a imagem, usei o `pull` no lugar, mantendo o final do endereço da imagem que o ECR mostra.

## Passo 5: rode o contêiner e abra por IPv6

Na instância pública, que tem entrada liberada, subi a aplicação mapeando a porta 80 do host para a 8080 do contêiner:

```bash
docker run -d -p 80:8080 <ID da conta>.dkr-ecr.us-east-1.on.aws/<repositório>:<tag>
```

O `-d` roda em segundo plano. O `docker ps` mostrou a imagem rodando. Para abrir no navegador, copiei o endereço IPv6 da instância e coloquei entre colchetes na URL:

```
http://[<IPv6 da instância>]
```

A aplicação abriu, rodando 100% em cima de IPv6.

**Fluxo:** Instância (subnet privada, sem IPv4) → Egress-only Internet Gateway (saída sem entrada) → ECR (endpoint dual stack) → docker pull (imagem na instância) → Contêiner (porta 80 para 8080)

## Onde isso me deixa

Em um único teste, sem NAT Gateway e sem IPv4 nas instâncias, a imagem saiu do ECR, chegou na instância e virou contêiner acessível por IPv6. Os pontos que travaram foram o GitHub, que ainda não tem IPv6, e o SSM, que não tinha na época da gravação. Eu falei que ainda há limitações, mas dá para fazer muita coisa.

Eu não rodei o contêiner na instância privada: ela só tem saída, então a aplicação foi pela pública.

## Checklist

- Confira se o serviço que a instância vai chamar tem suporte a IPv6 antes de tirar o IPv4.
- Na subnet privada só com IPv6, aponte `::/0` para o Egress-only Internet Gateway.
- Revise o user data: tudo o que ele baixa precisa funcionar por IPv6 (o GitHub não funciona).
- Use o endpoint dual stack do ECR no `--endpoint-url`, no `docker login` e no `docker pull`.
- Para provar que a chamada foi por IPv6, remova a saída da route table e veja o comando falhar.
- Para abrir a aplicação no navegador, coloque o endereço IPv6 entre colchetes na URL.
- Em produção, restrinja a origem do SSH e da porta 80 em vez de abrir para todo IPv6.

Se você quer levar imagens e contêineres para uma rede IPv6 sem tropeçar nesses limites, vale revisar o desenho com alguém que já testou.
