Anúncios incomodam? Ir Sem anúncios Hoje

Docker ENTRYPOINT vs CMD — Seu Container Mentiu Para Você

Atualizado em

Você combinou ENTRYPOINT e CMD no seu Dockerfile, o container iniciou a coisa errada e agora você está aqui. Aqui está a explicação completa — todas as combinações, o engano com shell versus forma exec, e os padrões que realmente funcionam.

Docker ENTRYPOINT vs CMD — Seu Container Mentiu Para Você 1
ANUNCIADO Remover?

O erro ocorre às 2h. Você inicia o container e, em vez do servidor da API, recebe um prompt de shell. Ou nada do tudo. Ou o processo executa envolvido em um fantasma sh que come SIGTERM como doces — a desligamento gracioso leva 10 segundos de espera do Docker antes de desistir e enviar SIGKILL.

O culpado, quase sempre: você confundiu ENTRYPOINT e CMD. Ou os combinou de maneiras que o Docker aceita silenciosamente — apenas não da forma que você esperava.

CMD: O Valor Padrão que Pode Ser Substituído

CMD define o que é executado quando você inicia um container — mas é uma sugestão, não uma regra. Qualquer coisa após o nome da imagem é substituída completamente:

FROM ubuntu
CMD ["echo", "hello from CMD"]
$ docker run myimage
hello from CMD

$ docker run myimage echo goodbye
goodbye

Que echo goodbye não foi concatenado — foi substituído. Seu todo CMD está perdido. Isso é por design: CMD é o comportamento padrão, não o comportamento obrigatório. Qualquer argumento de tempo de execução vence.

ENTRYPOINT: A Parte que Sempre é Executada

ENTRYPOINT define o executável que é executado independentemente de qualquer coisa. Os argumentos de tempo de execução não o substituem — eles são passados para ele em vez disso:

FROM ubuntu
ENTRYPOINT ["echo"]
CMD ["hello"]
$ docker run myimage
hello

$ docker run myimage goodbye
goodbye

$ docker run --entrypoint cat myimage /etc/hostname
mycontainer-abc123

Quando ambos estão definidos, ENTRYPOINT é o executável e CMD torna-se seus argumentos padrão. Você pode sobrescrever CMD livremente. Você pode sobrescrever ENTRYPOINT apenas se passar explicitamente --entrypoint.

Cada combinação de ENTRYPOINT + CMD, Explicada

Os documentos do Docker incluem esta tabela, mas não destacam as linhas que causam problemas no seu dia a dia:

ENTRYPOINTCMDO que realmente é executado
Não definidoNão definidoErro — o container precisa de um comando de algum lugar
Não definido["cmd", "arg"] forma execcmd arg
Não definidocmd arg forma shell/bin/sh -c "cmd arg"
["entry"] forma execNão definidoentry
["entry"] forma exec["arg1", "arg2"] forma execentry arg1 arg2
["entry"] forma execcmd arg forma shellentry /bin/sh -c "cmd arg" — quase certamente errado
entry forma shell["arg1"] forma exec/bin/sh -c "entry"CMD ignorada silenciosamente
entry forma shellcmd arg forma shell/bin/sh -c "entry"CMD ignorada silenciosamente

As duas linhas marcadas como "CMD ignorada silenciosamente" são responsáveis por uma grande parte das sessões de depuração do Docker. Forma shell ENTRYPOINT não se combina com CMD — ignora completamente. O Docker não te avisa sobre isso.

Forma Shell vs Forma Exec: A Armadilha de Tratamento de Sinais

Ambas as instruções aceitam duas formas, e a escolha importa mais do que a maioria dos tutoriais de Dockerfile admite.

Forma exec (sintaxe de array):

ENTRYPOINT ["nginx", "-g", "daemon off;"]

O seu binário é executado diretamente. Ele se torna o PID 1. Quando o Docker envia SIGTERM para parar o container, seu processo recebe o sinal. O desligamento gracioso funciona. Os logs são flushados. As conexões são fechadas com limpeza.

