¿Cuál es la diferencia entre CMD y ENTRYPOINT en un Dockerfile?

1700

En Dockerfiles hay dos comandos que se parecen a mí: CMDy ENTRYPOINT. Pero supongo que hay una diferencia (¿sutil?) Entre ellos; de lo contrario, no tendría sentido tener dos comandos para lo mismo.

La documentación indica para CMD

El objetivo principal de un CMD es proporcionar valores predeterminados para un contenedor en ejecución.

y para ENTRYPOINT:

Un ENTRYPOINT lo ayuda a configurar un contenedor que puede ejecutar como ejecutable.

Entonces, ¿cuál es la diferencia entre esos dos comandos?

Golo Roden
fuente
12
Esta publicación de blog tiene una buena descripción de las diferencias y cómo se pueden usar juntas también: crosbymichael.com/dockerfile-best-practices.html .
slm
2
^ eso! Gracias @slm. Aquí hay otra referencia muy similar que podría estar un poco más actualizada: docs.docker.com/reference/builder/#entrypoint
Adam Monsen
55
Tan confuso como la diferencia entre ADDyCOPY
Raedwald
1
Este enlace proporciona la diferencia entre RUN, CMD y ENTRYPOINT: goinbigdata.com/docker-run-vs-cmd-vs-entrypoint
prafi
1
@JaimeHablutzel La frase es hazte un favor
Jonathan Komar

Respuestas:

1738

Docker tiene un punto de entrada predeterminado que es /bin/sh -cpero no tiene un comando predeterminado.

Cuando ejecuta docker run -i -t ubuntu bash Docker de esta manera: el punto de entrada es el predeterminado /bin/sh -c, la imagen es ubuntuy el comando es bash.

El comando se ejecuta a través del punto de entrada. es decir, lo que realmente se ejecuta es /bin/sh -c bash. Esto permitió a Docker implementar RUNrápidamente confiando en el analizador del shell.

Más tarde, la gente pidió poder personalizar esto, ENTRYPOINTy --entrypointse presentaron.

Todo lo que ubuntusigue en el ejemplo anterior es el comando y se pasa al punto de entrada. Al usar la CMDinstrucción, es exactamente como si lo estuviera haciendo docker run -i -t ubuntu <cmd>. <cmd>será el parámetro del punto de entrada.

También obtendrá el mismo resultado si en su lugar escribe este comando docker run -i -t ubuntu. Aún comenzará un shell bash en el contenedor debido a que el Dockerfile de ubuntu especificó un CMD predeterminado:CMD ["bash"]

Como todo se pasa al punto de entrada, puede tener un comportamiento muy agradable de sus imágenes. El ejemplo de @Jiri es bueno, muestra cómo usar una imagen como "binario". Cuando se usa ["/bin/cat"]como punto de entrada y luego se hace docker run img /etc/passwd, se obtiene, /etc/passwdes el comando y se pasa al punto de entrada para que la ejecución del resultado final sea sencilla /bin/cat /etc/passwd.

Otro ejemplo sería tener cualquier cli como punto de entrada. Por ejemplo, si usted tiene una imagen de Redis, en lugar de correr docker run redisimg redis -H something -u toto get key, sólo tiene que tener ENTRYPOINT ["redis", "-H", "something", "-u", "toto"]y luego ejecutar así por el mismo resultado: docker run redisimg get key.

crujir
fuente
3
De ningún modo. ENTRYPOINT establece un metadato que puede (pero puede anularse) en tiempo de ejecución, por lo que si no cambia nada, después de iniciar su contenedor, el resultado será el mismo, sin embargo, RUN se ejecutará en el momento de la compilación y no importa lo que usted haga. hacer en tiempo de ejecución, estará aquí.
chirrido
8
Por defecto no hay ENTRYPOINT; si se utiliza un shell depende de la forma utilizada del CMDcomando ( docs.docker.com/engine/reference/builder/#cmd ).
Blaisorblade
19
Gracias por esto, el contexto histórico ayuda mucho ya que estaba luchando por recordar las reglas aparentemente arcanas sobre lo que se anula y lo que se adjunta, etc. Un punto útil para los escritores de documentación técnica en todas partes: ayudar al lector a construir un modelo mental del sistema, no se limite a la lista de hechos y escenarios :-)
ashirley
84
Esta es una respuesta fabulosa. Creo que la documentación del estibador debe agregar esta bajo una sección llamada CMDvs ENTRYPOINT.
Tarik
55
@Webman No. Son dos instrucciones diferentes. Si ambos existen, CMD se trataría como parámetros de ENTRYPOINT.
Light.G
628

