Qual é a diferença entre CMD e ENTRYPOINT em um Dockerfile?

1698

No Dockerfiles, existem dois comandos semelhantes a mim: CMDe ENTRYPOINT. Mas acho que há uma diferença (sutil?) Entre eles - caso contrário, não faria sentido ter dois comandos para a mesma coisa.

A documentação declara para CMD

O principal objetivo de um CMD é fornecer padrões para um contêiner em execução.

e para ENTRYPOINT:

Um ENTRYPOINT ajuda a configurar um contêiner que você pode executar como um executável.

Então, qual é a diferença entre esses dois comandos?

Golo Roden
fonte
12
Esta postagem do blog tem uma boa descrição das diferenças e como elas podem ser usadas juntas: crosbymichael.com/dockerfile-best-practices.html .
Slm
2
^ isso! Obrigado @slm. Aqui está outra referência muito similar que pode ser um pouco mais up-to-date: docs.docker.com/reference/builder/#entrypoint
Adam Monsen
5
Tão confuso quanto a diferença entre ADDeCOPY
Raedwald 21/02
1
Este link fornece diferença entre RUN, CMD e ENTRYPOINT: goinbigdata.com/docker-run-vs-cmd-vs-entrypoint
prafi
1
@JaimeHablutzel A frase é faça um favor a si mesmo
Jonathan Komar

Respostas:

1737

O Docker tem um ponto de entrada padrão que é, /bin/sh -cmas não possui um comando padrão.

Quando você executa a janela de encaixe desta forma: docker run -i -t ubuntu bash o ponto de entrada é o padrão /bin/sh -c, a imagem é ubuntue o comando é bash.

O comando é executado através do ponto de entrada. ou seja, a coisa real que é executada é /bin/sh -c bash. Isso permitiu que o Docker fosse implementado RUNrapidamente, contando com o analisador do shell.

Mais tarde, as pessoas pediram para poder personalizar isso ENTRYPOINTe --entrypointforam introduzidas.

Tudo ubuntuo que se segue no exemplo acima é o comando e é passado para o ponto de entrada. Ao usar a CMDinstrução, é exatamente como se você estivesse fazendo docker run -i -t ubuntu <cmd>. <cmd>será o parâmetro do ponto de entrada.

Você também obterá o mesmo resultado se digitar esse comando docker run -i -t ubuntu. Você ainda iniciará um shell bash no contêiner por causa do Dockerfile do ubuntu especificar um CMD padrão:CMD ["bash"]

Como tudo é passado para o ponto de entrada, você pode ter um comportamento muito agradável com suas imagens. @Jiri exemplo é bom, mostra como usar uma imagem como um "binário". Ao usar ["/bin/cat"]como ponto de entrada e, em seguida docker run img /etc/passwd, executar , você recebe, /etc/passwdé o comando e é passado para o ponto de entrada para que a execução do resultado final seja simples /bin/cat /etc/passwd.

Outro exemplo seria ter qualquer CLI como ponto de entrada. Por exemplo, se você tem uma imagem de Redis, em vez de correr docker run redisimg redis -H something -u toto get key, você pode simplesmente ter ENTRYPOINT ["redis", "-H", "something", "-u", "toto"]e depois executar como este para o mesmo resultado: docker run redisimg get key.

creack
fonte
3
De modo nenhum. ENTRYPOINT define um metadado que pode (mas pode ser substituído) no tempo de execução; portanto, se você não alterar nada, após iniciar o contêiner, o resultado será o mesmo; no entanto, o RUN será executado no tempo de construção e não importa o que você fazer em tempo de execução, será aqui.
creack
8
Por padrão, não há ENTRYPOINT; se um shell é usado depende da forma usada do CMDcomando ( docs.docker.com/engine/reference/builder/#cmd ).
Blaisorblade 13/01
19
Obrigado por isso, o contexto histórico ajuda muito, pois eu estava lutando para lembrar as regras aparentemente misteriosas sobre o que é substituído e o que é acrescentado etc. Um ponto útil para os escritores de documentação técnica em todos os lugares: ajudar o leitor a construir um modelo mental do sistema, não basta fatos lista e cenários :-)
ashirley
84
Esta é uma resposta fabulosa. Eu acho que a documentação Docker deve adicionar isso em uma seção chamada CMDvs ENTRYPOINT.
Tarik
5
@ Webman No. São duas instruções diferentes. Se ambos existirem, o CMD será tratado como parâmetros do ENTRYPOINT.
Light.G
628