Formato de Shell (string simples):

ENTRYPOINT nginx -g "daemon off;"

O Docker executa isso como /bin/sh -c "nginx -g daemon off;". A shell é o PID 1. Quando SIGTERM chega, sh recebe o sinal — e sh não passa os sinais para os processos filhos. O container fica parado por 10 segundos, recebe SIGKILLe morre sem limpeza. Cada vez que isso acontece.

Use a forma exec. Sempre. Para ambos ENTRYPOINT e CMD.

Três Modelos que Funcionam de Fato

Modelo 1: Executável fixo, com padrões reutilizáveis

O padrão correto para a maioria dos containers em produção. O binário é fixo; as flags são trocáveis no tempo de execução:

ENTRYPOINT ["/app/server"]
CMD ["--port", "8080", "--env", "production"]
# Use defaults
docker run myimage

# Override at deploy time
docker run myimage --port 9090 --env staging

Modelo 2: Script de envoltório com exec

Quando você precisa de lógica inicial antes do seu processo principal (migrações, injeção de segredos, captura de sinais), use um script de envoltório. A linha crítica é exec "$@" no final — ela substitui o processo de shell pelo seu CMD, então o binário se torna o PID 1:

#!/bin/sh
set -e

echo "Running migrations..."
/app/migrate

# Hand off to CMD — exec replaces shell, so /app/server becomes PID 1
exec "$@"
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
CMD ["/app/server", "--port", "8080"]

Se você pular exec "$@", a shell permanece como PID 1 e você volta aos problemas de tratamento de sinais.

Modelo 3: Apenas CMD, sem ENTRYPOINT

Adequado para imagens de desenvolvimento ou containers de ferramentas onde você deseja executar comandos arbitrários no mesmo ambiente:

FROM python:3.12-slim
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt
CMD ["python", "app.py"]

Para produção, o Modelo 1 ou 2 é mais seguro — você não quer que um script mal configurado execute acidentalmente docker run myimage bash e substitua seu servidor por uma sessão de shell.

O que o docker exec tem a ver com isso

Nada. docker exec executa um comando em um container já em execução. Ele pula completamente ENTRYPOINT . Você não precisa pensar sobre ENTRYPOINT quando você executa docker exec mycontainer bash para explorar — você está falando com o ambiente ativo do container, não com a configuração de inicialização.

A confusão geralmente vem de pessoas que usam docker exec para depurar e confirmam que tudo funciona, depois se perguntam por que docker run comporta-se de forma diferente. São caminhos de código completamente separados.

Lista de Verificação Antes do Envio

  • Ambos ENTRYPOINT e CMD use a forma exec (sintaxe de array, não strings simples)
  • Se você tiver um script de envoltório, ele termina com exec "$@"
  • Você testou docker run myimage e docker run myimage --your-flag para confirmar que ambas as rotas funcionam
  • docker stop mycontainer termina em menos de 2 segundos (não em 10 — se for 10, você tem um problema de sinal)

Se você quiser feedback automático antes de seu Dockerfile chegar perto de um registro, IO Tools’ Dockerfile Linter detecta o uso da forma shell, falta de exec em scripts de entrypoint e outros padrões que causam comportamento silencioso em tempo de execução.

Quer eliminar anúncios? Fique sem anúncios hoje mesmo

Instale nossas extensões

Adicione ferramentas de IO ao seu navegador favorito para acesso instantâneo e pesquisa mais rápida

Ao Extensão do Chrome Ao Extensão de Borda Ao Extensão Firefox Ao Extensão Opera

O placar chegou!

Placar é uma forma divertida de acompanhar seus jogos, todos os dados são armazenados em seu navegador. Mais recursos serão lançados em breve!

ANUNCIADO Remover?
ANUNCIADO Remover?
ANUNCIADO Remover?

Notícias com destaques técnicos

Envolver-se

Ajude-nos a continuar fornecendo ferramentas gratuitas valiosas

Compre-me um café
ANUNCIADO Remover?