# Enviar imagem Docker para o ECR com IAM role, sem access key

> Gere a imagem Docker numa EC2 e envie ao Amazon ECR com uma IAM role na instância, sem access key. Inclui o erro de disco cheio no build.

- Autor: Henrylle Maia, consultor AWS
- Publicado em: 2026-10-15
- Assuntos: Containers, Segurança
- URL: https://pages.formacaoaws.com.br/blog/enviar-imagem-docker-para-o-ecr-com-iam-role/
- Aula de origem: "AMBIENTE COM DOCKER NA AWS INTEGRADO AO VS CODE A CUSTO ZERO + EXECUÇÃO DE PROJETO - PARTE 1" (https://www.youtube.com/watch?v=eMUOQ_5LsQc)

Uma imagem Docker que só existe na sua máquina de trabalho não serve para um cluster: o ECS, o Kubernetes e o Elastic Beanstalk precisam puxá-la de um repositório remoto. Aqui você gera a imagem numa EC2, dá a ela uma IAM role com permissão no Amazon ECR e envia, sem criar access key e sem guardar credencial na máquina.

Gravei essa aula em julho de 2024, em duas partes. Na [parte 1](https://www.youtube.com/watch?v=eMUOQ_5LsQc) subi a máquina de trabalho e rodei o projeto; na [parte 2](https://www.youtube.com/watch?v=TPpekCjU0sg) tirei a imagem dela e enviei para o ECR, e é dela que vêm a role, o repositório e o `build.sh`.

> **Importante:** o título das aulas diz "custo zero", e isso dependia da Free Tier da época. As regras mudaram, e desde 1º de fevereiro de 2024 a AWS cobra todo IPv4 público. Veja [Nova Free Tier da AWS](https://pages.formacaoaws.com.br/blog/nova-free-tier-da-aws/) e confira a [página oficial](https://aws.amazon.com/free/) antes de contar com custo zero.

## O ponto de partida

Parto da máquina de trabalho montada em [Docker na AWS com VS Code Remote SSH](https://pages.formacaoaws.com.br/blog/ambiente-docker-na-aws-com-vs-code-remote-ssh/): uma EC2 com Docker, Git e Node instalados por user data e o VS Code conectado por SSH. Em 2024 usei Amazon Linux numa T3 micro na zona A, com 10 GB de disco e o usuário `ec2-user`; o script do user data está na pasta `scripts` do [repositório `henrylle/bia`](https://github.com/henrylle/bia).

## Rodar o projeto com Docker Compose

O projeto tem um `docker-compose.yml` que mapeia a porta 3001 da instância para a 8080 do container:

![docker-compose.yml do projeto, com o serviço server e a linha de portas 3001:8080](https://pages.formacaoaws.com.br/blog/assets/posts/enviar-imagem-docker-para-o-ecr-com-iam-role/compose-portas-3001-8080.webp)

O Compose procura o `Dockerfile` na raiz e constrói a imagem linha por linha: parte de uma imagem do Node, instala o NPM mais recente, copia o `package.json`, instala as dependências, copia o código e gera o build do React. Depois sobe os containers:

```bash
docker compose up -d
```

No VS Code, encaminhe a porta **3001** na aba **Ports**. Sem esse encaminhamento, o `localhost:3001` não responde.

Ao salvar uma tarefa, a chamada à API ia para um IP público, e não para o `localhost`. O Dockerfile tinha o endereço da API do React apontando para esse IP. Troquei por `http://localhost:3001`:

![Linha 12 do Dockerfile com REACT_APP_API_URL=http://localhost:3001 no comando de build do React](https://pages.formacaoaws.com.br/blog/assets/posts/enviar-imagem-docker-para-o-ecr-com-iam-role/dockerfile-api-localhost-3001.webp)

Como mudei o Dockerfile, reconstruí o servidor e recriei os containers. Reconstruir a imagem sozinho não basta: o container antigo continua rodando até você derrubar e subir de novo.

```bash
docker compose build server
docker compose down
docker compose up -d
```

Depois disso, a aplicação salvou os dados no banco, que também roda em container.

## Por que a imagem precisa sair da máquina

No ECS, o cluster é o poder computacional. O service usa uma task definition, e é nela que ficam as informações da imagem que cada task vai rodar. Se a imagem só existe na instância de trabalho, o cluster não consegue puxá-la. Para quebrar essa dependência, preciso de duas coisas: um repositório no ECR e permissão para a instância enviar imagem para ele.

![A máquina BIA-DEV, na zona A da VPC, com uma role que permite enviar a imagem ao ECR; o ECR entrega a imagem ao service do cluster ECS, na zona B](https://pages.formacaoaws.com.br/blog/assets/posts/enviar-imagem-docker-para-o-ecr-com-iam-role/desenho-bia-dev-ecr-cluster.svg)

## Passo 1: criar a role com permissão no ECR

No IAM, crie uma role para o serviço **EC2** e anexe a policy gerenciada de Container Registry Power User (`AmazonEC2ContainerRegistryPowerUser`). Eu procurei pelo `PutImage` e vi que ela traz a permissão de push. Dei o nome `role-aula-docker`.

Depois, no console do EC2, clique com o botão direito na instância e vá em **Security, Modify IAM role**. Escolha a role e atualize.

Pronto: a instância tem permissão para enviar imagem ao ECR, e eu não criei nenhuma access key. Rodar o AWS CLI com chaves de acesso é a forma insegura de fazer isso. Veja a [documentação de roles para instâncias EC2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html) e a [lista de policies do ECR](https://docs.aws.amazon.com/AmazonECR/latest/userguide/security-iam-awsmanpol.html).

## Passo 2: criar o repositório no ECR

No ECR, crie um repositório **privado** chamado `aula-docker`. Ao criar, o botão **View push commands** mostra os comandos de login, build, tag e push com o endereço do seu repositório. Foi daí que montei o script.

## Passo 3: montar o build.sh e enviar

Na pasta do projeto criei o `build.sh` com os quatro comandos que o console mostrou, trocando o placeholder pelo ID da sua conta:

```bash
aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin <id-da-conta>.dkr.ecr.us-east-1.amazonaws.com
docker build -t aula-docker .
docker tag aula-docker:latest <id-da-conta>.dkr.ecr.us-east-1.amazonaws.com/aula-docker:latest
docker push <id-da-conta>.dkr.ecr.us-east-1.amazonaws.com/aula-docker:latest
```

O primeiro autentica no repositório, sem access key, pela role da instância. O segundo gera a imagem a partir do Dockerfile do diretório atual. O terceiro aplica a tag com o endereço do repositório, e o quarto envia. Usei sempre a tag `latest`; dá para trabalhar com tags de versão para ter rollback, mas isso ficou fora da aula.

```bash
chmod +x build.sh
./build.sh
```

## Passo 4: se o build falhar com "no space left on device"

Na primeira execução o login passou, mas o build quebrou na etapa do `COPY` com `no space left on device`, e o push falhou porque a imagem não existia. A instância tinha 10 GB e ficou sem espaço. Para liberar, derrubei o Compose com os volumes, removi a imagem do servidor e limpei o Docker:

```bash
docker compose down -v
docker rmi <imagem-do-servidor>
docker system prune
```

O prune recuperou 1,6 GB. Rodei o `./build.sh` de novo e o fluxo completo passou: login, build, tag e push.

No ECR, a imagem apareceu com 310 MB. O push anunciava uns 400 MB, mas as camadas que o repositório já tinha, como a do Node, não são enviadas de novo. Na aula, comentei que a Free Tier da época cobria até 500 MB de ECR; confira o valor atual na [página de preços do ECR](https://aws.amazon.com/ecr/pricing/).

A partir daí a imagem tem um endereço no ECR e serve para o Elastic Beanstalk, o ECS ou qualquer outro serviço: basta apontar para ela. Terminada a prática, você pode remover a instância.

**Fluxo:** Role na instância (policy do ECR) → build.sh (login, build, tag e push) → Repositório no ECR (aula-docker) → Cluster ECS (vai puxar a imagem)

O próximo passo é [criar o cluster, o service e a task definition no ECS](https://pages.formacaoaws.com.br/blog/ecs-cluster-service-task-definition/). Para a versão que usa um usuário IAM com chave no lugar da role, veja [o primeiro container em produção no ECS](https://pages.formacaoaws.com.br/blog/primeiro-container-em-producao-no-ecs/).

## Checklist

- Rode o projeto com `docker compose up -d` e encaminhe a porta 3001 pelo VS Code.
- Se mudar o endereço da API no Dockerfile, reconstrua a imagem, derrube e suba o Compose de novo.
- Crie uma role para EC2 com a policy do ECR e associe à instância em Modify IAM role.
- Crie o repositório privado no ECR e copie os push commands.
- Monte o `build.sh` com login, build, tag e push, e rode com `chmod +x` e `./build.sh`.
- Se faltar espaço, `docker compose down -v`, `docker rmi` e `docker system prune`.
- Confira a imagem no repositório e as regras da Free Tier nas páginas oficiais.

Com a role na instância, a imagem sai da máquina de trabalho sem nenhuma chave de acesso para guardar ou vazar.