O ENTRYPOINTespecifica um comando que sempre será executado quando o contêiner for iniciado.

O CMDespecifica argumentos que serão alimentados para o ENTRYPOINT.

Se você quiser criar uma imagem dedicada a um comando específico, usará ENTRYPOINT ["/path/dedicated_command"]

Caso contrário, se desejar criar uma imagem para uso geral, você pode deixar ENTRYPOINTnão especificado e usá- CMD ["/path/dedicated_command"]lo, pois poderá substituir a configuração fornecendo argumentos para docker run.

Por exemplo, se o seu Dockerfile for:

FROM debian:wheezy
ENTRYPOINT ["/bin/ping"]
CMD ["localhost"]

A execução da imagem sem nenhum argumento fará ping no host local:

$ docker run -it test
PING localhost (127.0.0.1): 48 data bytes
56 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.096 ms
56 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.088 ms
56 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.088 ms
^C--- localhost ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.088/0.091/0.096/0.000 ms

Agora, executar a imagem com um argumento fará ping no argumento:

$ docker run -it test google.com
PING google.com (173.194.45.70): 48 data bytes
56 bytes from 173.194.45.70: icmp_seq=0 ttl=55 time=32.583 ms
56 bytes from 173.194.45.70: icmp_seq=2 ttl=55 time=30.327 ms
56 bytes from 173.194.45.70: icmp_seq=4 ttl=55 time=46.379 ms
^C--- google.com ping statistics ---
5 packets transmitted, 3 packets received, 40% packet loss
round-trip min/avg/max/stddev = 30.327/36.430/46.379/7.095 ms

Para comparação, se o seu Dockerfile for:

FROM debian:wheezy
CMD ["/bin/ping", "localhost"]

A execução da imagem sem nenhum argumento fará ping no host local:

$ docker run -it test
PING localhost (127.0.0.1): 48 data bytes
56 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.076 ms
56 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.087 ms
56 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.090 ms
^C--- localhost ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.076/0.084/0.090/0.000 ms

Mas executar a imagem com um argumento executará o argumento:

docker run -it test bash
root@e8bb7249b843:/#

Consulte este artigo de Brian DeHamer para obter mais detalhes: https://www.ctl.io/developers/blog/post/dockerfile-entrypoint-vs-cmd/

Daishi
fonte
219
The ENTRYPOINT specifies a command that will always be executed when the container starts. The CMD specifies arguments that will be fed to the ENTRYPOINT.é um bom resumo direto do ponto.
Jingguo Yao 4/16/16
1
ENTRYPOINT também pode ser substituído usando o sinalizador --entrypoint. por exemplo, janela de encaixe executar -é --entrypoint festa teste
seenimurugan
2
Gosto dos seus exemplos, é realmente útil!
Chau Giang
2
@Jingguo Yao: E se o CMD contiver um comando como - CMD ["nginx", "- g", "daemon", "off"]? Seria acorrentado?
KMC
@KMC CMD é o argumento padrão do ENTRYPOINT; você o substitui passando um novo argumento ao executar a imagem.
MGP
237

De acordo com os documentos do docker ,

As instruções CMD e ENTRYPOINT definem qual comando é executado ao executar um contêiner. Existem poucas regras que descrevem sua cooperação.

  1. O Dockerfile deve especificar pelo menos um CMDou ENTRYPOINTcomandos.
  2. ENTRYPOINT deve ser definido ao usar o contêiner como um executável.
  3. CMDdeve ser usado como uma maneira de definir argumentos padrão para um ENTRYPOINTcomando ou para executar um comando ad-hoc em um contêiner.
  4. CMD será substituído ao executar o contêiner com argumentos alternativos.

As tabelas abaixo mostram qual comando é executado para diferentes ENTRYPOINT/ CMDcombinações :

- No ENTRYPOINT

╔════════════════════════════╦═════════════════════════════╗
║ No CMD                     ║ error, not allowed          ║
╟────────────────────────────╫─────────────────────────────╢
║ CMD [“exec_cmd”, “p1_cmd”] ║ exec_cmd p1_cmd             ║
╟────────────────────────────╫─────────────────────────────╢
║ CMD [“p1_cmd”, “p2_cmd”]   ║ p1_cmd p2_cmd               ║
╟────────────────────────────╫─────────────────────────────╢
║ CMD exec_cmd p1_cmd        ║ /bin/sh -c exec_cmd p1_cmd  ║
╚════════════════════════════╩═════════════════════════════╝