Las ENTRYPOINTespecifica un comando que siempre se ejecuta cuando se inicia el contenedor.

El CMDespecifica los argumentos que serán alimentados al ENTRYPOINT.

Si desea hacer una imagen dedicada a un comando específico, utilizará ENTRYPOINT ["/path/dedicated_command"]

De lo contrario, si desea crear una imagen para fines generales, puede dejarla sin ENTRYPOINTespecificar y usar, CMD ["/path/dedicated_command"]ya que podrá anular la configuración al proporcionar argumentos a docker run.

Por ejemplo, si su Dockerfile es:

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

Ejecutar la imagen sin ningún argumento hará ping al localhost:

$ 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

Ahora, ejecutar la imagen con un argumento hará ping al 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

A modo de comparación, si su Dockerfile es:

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

Ejecutar la imagen sin ningún argumento hará ping al localhost:

$ 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

Pero ejecutar la imagen con un argumento ejecutará el argumento:

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

Vea este artículo de Brian DeHamer para obtener más detalles: https://www.ctl.io/developers/blog/post/dockerfile-entrypoint-vs-cmd/

Daishi
fuente
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.es un buen resumen al punto.
Jingguo Yao
1
ENTRYPOINT también se puede anular usando --entrypoint flag. por ejemplo, docker run -it
pointpoint
2
Me gustan tus ejemplos, ¡es realmente útil!
Chau Giang
2
@Jingguo Yao: ¿Qué pasa si CMD contiene un comando como - CMD ["nginx", "- g", "daemon", "off"]? ¿Estaría encadenado?
KMC
@KMC CMD es el argumento predeterminado de ENTRYPOINT, lo anula pasando un nuevo argumento al ejecutar la imagen.
Pop
237

Según los documentos de Docker ,

Las instrucciones CMD y ENTRYPOINT definen qué comando se ejecuta al ejecutar un contenedor. Hay pocas reglas que describen su cooperación.

  1. Dockerfile debe especificar al menos uno de los comandos CMDo ENTRYPOINT.
  2. ENTRYPOINT debe definirse cuando se usa el contenedor como un ejecutable.
  3. CMDdebe usarse como una forma de definir argumentos predeterminados para un ENTRYPOINTcomando o para ejecutar un comando ad-hoc en un contenedor.
  4. CMD se anulará al ejecutar el contenedor con argumentos alternativos.

Las tablas a continuación muestran qué comando se ejecuta para diferentes ENTRYPOINT/ CMDcombinaciones :

- 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
fuente
¿Qué son px_cmd y exec_entry? ¿Qué significa cuando están en la misma línea de ejecución? ¿Se pasan como argumento el uno al otro? ¿Incluso cuando /bin/sh -cestá involucrado?
Danielo515
1
@ Danielo515 Tanto 'px_cmd' como 'exec_entry' son solo cadenas falsas aquí. Puede notar que /bin/sh -cse agregaría a CMD como prefijo mientras CMD está escrito en sintaxis ejecutable (no en la sintaxis de lista).
Light.G
1
@royki Si el usuario especifica argumentos para ejecutar Docker , anulará el valor predeterminado especificado en CMD.
donrondadon
2
ENTRYPOINT exec_entry p1_entfue mal explicado. El formulario de shell evita que se utilicen argumentos CMD o de línea de comandos de ejecución
Mariusz Miesiak
1
@MariuszMiesiak ahora está actualizado. Gracias por sus comentarios.
Rafaf Tahsin el
170

Sí, esa es una buena pregunta. Todavía no lo entiendo completamente, pero:

Entiendo que ENTRYPOINTes el binario que se está ejecutando. Puede anular el punto de entrada mediante --entrypoint = "".

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

CMD es el argumento predeterminado para el contenedor. Sin punto de entrada, el argumento predeterminado es un comando que se ejecuta. Con punto de entrada, cmd se pasa al punto de entrada como argumento. Puede emular un comando con punto 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

Entonces, la principal ventaja es que con el punto de entrada puede pasar argumentos (cmd) a su contenedor. Para lograr esto, debe usar ambos:

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

y

docker build -t=cat .

entonces puedes usar:

