# X-Ray com Docker: tracing de uma aplicação Node em 4 passos

> Rode o daemon do AWS X-Ray em container, integre o SDK ao Express e veja no console as requisições da sua aplicação por rota, tempo e status.

- Autor: Henrylle Maia, consultor AWS
- Publicado em: 2026-10-15
- Assuntos: Containers
- URL: https://pages.formacaoaws.com.br/blog/xray-docker-tracing-na-aplicacao/
- Aula de origem: "Como utilizar o AWS X-Ray com Docker para tracing em sua app" (https://www.youtube.com/watch?v=PFU278j4c2A)

Sua aplicação está com a CPU perto de 90% e os logs não dizem qual rota custa mais caro. Com o AWS X-Ray você manda para a AWS cada requisição, com rota, método, status e tempo de resposta, e enxerga isso agrupado no console. Aqui rodo o daemon do X-Ray em container ao lado de uma aplicação Node com React e mostro o resultado no Service Map.

> **Importante:** este vídeo foi publicado em 14/09/2023. A própria AWS informa que o SDK e o daemon do X-Ray entram em modo de manutenção em 25/02/2026, com releases só para correções de segurança, e recomenda migrar para o OpenTelemetry. Antes de copiar o que mostro, leia o [aviso na documentação oficial](https://docs.aws.amazon.com/xray/latest/devguide/xray-daemon.html) e o [guia de migração para OpenTelemetry](https://docs.aws.amazon.com/xray/latest/devguide/xray-sdk-migration.html). O que mostro aqui continua servindo para entender o conceito de trace.

## Por que log não basta e o trace resolve

Imagine uma aplicação web em dois servidores, de repente com 90% de uso de CPU. O primeiro nível de investigação é a máquina. O segundo é o log, no CloudWatch: você vê as requisições e o tempo de cada uma, 630 ms, 940 ms, 230 ms.

Só que, no volume de um log de produção, fica difícil dizer onde agir. Quais requisições custam mais? Qual rota recebe mais chamadas? Qual o tempo médio? Atendendo um cliente com a frota quase sempre em 100% de CPU, foi exatamente aí que o log deixou de bastar.

O **trace** é o nível seguinte. A aplicação se integra a um serviço que coleta as métricas e as compila. Na AWS esse serviço é o X-Ray. Numa rota como `GET /api/tarefas`, você passa a ver quantas requisições chegam, o tempo médio e o status de resposta.

**Fluxo:** Aplicação Node (SDK do X-Ray no Express) → Daemon em container (porta 2000 TCP e UDP) → AWS X-Ray (recebe os segmentos) → Console do X-Ray (Service Map e lista de traces)

## Por que usar Docker nesta prova de conceito

O X-Ray trabalha junto da aplicação por meio de um processo chamado daemon. A aplicação manda os dados para ele, e ele repassa ao X-Ray. Com Docker, essa peça roda igual em Windows, Linux ou Mac, e o ambiente fica simples de subir.

Usei a BIA, uma aplicação Node com React que já roda com Docker, com `Dockerfile` e `docker-compose.yml`. Clonei o projeto, entrei na pasta e criei uma branch chamada `xray`:

```bash
git checkout -b xray
```

## Passo 1: criar o Dockerfile do daemon

Criei o arquivo `Dockerfile_xray_daemon`. A estrutura vem da própria documentação da AWS: instala o `unzip`, baixa o daemon, extrai, copia o executável e expõe a porta 2000, em TCP e UDP.

```dockerfile
FROM amazonlinux
RUN yum install -y unzip
RUN curl -o daemon.zip <URL do daemon na documentação da AWS>
RUN unzip daemon.zip && cp xray /usr/bin/xray
ENTRYPOINT ["/usr/bin/xray", "-t", "0.0.0.0:2000", "-b", "0.0.0.0:2000"]
EXPOSE 2000/udp
EXPOSE 2000/tcp
```

A URL de download eu copiei da documentação e não reproduzo aqui, porque a versão do daemon muda. Pegue a atual na [página do daemon](https://docs.aws.amazon.com/xray/latest/devguide/xray-daemon.html).

![Serviço xray_daemon no docker-compose: build do Dockerfile_xray_daemon, container xray, AWS_REGION us-east-1, command --local-mode, portas 2000 e volume ~/.aws](https://pages.formacaoaws.com.br/blog/assets/posts/xray-docker-tracing-na-aplicacao/xray-daemon-no-compose.webp)

## Passo 2: subir o daemon junto da aplicação no Compose

No `docker-compose.yml` já havia os serviços `server` e `database`. Criei um serviço novo, `xray_daemon`, para subir junto:

- **build:** o `Dockerfile_xray_daemon`, com o diretório atual como contexto;
- **container_name:** `xray`;
- **environment:** `AWS_REGION` com `us-east-1`, a região para onde vão os dados;
- **command:** `--local-mode`, porque na documentação da AWS esse modo faz o daemon não checar se está numa máquina EC2, e aqui estou rodando local;
- **ports:** a 2000, em TCP e UDP;
- **volumes:** a pasta de credenciais da AWS da minha máquina, para o daemon saber para qual conta enviar.

No volume, usei o profile padrão do `aws configure`, de um usuário com permissão de administrador. Para o X-Ray, o mínimo é a permissão de administração do X-Ray, e usei a de administrador geral só no teste.

> **Importante:** dar permissão de administrador e compartilhar a pasta de credenciais com o container serve só para teste local. Ao rodar na AWS, use uma IAM role com a política do X-Ray e nada além disso. Na EC2, o daemon usa o perfil de instância da máquina sozinho, sem chave de acesso. Veja [como dar ao daemon permissão para enviar dados ao X-Ray](https://docs.aws.amazon.com/xray/latest/devguide/xray-daemon.html#xray-daemon-permissions) na documentação oficial.

No serviço `server`, fiz três ajustes para ele enxergar o daemon:

- `depends_on` apontando para o `xray_daemon`, para o daemon subir antes;
- `links` com o `xray_daemon`, para a aplicação resolver o endereço dele;
- a variável `AWS_XRAY_DAEMON_ADDRESS` com `xray_daemon:2000`, junto de `AWS_REGION` com `us-east-1`.

Depois deixei tudo commitado na branch `xray`.

## Passo 3: integrar o SDK do X-Ray ao Express

A aplicação precisa do SDK do X-Ray; há um para JavaScript, e também para .NET, Java e outras linguagens. Para Node:

```bash
npm install --save aws-xray-sdk
```

No `express.js`, importei o SDK e abri um segmento no início da configuração, dando o nome `bia`. No fim, depois de registrar as rotas, fechei o segmento. O X-Ray coleta o que acontece nesse intervalo.

```javascript
var AWSXray = require("aws-xray-sdk");

app.use(AWSXray.express.openSegment("bia"));
// ...rotas da aplicação...
app.use(AWSXray.express.closeSegment());
```

É uma integração simples, só para ver o funcionamento.

![express.js importando aws-xray-sdk na linha 6 e abrindo o segmento com AWSXray.express.openSegment("bia") na linha 11](https://pages.formacaoaws.com.br/blog/assets/posts/xray-docker-tracing-na-aplicacao/sdk-no-express.webp)

## Passo 4: gerar a imagem, subir e ver o resultado

Como mudei a aplicação, gerei uma nova imagem do `server` (antes parei tudo com `docker compose down`):

```bash
docker compose down
docker compose build server
docker compose up -d
docker logs -f xray
```

No log do container `xray`, a confirmação de que deu certo é a mensagem de envio de um batch de segmentos para o X-Ray. Depois abri a aplicação em `localhost:3001` e cadastrei, alterei e apaguei algumas tarefas para gerar requisições.

No console, em **CloudWatch**, **X-Ray traces**, **Service map**, o mapa apareceu: 2 traces por minuto, 100% das requisições OK e latência média de 8 ms.

![Service Map do X-Ray com o serviço bia: Ok 100%, 2.00 t/min, latência média de 8 ms e 0.00 falhas por minuto](https://pages.formacaoaws.com.br/blog/assets/posts/xray-docker-tracing-na-aplicacao/service-map.webp)

Em **Traces** estão as requisições, com as rotas que chegaram. Dá para refinar por URL e ver o percentual de cada rota, o tempo de resposta e o método de cada uma. Na AWS, também dá para agrupar por instância. Foram 10 traces nesse teste.

![Lista de 10 traces com duração de 0,003 s a 0,029 s, método HTTP e URL de cada requisição à API de tarefas](https://pages.formacaoaws.com.br/blog/assets/posts/xray-docker-tracing-na-aplicacao/lista-de-traces.webp)

Com isso, a decisão sobre onde atuar passa a vir de dado agrupado, e não de uma pilha de linhas de log.

## O que esta prova de conceito ainda não mostra

O mapa mostra só a camada web. A BIA conversa com um banco, e essa camada não foi integrada aqui. Com ela no Service Map, você identifica se o gargalo está no banco. Fica como evolução do projeto.

## Checklist

- [ ] Entendi a diferença entre olhar a máquina, olhar o log e olhar o trace.
- [ ] Criei o Dockerfile do daemon do X-Ray, expondo a porta 2000 em TCP e UDP.
- [ ] Adicionei o serviço do daemon no Compose, com `--local-mode` e a região.
- [ ] Configurei `depends_on`, `links` e `AWS_XRAY_DAEMON_ADDRESS` no serviço da aplicação.
- [ ] Instalei o SDK e abri e fechei o segmento no Express.
- [ ] Refiz a imagem, subi o Compose e vi o Service Map e a lista de traces.
- [ ] Conferi o aviso de manutenção e o caminho de migração para OpenTelemetry na documentação.
