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

Resuelto Golo Roden asked hace 10 años • 20 respuestas

En Dockerfiles hay dos comandos que me parecen similares: CMDy ENTRYPOINT. Pero supongo que hay una diferencia (¿sutil?) entre ellos; de lo contrario, no tendría ningún sentido tener dos comandos para exactamente la misma cosa.

La documentación establece para CMD-

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

y para ENTRYPOINT:

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

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

Golo Roden avatar Feb 04 '14 20:02 Golo Roden
Aceptado

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

Cuando ejecuta Docker de esta manera: docker run -i -t ubuntu bash 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 implementarlo RUNrápidamente confiando en el analizador del shell.

Más tarde, la gente pidió poder personalizar esto, así ENTRYPOINTque --entrypointnos presentaron.

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

También obtendrá el mismo resultado si escribe este comando docker run -i -t ubuntu: se iniciará un shell bash en el contenedor porque en el Dockerfile de ubuntuCMD se especifica un valor predeterminado :
CMD ["bash"].

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

Otro ejemplo sería tener cualquier cli como punto de entrada. Por ejemplo, si tiene una imagen de Redis, en lugar de ejecutarla docker run redisimg redis -H something -u toto get key, puede simplemente tenerla ENTRYPOINT ["redis", "-H", "something", "-u", "toto"]y luego ejecutarla así para obtener el mismo resultado docker run redisimg get key:

creack avatar Feb 04 '2014 22:02 creack

Especifica ENTRYPOINTun comando que siempre se ejecutará cuando se inicie el contenedor.

Especifica los CMDargumentos que se enviarán al archivo ENTRYPOINT.

Si desea crear 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 ENTRYPOINTsin especificar y usarla CMD ["/path/dedicated_command"], ya que podrá anular la configuración proporcionando 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:/#

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

Daishi avatar Dec 12 '2015 22:12 Daishi

Según los documentos de Docker ,

Tanto las instrucciones CMD como ENTRYPOINT definen qué comando se ejecuta cuando se ejecuta un contenedor. Hay pocas reglas que describen su cooperación.

  1. Dockerfile debe especificar al menos uno de los comandos CMDo ENTRYPOINT.
  2. ENTRYPOINTdebe definirse al utilizar el contenedor como 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. CMDse anulará cuando se ejecute el contenedor con argumentos alternativos.

Las siguientes tablas muestran qué comando se ejecuta para diferentes combinaciones ENTRYPOINT/CMD :

--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 avatar Sep 09 '2016 09:09 Rafaf Tahsin

Sí, esa es una buena pregunta. Aún no lo entiendo del todo, 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 del contenedor. Sin punto de entrada, el argumento predeterminado es el comando que se ejecuta. Con el 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 puedes pasar argumentos (cmd) a tu contenedor. Para lograr esto, necesita 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 avatar Feb 04 '2014 17:02 Jiri

En una palabra:

  • CMD establece el comando y/o los parámetros predeterminados en el punto de entrada, que se pueden sobrescribir desde la línea de comando cuando se ejecuta el contenedor acoplable ( docker run example "override").
  • El comando ENTRYPOINT se sobrescribe antes de la imagen con su propio indicador de línea de comando ( docker run --entrypoint="override" image). Luego, todos los argumentos CMD se agregarán después de ENTRYPOINT como parámetros. En muchos casos, el punto de entrada se establece como sh -c. Puedes encontrar esto condocker inspect image -f '{{ .Config.Entrypoint }}'
  • Ambos se pueden combinar. ( docker run --entrypoint="/docker-entrypoint.sh" image arg1 arg2)

Si necesita más detalles o le gustaría ver la diferencia en un ejemplo, hay una publicación de blog que compara exhaustivamente CMD y ENTRYPOINT con muchos ejemplos: https://codewithyury.com/docker-run-vs-cmd-vs-entrypoint/

upitau avatar Apr 03 '2016 09:04 upitau

Diferencia entre CMD y ENTRYPOINT por intuición :

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

Sí, es confuso.

Puede anular cualquiera de ellos al ejecutar 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]. Los argsal final de docker run [args]se proporcionan como argumentos para ENTRYPOINT. De esta manera podemos crear un containerbinario normal como ls.

Entonces CMD puede actuar como parámetros predeterminados para ENTRYPOINT y luego podemos anular los argumentos de CMD desde [args].

ENTRYPOINT se puede anular con --entrypoint.

Tomer Ben David avatar Jan 16 '2017 12:01 Tomer Ben David