docker run cat /etc/passwd
#              ^^^^^^^^^^^
#                   CMD
#          ^^^      
#          image (tag)- using the default ENTRYPOINT
Jiri
fuente
@Blauhirn En su caso, debe agregar argumentos a CMD en la sintaxis de la lista y asegurarse de que el punto de entrada que separó pueda analizar sus argumentos en CMD. Por lo general, agrego un argumento '-h' al punto de entrada. Luego puedo ejecutar docker run image_name -hpara mostrar información de ayuda de esta imagen.
Light.G
1
Esta es la respuesta más simple y clara.
Eric Wang
44

Diferencia entre CMD y ENTRYPOINT por intuición :

  • PUNTO DE ENTRADA: comando para ejecutar cuando se inicia el contenedor.
  • CMD: comando para ejecutar cuando se inicia el contenedor o argumentos para ENTRYPOINT si se especifica.

Sí, se está mezclando.

Puede anular cualquiera de ellos cuando ejecute Docker Run.

Diferencia entre CMD y ENTRYPOINT por ejemplo :

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

Más sobre la diferencia entre CMDy ENTRYPOINT:

Argumentos docker runcomo / bin / bash anulan cualquier comando CMD que escribimos en Dockerfile.

ENTRYPOINT no se puede anular en tiempo de ejecución con comandos normales como docker run [args]. Al argsfinal de docker run [args]se proporcionan como argumentos para ENTRYPOINT. De esta manera podemos crear un containerque es como un binario normal como ls.

Por lo tanto, CMD puede actuar como parámetros predeterminados para ENTRYPOINT y luego podemos anular los args CMD de [args].

ENTRYPOINT se puede anular con --entrypoint.

Tomer Ben David
fuente
38

En una palabra:

  • CMD establece comandos y / o parámetros predeterminados, que se pueden sobrescribir desde la línea de comandos cuando se ejecuta el contenedor Docker.
  • El comando ENTRYPOINT y los parámetros no se sobrescribirán desde la línea de comando. En cambio, todos los argumentos de la línea de comandos se agregarán después de los parámetros ENTRYPOINT.

Si necesita más detalles o desea ver la diferencia en el ejemplo, hay una publicación de blog que compara exhaustivamente CMD y ENTRYPOINT con muchos ejemplos: http://goinbigdata.com/docker-run-vs-cmd-vs-entrypoint/

upitau
fuente
21

Agregaré mi respuesta como ejemplo 1 que podría ayudarlo a comprender mejor la diferencia.

Supongamos que queremos crear una imagen que siempre ejecutará un comando de suspensión cuando se inicie. Crearemos nuestra propia imagen y especificaremos un nuevo comando:

FROM ubuntu
CMD sleep 10

Ahora, construimos la imagen:

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

¿Qué pasa si queremos cambiar el número de segundos? Tendríamos que cambiar el Dockerfilevalor ya que el valor está codificado allí, o anular el comando proporcionando uno diferente:

docker run custom_sleep sleep 20

Si bien esto funciona, no es una buena solución, ya que tenemos un comando de "suspensión" redundante (el propósito del contenedor es dormir , por lo que tener que especificar explícitamente el sleepcomando no es una buena práctica).

Ahora intentemos usar las ENTRYPOINTinstrucciones:

FROM ubuntu
ENTRYPOINT sleep

Esta instrucción especifica el programa que se ejecutará cuando se inicie el contenedor .

Ahora podemos ejecutar:

docker run custom_sleep 20

¿Qué pasa con un valor predeterminado? Bueno, lo has adivinado bien:

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

El ENTRYPOINTes el programa que se ejecutará y se le agregará el valor pasado al contenedor.

Se ENTRYPOINTpuede anular especificando un --entrypointindicador, seguido del nuevo punto de entrada que desea usar.

No es mío, una vez vi un tutorial que proporcionó este ejemplo

Maroun
fuente
1
Aquí hay un enlace al tutorial: youtu.be/OYbEWUbmk90 . Puede ser útil para futuros usuarios.
ChiPlusPlus
7

Comentarios sobre la función EntryPoint en el código

// ENTRYPOINT / usr / sbin / nginx.

// Establezca el punto de entrada (que por defecto es sh -c) en / usr / sbin / nginx.

// Aceptará el CMD como argumentos para / usr / sbin / nginx.

Otra referencia de documentos