- ENTRYPOINT exec_entry p1_entry

╔════════════════════════════╦══════════════════════════════════╗
║ No CMD                     ║ /bin/sh -c exec_entry p1_entry   ║
╟────────────────────────────╫──────────────────────────────────╢
║ CMD [“exec_cmd”, “p1_cmd”] ║ /bin/sh -c exec_entry p1_entry   ║
╟────────────────────────────╫──────────────────────────────────╢
║ CMD [“p1_cmd”, “p2_cmd”]   ║ /bin/sh -c exec_entry p1_entry   ║
╟────────────────────────────╫──────────────────────────────────╢
║ CMD exec_cmd p1_cmd        ║ /bin/sh -c exec_entry p1_entry   ║
╚════════════════════════════╩══════════════════════════════════╝

- ENTRYPOINT [“exec_entry”, “p1_entry”]

╔════════════════════════════╦═════════════════════════════════════════════════╗
║ No CMD                     ║ exec_entry p1_entry                             ║
╟────────────────────────────╫─────────────────────────────────────────────────╢
║ CMD [“exec_cmd”, “p1_cmd”] ║ exec_entry p1_entry exec_cmd p1_cmd             ║
╟────────────────────────────╫─────────────────────────────────────────────────╢
║ CMD [“p1_cmd”, “p2_cmd”]   ║ exec_entry p1_entry p1_cmd p2_cmd               ║
╟────────────────────────────╫─────────────────────────────────────────────────╢
║ CMD exec_cmd p1_cmd        ║ exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd  ║
╚════════════════════════════╩═════════════════════════════════════════════════╝
Rafaf Tahsin
fonte
O que são px_cmd e exec_entry? O que significa quando eles estão na mesma linha de execução? Eles são passados ​​como argumento um para o outro? Mesmo quando /bin/sh -cestá envolvido?
precisa saber é o seguinte
1
@ Danielo515 'px_cmd' e 'exec_entry' são apenas sequências falsas aqui. Você pode observar que isso /bin/sh -cseria adicionado ao CMD como prefixo enquanto o CMD era gravado na sintaxe executável (não na sintaxe da lista).
Light.G 26/09/18
1
@royki Se o usuário especificar argumentos para executar a janela de encaixe , ele substituirá o padrão especificado no CMD.
31419 Donrondadon
2
ENTRYPOINT exec_entry p1_entfoi explicado erroneamente. A forma de concha impede quaisquer argumentos de linha de comando CMD ou execução de ser usado - docs.docker.com/engine/reference/builder/#entrypoint
Mariusz Miesiak
1
@MariuszMiesiak agora está atualizado. Obrigado pelo seu feedback!
Rafaf Tahsin 22/11/19
170

Sim, essa é uma boa pergunta. Ainda não o compreendo completamente, mas:

Eu entendo que ENTRYPOINTé o binário que está sendo executado. Você pode substituir o ponto de entrada por --entrypoint = "".

docker run -t -i --entrypoint="/bin/bash" ubuntu

CMD é o argumento padrão para o contêiner. Sem ponto de entrada, o argumento padrão é o comando que é executado. Com o ponto de entrada, o cmd é passado para o ponto de entrada como argumento. Você pode emular um comando com ponto de entrada.

# no entrypoint
docker run ubuntu /bin/cat /etc/passwd

# with entry point, emulating cat command
docker run --entrypoint="/bin/cat" ubuntu /etc/passwd

Portanto, a principal vantagem é que, com o ponto de entrada, você pode passar argumentos (cmd) para o seu contêiner. Para fazer isso, você precisa usar os dois:

# Dockerfile
FROM ubuntu
ENTRYPOINT ["/bin/cat"]

e

docker build -t=cat .

então você pode usar:

docker run cat /etc/passwd
#              ^^^^^^^^^^^
#                   CMD
#          ^^^      
#          image (tag)- using the default ENTRYPOINT
Jiri
fonte
@Blauhirn No seu caso, você deve adicionar argumentos ao CMD na sintaxe da lista e garantir que o ponto de entrada que você separou possa analisar seus argumentos no CMD. Normalmente, adiciono um argumento '-h' ao ponto de entrada. Então eu posso executar docker run image_name -hpara mostrar algumas informações de ajuda desta imagem.
Light.G
1
Esta é a resposta mais simples e clara.
Eric Wang
44

