Docker ENTRYPOINT vs CMD — Seu Container Mentiu Para Você
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.
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:
| ENTRYPOINT | CMD | O que realmente é executado |
|---|---|---|
| Não definido | Não definido | Erro — o container precisa de um comando de algum lugar |
| Não definido | ["cmd", "arg"] forma exec | cmd arg |
| Não definido | cmd arg forma shell | /bin/sh -c "cmd arg" |
["entry"] forma exec | Não definido | entry |
["entry"] forma exec | ["arg1", "arg2"] forma exec | entry arg1 arg2 ✓ |
["entry"] forma exec | cmd arg forma shell | entry /bin/sh -c "cmd arg" — quase certamente errado |
entry forma shell | ["arg1"] forma exec | /bin/sh -c "entry" — CMD ignorada silenciosamente |
entry forma shell | cmd 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
ENTRYPOINTeCMDuse 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 myimageedocker run myimage --your-flagpara confirmar que ambas as rotas funcionam docker stop mycontainertermina 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.
Instale nossas extensões
Adicione ferramentas de IO ao seu navegador favorito para acesso instantâneo e pesquisa mais rápida
恵 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!
Ferramentas essenciais
Ver tudo Novas chegadas
Ver tudoAtualizar: Nosso ferramenta mais recente was added on Jun 26, 2026