Puede usar la forma ejecutiva de ENTRYPOINT para establecer comandos y argumentos predeterminados bastante estables y luego usar CMD para establecer valores predeterminados adicionales que tienen más probabilidades de cambiar.

Ejemplo:

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

Construir : sudo ventana acoplable acumulación -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: en presencia de EntryPoint, CMD mantendrá argumentos para alimentar a EntryPoint. En ausencia de EntryPoint, CMD será el comando que se ejecutará.

Tahir Rauf
fuente
3

CMDEl comando mencionado dentro del Dockerfilearchivo se puede anular mediante un docker runcomando, mientras ENTRYPOINTque no se puede.

anshul
fuente
44
docker run --helpel comando dice lo contrario:--entrypoint string Overwrite the default ENTRYPOINT of the image
iomv
3

He leído todas las respuestas y quiero resumirlas para una mejor comprensión a primera vista como las siguientes:

En primer lugar, todo el comando que se ejecuta en el contenedor incluye dos partes: el comando y los argumentos

  • ENTRYPOINT define el ejecutable invocado cuando se inicia el contenedor (para comando)

  • CMD especifica los argumentos que se pasan al ENTRYPOINT (para argumentos)

En el libro Kubernetes In Action señala una nota importante al respecto. (Capítulo 7)

Aunque puede usar la instrucción CMD para especificar el comando que desea ejecutar cuando se ejecuta la imagen, la forma correcta es hacerlo a través de la instrucción ENTRYPOINT y solo especificar el CMD si desea definir los argumentos predeterminados.

También puede leer este artículo para obtener una gran explicación de una manera simple

fgul
fuente
2

CMD:

  • CMD ["executable","param1","param2"]: ["executable","param1","param2"]es el primer proceso.
  • CMD command param1 param2: /bin/sh -c CMD command param1 param2es el primer proceso. CMD command param1 param2se bifurca desde el primer proceso.
  • CMD ["param1","param2"]: Este formulario se utiliza para proporcionar argumentos predeterminados para ENTRYPOINT.

PUNTO DE ENTRADA (La siguiente lista no considera el caso donde CMD y ENTRYPOINT se usan juntos):

  • ENTRYPOINT ["executable", "param1", "param2"]: ["executable", "param1", "param2"]es el primer proceso.
  • ENTRYPOINT command param1 param2: /bin/sh -c command param1 param2es el primer proceso. command param1 param2se bifurca desde el primer proceso.

Como dijo Creack , CMD se desarrolló primero. Luego ENTRYPOINT fue desarrollado para una mayor personalización. Dado que no están diseñados juntos, hay algunas superposiciones de funcionalidad entre CMD y ENTRYPOINT, que a menudo confunden a las personas.

Jingguo Yao
fuente
2

La mayoría de la gente lo explica perfectamente aquí, así que no repetiré todas las respuestas. Pero para tener una buena idea, sugeriría probarlo usted mismo observando los procesos en el contenedor.

Cree un pequeño Dockerfile de la forma:

FROM ubuntu:latest
CMD /bin/bash

Constrúyalo, ejecútelo docker run -it theimagey ejecútelo ps -eo ppid,pid,argsen el contenedor. Compare esta salida con la salida que recibe de ps cuando usa:

  • docker run -it theimage bash
  • Reconstruyendo la imagen pero con ENTRYPOINT /bin/bashy ejecutándola de ambas maneras
  • Utilizando CMD ["/bin/bash"]
  • ...

De esta manera, verá fácilmente las diferencias entre todos los métodos posibles.

Garo
fuente
0

La documentación oficial de las mejores prácticas de Dockerfile hace un gran trabajo explicando las diferencias. Mejores prácticas de Dockerfile

CMD:

La instrucción CMD debe usarse para ejecutar el software contenido en su imagen, junto con cualquier argumento. La CMD casi siempre debe usarse en forma de CMD ["executable", "param1", "param2"…]. Por lo tanto, si la imagen es para un servicio, como Apache y Rails, ejecutaría algo así CMD ["apache2","-DFOREGROUND"]. De hecho, esta forma de instrucción se recomienda para cualquier imagen basada en servicios.

PUNTO DE ENTRADA:

El mejor uso para ENTRYPOINT es establecer el comando principal de la imagen, permitiendo que esa imagen se ejecute como si fuera ese comando (y luego usar CMD como los indicadores predeterminados).

MIYUKI NARAHARA
fuente