Diferença entre CMD e ENTRYPOINT por intuição :

  • ENTRYPOINT: comando para executar quando o contêiner é iniciado.
  • CMD: comando a ser executado quando o contêiner é iniciado ou argumentos para ENTRYPOINT, se especificado.

Sim, está se misturando.

Você pode substituir qualquer um deles ao executar a janela de encaixe.

Diferença entre CMD e ENTRYPOINT por exemplo :

docker run -it --rm yourcontainer /bin/bash            <-- /bin/bash overrides CMD
                                                       <-- /bin/bash does not override ENTRYPOINT
docker run -it --rm --entrypoint ls yourcontainer      <-- overrides ENTRYPOINT with ls
docker run -it --rm --entrypoint ls yourcontainer  -la  <-- overrides ENTRYPOINT with ls and overrides CMD with -la

Mais sobre a diferença entre CMDe ENTRYPOINT:

Argumentos docker runcomo / bin / bash substituem qualquer comando CMD que escrevemos no Dockerfile.

ENTRYPOINT não pode ser substituído no tempo de execução por comandos normais como docker run [args]. No argsfinal de docker run [args]são fornecidos como argumentos para ENTRYPOINT. Desta forma, podemos criar um containerque é como um binário normal como ls.

Portanto, o CMD pode atuar como parâmetros padrão para ENTRYPOINT e, em seguida, podemos substituir os args do CMD de [args].

ENTRYPOINT pode ser substituído por --entrypoint.

Tomer Ben David
fonte
38

Em poucas palavras:

  • O CMD define comando e / ou parâmetros padrão, que podem ser substituídos na linha de comando quando o contêiner do docker é executado.
  • O comando e os parâmetros ENTRYPOINT não serão substituídos na linha de comandos. Em vez disso, todos os argumentos da linha de comando serão adicionados após os parâmetros ENTRYPOINT.

Se você precisar de mais detalhes ou quiser ver a diferença no exemplo, há uma postagem no blog que compara de maneira abrangente o CMD e o ENTRYPOINT com vários exemplos - http://goinbigdata.com/docker-run-vs-cmd-vs-entrypoint/

upitau
fonte
21

Vou adicionar minha resposta como exemplo 1 que pode ajudar você a entender melhor a diferença.

Vamos supor que queremos criar uma imagem que sempre execute um comando de suspensão quando for iniciado. Criaremos nossa própria imagem e especificaremos um novo comando:

FROM ubuntu
CMD sleep 10

Agora, criamos a imagem:

docker build -t custom_sleep .
docker run custom_sleep
# sleeps for 10 seconds and exits

E se quisermos mudar o número de segundos? Teríamos que alterar o Dockerfilevalor como o código é codificado lá ou substituir o comando fornecendo um diferente:

docker run custom_sleep sleep 20

Enquanto isso funciona, não é uma boa solução, pois temos um comando "sleep" redundante (o objetivo do contêiner é dormir , portanto, especificar explicitamente o sleepcomando não é uma boa prática).

Agora vamos tentar usar a ENTRYPOINTinstrução:

FROM ubuntu
ENTRYPOINT sleep

Esta instrução especifica o programa que será executado quando o contêiner iniciar .

Agora podemos executar:

docker run custom_sleep 20

Que tal um valor padrão? Bem, você adivinhou certo:

FROM ubuntu
ENTRYPOINT ["sleep"]
CMD ["10"]

O ENTRYPOINTé o programa que será executado e o valor passado para o contêiner será anexado a ele.

O ENTRYPOINTpode ser substituído, especificando um --entrypointsinalizador, seguido pelo novo ponto de entrada que você deseja usar.

Não meu, uma vez assisti a um tutorial que forneceu este exemplo

Maroun
fonte
1
Aqui está um link para o tutorial: youtu.be/OYbEWUbmk90 . Pode ser útil para usuários futuros.
ChiPlusPlus 16/11/19
7

Comentários sobre a função EntryPoint no código

// ENTRYPOINT / usr / sbin / nginx.

// Defina o ponto de entrada (cujo padrão é sh -c) como / usr / sbin / nginx.

// Aceitará o CMD como os argumentos para / usr / sbin / nginx.

Outra referência de documentos

Você pode usar o formato exec de ENTRYPOINT para definir comandos e argumentos padrão bastante estáveis e, em seguida, usar o CMD para definir padrões adicionais com maior probabilidade de serem alterados.

Exemplo:

FROM ubuntu:14.04.3
ENTRYPOINT ["/bin/ping"]
CMD ["localhost", "-c", "2"]

