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âmetroFunção
--tail 3Mostra apenas as últimas 3 linhas
-tAdiciona no início de cada linha o registro de data e hora do Docker
-fAcompanha continuamente os novos logs (como tail -f); pressione Ctrl + C para sair
--since 10mMostra 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 logs nã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
SintaxeFunção
docker exec -it web bashAbre um shell interativo (se a imagem enxuta não tiver bash, use sh)
docker exec web comandoExecuta 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:

A aba Exec do Docker Desktop
A aba Exec da página de detalhes do contêiner no Docker Desktop equivale a docker exec -it. Imagem: documentação oficial do Docker (Apache-2.0)

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 saberCampo
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 (pressione Ctrl + C para 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 comando ps (consulte Seu primeiro contêiner); com docker 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 -a mostra Exited (137)
  • docker inspect --format '{{.State.OOMKilled}}' nome-do-contêiner mostra true

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

  1. docker ps -a: o contêiner está em execução? Qual é o código de saída?
  2. docker logs contêiner (adicione 2>&1 | grep se necessário): o que o próprio programa informou?
  3. Compare o código de saída: 1 consulte os logs, 127 comando não encontrado, 137 encerrado à força ou OOM, 139 falha do programa (segfault).
  4. docker inspect: confirme se as variáveis de ambiente, montagens, portas e o comando executado estão como esperado.
  5. 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, consulte docker logs.
  • Use docker exec para entrar em um contêiner em execução e docker cp para copiar arquivos para fora dele.
  • Use docker inspect -f para consultar configurações e estado; docker stats mostra o uso de recursos.
  • Se o contêiner sair logo após iniciar, use --entrypoint sh para 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