Conteúdo
Depuração de contêineres: docker logs, exec, inspect, cp, stats
Como os contêineres são executados em segundo plano, os erros não aparecem diretamente na tela. Esta seção reúne as ferramentas de depuração mais usadas e reproduz alguns erros comuns. Todos os exemplos desta seção usam um contêiner nginx:
docker run -d --name web -p 8080:80 nginx:1.30
Consultar logs: docker logs
Você pode consultar com docker logs o conteúdo que o processo principal do contêiner envia para a saída padrão (stdout) e para a saída de erro padrão (stderr). Primeiro, faça algumas requisições ao nginx (os caminhos /page1 a /page3 não existem) e depois consulte os logs:
$ docker logs --tail 3 web
2026/10/12 23:52:59 [error] 28#28: *3 open() "/usr/share/nginx/html/page3" failed (2: No such file or directory), client: 172.18.0.1, server: localhost, request: "GET /page3 HTTP/1.1", host: "localhost:8080"
172.18.0.1 - - [12/Oct/2026:23:52:59 +0000] "GET /page3 HTTP/1.1" 404 153 "-" "curl/8.22.0" "-"
172.18.0.1 - - [12/Oct/2026:23:52:59 +0000] "GET / HTTP/1.1" 200 896 "-" "curl/8.22.0" "-"
$ docker logs --tail 2 -t web
2026-10-12T23:52:59.403434333Z 172.18.0.1 - - [12/Oct/2026:23:52:59 +0000] "GET /page3 HTTP/1.1" 404 153 "-" "curl/8.22.0" "-"
2026-10-12T23:52:59.503902089Z 172.18.0.1 - - [12/Oct/2026:23:52:59 +0000] "GET / HTTP/1.1" 200 896 "-" "curl/8.22.0" "-"
| Parâmetro | Função |
|---|---|
--tail 3 | Mostra apenas as últimas 3 linhas |
-t | Adiciona no início de cada linha o registro de data e hora do Docker |
-f | Acompanha continuamente os novos logs (como tail -f); pressione Ctrl + C para sair |
--since 10m | Mostra apenas os últimos 10 minutos (você também pode informar 2026-10-12T23:00:00) |
Você também pode consultar os logs depois que o contêiner parar. Esse é o primeiro passo para investigar “por que ele parou”.
stdout e stderr
Ao salvar os logs em um arquivo, você vai notar algo estranho:
$ docker logs --since 1m web > out.log; wc -l out.log
2026/10/12 23:52:57 [notice] 1#1: using the "epoll" event method
2026/10/12 23:52:57 [notice] 1#1: nginx/1.30.5
2026/10/12 23:52:57 [notice] 1#1: built by gcc 14.2.0 (Debian 14.2.0-19)
2026/10/12 23:52:57 [notice] 1#1: OS: Linux 5.4.0-216-generic
2026/10/12 23:52:57 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2026/10/12 23:52:57 [notice] 1#1: start worker processes
2026/10/12 23:52:57 [notice] 1#1: start worker process 28
2026/10/12 23:52:59 [error] 28#28: *1 open() "/usr/share/nginx/html/page1" failed (2: No such file or directory), client: 172.18.0.1, server: localhost, request: "GET /page1 HTTP/1.1", host: "localhost:8080"
2026/10/12 23:52:59 [error] 28#28: *2 open() "/usr/share/nginx/html/page2" failed (2: No such file or directory), client: 172.18.0.1, server: localhost, request: "GET /page2 HTTP/1.1", host: "localhost:8080"
2026/10/12 23:52:59 [error] 28#28: *3 open() "/usr/share/nginx/html/page3" failed (2: No such file or directory), client: 172.18.0.1, server: localhost, request: "GET /page3 HTTP/1.1", host: "localhost:8080"
13 out.log
$ docker logs --since 1m web > all.log 2>&1; wc -l all.log
23 all.log
Mesmo usando > para redirecionar a saída para um arquivo, as mensagens de inicialização e os logs de erro do nginx continuam aparecendo na tela, e o arquivo contém apenas 13 linhas. Isso acontece porque docker logs mantém stdout e stderr separados: os registros de acesso do nginx são enviados para stdout, enquanto as mensagens de erro e de inicialização são enviadas para stderr. > redireciona apenas stdout; adicione 2>&1 para salvar ambos no arquivo (23 linhas). O mesmo vale ao filtrar logs com grep: docker logs web 2>&1 | grep error.
Se um programa gravar os logs em um arquivo dentro do contêiner (por exemplo,
/var/log/app.log),docker logsnão poderá exibi-los. Em geral, as imagens oficiais redirecionam os logs para stdout / stderr; também é recomendável que seus próprios programas gravem diretamente em stdout.
Acessar o contêiner: docker exec
Execute um comando dentro de um contêiner em execução:
$ docker exec web cat /etc/nginx/conf.d/default.conf | head -n 12
server {
listen 80;
listen [::]:80;
server_name localhost;
#access_log /var/log/nginx/host.access.log main;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
$ docker exec -u nginx web whoami
nginx
$ docker exec -e DEBUG=1 web sh -c "echo DEBUG=\$DEBUG"
DEBUG=1
| Sintaxe | Função |
|---|---|
docker exec -it web bash | Abre um shell interativo (se a imagem enxuta não tiver bash, use sh) |
docker exec web comando | Executa um único comando e retorna a saída diretamente ao seu terminal |
docker exec -u nginx web … | Executa como o usuário especificado |
docker exec -e KEY=VALUE web … | Define variáveis de ambiente |
exec inicia um processo adicional. Sair (exit) não interrompe o contêiner.
Se o contêiner encerrar logo após iniciar, você não poderá usar exec (ele não estará em execução). Nesse caso, use --entrypoint para iniciar um novo contêiner sem executar o serviço original e entre diretamente nele para investigar:
$ docker run --rm --entrypoint sh nginx:1.30 -c "ls /docker-entrypoint.d"
10-listen-on-ipv6-by-default.sh
15-local-resolvers.envsh
20-envsubst-on-templates.sh
30-tune-worker-processes.sh
No Docker Desktop, você também pode abrir um shell clicando na aba Exec depois de abrir o contêiner:

Consultar configurações e estado: docker inspect
docker inspect exibe a configuração completa e o estado do contêiner em JSON. Use --format para extrair os campos necessários:
$ docker inspect --format '{{.State.Status}} {{.State.ExitCode}}' web
running 0
$ docker inspect --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' web
172.18.0.2
$ docker inspect --format '{{json .HostConfig.PortBindings}}' web
{"80/tcp":[{"HostIp":"","HostPort":"8080"}]}
$ docker inspect --format '{{.Path}} {{.Args}}' web
/docker-entrypoint.sh [nginx -g daemon off;]
| O que você quer saber | Campo |
|---|---|
| Por que parou | .State.ExitCode, .State.Error, .State.OOMKilled |
| Quais diretórios estão montados | .Mounts |
| Variáveis de ambiente | .Config.Env |
| Comando executado de fato | .Path, .Args |
| Endereço IP | .NetworkSettings.Networks |
| Mapeamento de portas | .HostConfig.PortBindings |
| Número de reinicializações | .RestartCount |
Copiar arquivos: docker cp
Você pode copiar arquivos entre o host e o contêiner mesmo quando ele está parado:
$ docker cp web:/etc/nginx/nginx.conf ./nginx.conf
$ head -n 5 nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
$ echo "<h1>copied in</h1>" > index.html
$ docker cp ./index.html web:/usr/share/nginx/html/
$ curl -s http://localhost:8080
<h1>copied in</h1>
Isso é útil para consultar um arquivo de configuração ou colocar um arquivo temporariamente no contêiner para testar. Em produção, o correto é incluí-lo no Dockerfile ou montá-lo com um Volume.
Recursos e processos: docker stats, top, diff
$ docker stats --no-stream
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
4a43d09d0bcb web 0.00% 7.59MiB / 1.919GiB 0.39% 2.79kB / 2.5kB 15MB / 8.19kB 2
$ docker top web
PID USER TIME COMMAND
1180 root 0:00 nginx: master process nginx -g daemon off;
1238 101 0:00 nginx: worker process
docker stats: CPU, memória, rede e I/O de disco. Sem--no-stream, os dados são atualizados continuamente (pressioneCtrl + Cpara sair). Se não houver um limite de memória configurado, LIMIT corresponde à memória total do host (ou da máquina virtual do Docker Desktop).docker top: mostra os processos dentro do contêiner. A imagem do nginx não inclui o comandops(consulte Seu primeiro contêiner); comdocker top, você pode ver os processos de fora.
$ docker diff web
C /run
A /run/nginx.pid
C /etc
C /etc/nginx
C /etc/nginx/conf.d
C /etc/nginx/conf.d/default.conf
C /usr
C /usr/share
C /usr/share/nginx
C /usr/share/nginx/html
C /usr/share/nginx/html/index.html
C /var
C /var/cache
C /var/cache/nginx
A /var/cache/nginx/client_temp
A /var/cache/nginx/fastcgi_temp
A /var/cache/nginx/proxy_temp
A /var/cache/nginx/scgi_temp
A /var/cache/nginx/uwsgi_temp
docker diff lista os arquivos adicionados (A), modificados (C) ou removidos (D) na camada gravável do contêiner em comparação com a imagem original. Você verá que o index.html copiado há pouco com docker cp aparece como modificado. Já o default.conf foi alterado automaticamente pelo script de inicialização do nginx (para ativar o IPv6). Essas alterações desaparecem quando o contêiner é removido.
Problemas comuns na prática
O contêiner sai logo após iniciar
$ docker run -d --name broken postgres:18
Unable to find image 'postgres:18' locally
18: Pulling from library/postgres
ecc510c1e359: Already exists
4a3cafbebf6d: Pull complete
28ced28a309b: Pull complete
ab69e2551985: Pull complete
1f04dfa92b9f: Pull complete
5a487c9461a5: Pull complete
e0d4a6e58470: Pull complete
496ce2ef5b2f: Pull complete
c8145e79cc2b: Pull complete
d23c975c4693: Pull complete
06ea90d3bcc9: Pull complete
dc25540d793f: Pull complete
7967f593457f: Pull complete
Digest: sha256:74935e72241653ca55e0414067e6d8763aceb8a810eb51b452253ec3dcfc4336
Status: Downloaded newer image for postgres:18
05a9084084fc2b744e4414e95323159bbc7455a1872784176f7333d31e875bda
$ docker ps -a --filter name=broken
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
05a9084084fc postgres:18 "docker-entrypoint.s…" 4 seconds ago Exited (1) 4 seconds ago broken
$ docker logs broken
Error: Database is uninitialized and superuser password is not specified.
You must specify POSTGRES_PASSWORD to a non-empty value for the
superuser. For example, "-e POSTGRES_PASSWORD=password" on "docker run".
You may also use "POSTGRES_HOST_AUTH_METHOD=trust" to allow all
connections without a password. This is *not* recommended.
See PostgreSQL documentation about "trust":
https://www.postgresql.org/docs/current/auth-trust.html
Você pode achar que deu certo ao ver o ID do contêiner impresso por docker run -d, mas docker ps -a mostra que ele saiu (Exited (1)) poucos segundos depois. docker logs informa diretamente o motivo: POSTGRES_PASSWORD não foi definido. A ordem para investigar é sempre: consulte o estado com docker ps -a → veja o motivo com docker logs.
A porta já está em uso
$ docker run -d -p 8080:80 nginx:1.30
c7b7a64eab9314885fb41d5ac82352c519240a17ea2e2e53098a0536a3264e6c
docker: Error response from daemon: failed to set up container networking: driver failed programming external connectivity on endpoint youthful_aryabhata (aff407d4a63df5baee04263bfdc54732e45cb69016b909a8e809c9010d81e926): Bind for 0.0.0.0:8080 failed: port is already allocated
Run 'docker run --help' for more information
A porta 8080 do host já está ocupada pelo contêiner web. Observe que a primeira linha ainda mostra o ID do contêiner: ele foi criado, mas a inicialização falhou. Ele permanece com o estado Created em docker ps -a, então lembre-se de removê-lo. Solução: escolha outra porta no host (-p 8081:80) ou descubra quem está usando essa porta (docker ps; para programas que não são do Docker, use sudo lsof -i :8080).
Erro de formato do executável
$ docker run --rm --platform linux/arm64 alpine:3.23 uname -m
Unable to find image 'alpine:3.23' locally
3.23: Pulling from library/alpine
ace1621be7ff: Pull complete
Digest: sha256:85fe1e81d6758c208f3e1eed4338a1997e19d4be002d4dd32d3100c9a8c010a0
Status: Image is up to date for alpine:3.23
exec /bin/uname: exec format error
Este host usa amd64 (x86_64), mas você está forçando a execução de uma imagem arm64. O programa não consegue ser executado nessa CPU. Na prática, o caso mais comum é construir uma imagem em um Mac com Apple Silicon e executá-la em um host de nuvem x86 comum. Veja a solução em Imagens multiplataforma.
Memória insuficiente (OOM)
Quando um contêiner ultrapassa o limite definido por --memory, o kernel do Linux encerra o processo à força:
docker ps -amostraExited (137)docker inspect --format '{{.State.OOMKilled}}' nome-do-contêinermostratrue
Se você encontrar o código 137, mas OOMKilled for false, geralmente o processo foi encerrado à força por docker kill ou por um timeout de docker stop. Aumente --memory ou verifique se o programa tem um vazamento de memória.
no space left on device
O Docker está usando espaço demais em disco. Primeiro, use docker system df para conferir:
$ docker system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 6 2 1.026GB 757.3MB (73%)
Containers 3 2 122.9kB 4.096kB (3%)
Local Volumes 1 0 0B 0B
Build Cache 0 0 0B 0B
RECLAIMABLE é o espaço que pode ser liberado. Veja como fazer isso em Liberar espaço em disco.
Resumo do processo de diagnóstico
docker ps -a: o contêiner está em execução? Qual é o código de saída?docker logs contêiner(adicione2>&1 | grepse necessário): o que o próprio programa informou?- Compare o código de saída:
1consulte os logs,127comando não encontrado,137encerrado à força ou OOM,139falha do programa (segfault). docker inspect: confirme se as variáveis de ambiente, montagens, portas e o comando executado estão como esperado.docker run -it --rm --entrypoint sh imagem: entre no contêiner e execute os comandos manualmente para descobrir o que está faltando.
Resumo
- Primeiro, confira o estado e o código de saída em
docker ps -a; depois, consultedocker logs. - Use
docker execpara entrar em um contêiner em execução edocker cppara copiar arquivos para fora dele. - Use
docker inspect -fpara consultar configurações e estado;docker statsmostra o uso de recursos. - Se o contêiner sair logo após iniciar, use
--entrypoint shpara iniciar um novo contêiner e investigar manualmente.
Exercícios
Exercício 1: execute docker run --name broken alpine:3.23 ls /not-exist e use os métodos deste capítulo para descobrir por que ele falhou e qual foi o código de saída.
Resposta
docker ps -a --filter name=broken
docker logs broken
docker inspect -f "{{.State.ExitCode}}" broken
Os logs mostram ls: /not-exist: No such file or directory, e o código de saída é 1.
Exercício 2: inicie docker run -d --name w nginx:1.30-alpine, crie um arquivo dentro do contêiner e descubra qual comando lista os arquivos que mudaram no contêiner em relação à imagem.
Resposta
docker diff w. A indica adição, C alteração e D exclusão. Veja a explicação em Como funciona internamente.
Perguntas frequentes
O contêiner encerra logo após iniciar e não consigo entrar com exec. O que faço?
Confira primeiro docker logs contêiner; depois, inicie um novo contêiner com docker run --rm -it --entrypoint sh imagem e execute manualmente o comando original para ver o erro.
Há tantos logs em docker logs que não consigo ler tudo.
Use --tail 50 para ver apenas as últimas 50 linhas ou --since 10m para ver apenas os últimos 10 minutos. Você também pode combinar com 2>&1 | grep palavra-chave. Consulte todos os parâmetros em [docker logs](/pt/docker/docker-logs/).
Onde posso descobrir o significado de uma mensagem de erro?
Consulte [Lista de mensagens de erro comuns](/pt/docker/errors/), com saídas reais e soluções para 25 tipos de erro.
Atualizado 14 de outubro de 2026