Compilação : sudo docker build -t ent_cmd.

CMD arguments are easy to override.

NO argument (sudo docker -it ent_cmd)                :  ping localhost 
argument    (sudo docker run -it ent_cmd google.com) :  ping google.com

.

To override EntryPoint argument, you need to supply entrypoint
sudo docker run -it --entrypoint="/bin/bash" ent_cmdd

ps: Na presença do EntryPoint, o CMD manterá argumentos para alimentar o EntryPoint. Na ausência do EntryPoint, o CMD será o comando que será executado.

Tahir Rauf
fonte
3

CMDO comando mencionado dentro do Dockerfilearquivo pode ser substituído pelo docker runcomando enquanto ENTRYPOINTnão pode ser.

anshul
fonte
4
docker run --helpcomando diz o contrário:--entrypoint string Overwrite the default ENTRYPOINT of the image
iomv 01/08/1919
3

Li todas as respostas e quero resumir para uma melhor compreensão à primeira vista, como a seguir:

Primeiramente, todo o comando executado no contêiner inclui duas partes: o comando e os argumentos

  • ENTRYPOINT define o executável chamado quando o contêiner é iniciado (para comando)

  • CMD especifica os argumentos que são passados ​​para o ENTRYPOINT (para argumentos)

No livro Kubernetes In Action, destaca-se uma nota importante. (Capítulo 7)

Embora você possa usar a instrução CMD para especificar o comando que deseja executar quando a imagem for executada, a maneira correta é fazê-lo através da instrução ENTRYPOINT e especificar o CMD apenas se desejar definir os argumentos padrão.

Você também pode ler este artigo para obter ótimas explicações de uma maneira simples

fgul
fonte
2

CMD:

  • CMD ["executable","param1","param2"]: ["executable","param1","param2"]é o primeiro processo.
  • CMD command param1 param2: /bin/sh -c CMD command param1 param2é o primeiro processo. CMD command param1 param2é bifurcada desde o primeiro processo.
  • CMD ["param1","param2"]: Este formulário é usado para fornecer argumentos padrão para ENTRYPOINT.

ENTRYPOINT (A lista a seguir não considera o caso em que CMD e ENTRYPOINT são usados ​​juntos):

  • ENTRYPOINT ["executable", "param1", "param2"]: ["executable", "param1", "param2"]é o primeiro processo.
  • ENTRYPOINT command param1 param2: /bin/sh -c command param1 param2é o primeiro processo. command param1 param2é bifurcada desde o primeiro processo.

Como o creack disse, o CMD foi desenvolvido primeiro. Em seguida, o ENTRYPOINT foi desenvolvido para mais personalização. Como eles não são projetados juntos, existem algumas sobreposições de funcionalidade entre o CMD e o ENTRYPOINT, que geralmente confundem as pessoas.

Jingguo Yao
fonte
2

A maioria das pessoas explica perfeitamente aqui, então não vou repetir todas as respostas. Mas, para ter uma boa sensação, sugiro testá-lo, analisando os processos no contêiner.

Crie um pequeno Dockerfile do formulário:

FROM ubuntu:latest
CMD /bin/bash

Construa, execute docker run -it theimagee execute ps -eo ppid,pid,argsno contêiner. Compare esta saída com a saída que você recebe do ps ao usar:

  • docker run -it theimage bash
  • Reconstruindo a imagem, mas com ENTRYPOINT /bin/bashe executando-a nos dois sentidos
  • Usando CMD ["/bin/bash"]
  • ...

Dessa forma, você verá facilmente as diferenças entre todos os métodos possíveis.

Garo
fonte
0

A documentação oficial das melhores práticas do Dockerfile faz um ótimo trabalho explicando as diferenças. Práticas recomendadas do Dockerfile

CMD:

A instrução CMD deve ser usada para executar o software contido na sua imagem, juntamente com quaisquer argumentos. O CMD quase sempre deve ser usado na forma de CMD ["executable", "param1", "param2"…]. Portanto, se a imagem for para um serviço, como Apache e Rails, você executaria algo parecido CMD ["apache2","-DFOREGROUND"]. De fato, essa forma de instrução é recomendada para qualquer imagem baseada em serviço.

PONTO DE ENTRADA:

O melhor uso para ENTRYPOINT é definir o comando principal da imagem, permitindo que a imagem seja executada como se fosse esse comando (e use o CMD como sinalizadores padrão).

MIYUKI NARAHARA
fonte