Quelle est la différence entre CMD et ENTRYPOINT dans un Dockerfile?

1701

Dans Dockerfiles, il y a deux commandes qui me ressemblent: CMDet ENTRYPOINT. Mais je suppose qu'il y a une différence (subtile?) Entre eux - sinon cela n'aurait aucun sens d'avoir deux commandes pour la même chose.

La documentation indique CMD

Le but principal d'un CMD est de fournir des valeurs par défaut pour un conteneur en cours d'exécution.

et pour ENTRYPOINT:

Un ENTRYPOINT vous aide à configurer un conteneur que vous pouvez exécuter en tant qu'exécutable.

Alors, quelle est la différence entre ces deux commandes?

Golo Roden
la source
12
Cet article de blog a une bonne description des différences et comment elles peuvent également être utilisées ensemble: crosbymichael.com/dockerfile-best-practices.html .
slm
2
^ ça! Merci @slm. Voici une autre référence très similaire qui pourrait être un peu plus à jour: docs.docker.com/reference/builder/#entrypoint
Adam Monsen
5
Aussi déroutant que la différence entre ADDetCOPY
Raedwald
1
Ce lien fournit la différence entre RUN, CMD et ENTRYPOINT: goinbigdata.com/docker-run-vs-cmd-vs-entrypoint
prafi
1
@JaimeHablutzel La phrase est de vous rendre service
Jonathan Komar

Réponses:

1738

Docker a un point d'entrée par défaut qui est /bin/sh -cmais n'a pas de commande par défaut.

Lorsque vous exécutez docker comme ceci: docker run -i -t ubuntu bash le point d'entrée est la valeur par défaut /bin/sh -c, l'image est ubuntuet la commande l'est bash.

La commande est exécutée via le point d'entrée. c'est-à-dire que la chose réelle qui est exécutée est /bin/sh -c bash. Cela a permis à Docker de mettre en œuvre RUNrapidement en s'appuyant sur l'analyseur du shell.

Plus tard, les gens ont demandé à pouvoir le personnaliser, ENTRYPOINTet --entrypointont été présentés.

Tout ce qui suit ubuntudans l'exemple ci-dessus est la commande et est passé au point d'entrée. Lorsque vous utilisez l' CMDinstruction, c'est exactement comme si vous le faisiez docker run -i -t ubuntu <cmd>. <cmd>sera le paramètre du point d'entrée.

Vous obtiendrez également le même résultat si vous tapez plutôt cette commande docker run -i -t ubuntu. Vous démarrerez toujours un shell bash dans le conteneur car le Dockerfile ubuntu a spécifié un CMD par défaut:CMD ["bash"]

Comme tout est passé au point d'entrée, vous pouvez avoir un très bon comportement à partir de vos images. L'exemple @Jiri est bon, il montre comment utiliser une image comme "binaire". Lorsque vous l'utilisez ["/bin/cat"]comme point d'entrée et que docker run img /etc/passwdvous le faites , vous l'obtenez, /etc/passwdest la commande et est passée au point d'entrée, de sorte que l'exécution du résultat final est simple /bin/cat /etc/passwd.

Un autre exemple serait d'avoir n'importe quel cli comme point d'entrée. Par exemple, si vous avez une image Redis, au lieu de courir docker run redisimg redis -H something -u toto get key, vous pouvez simplement avoir ENTRYPOINT ["redis", "-H", "something", "-u", "toto"]et courir comme cela pour le même résultat: docker run redisimg get key.

creack
la source
3
Pas du tout. ENTRYPOINT définit une métadonnée qui peut (mais peut être remplacée) au moment de l'exécution, donc si vous ne changez rien, après le démarrage de votre conteneur, le résultat sera le même, cependant, RUN sera exécuté au moment de la construction et peu importe ce que vous faire à l'exécution, il sera ici.
creack
8
Par défaut, il n'y a pas ENTRYPOINT; L'utilisation d'un shell dépend de la forme utilisée de la CMDcommande ( docs.docker.com/engine/reference/builder/#cmd ).
Blaisorblade
19
Merci pour cela, le contexte historique aide beaucoup car je luttais pour me souvenir des règles apparemment obscures sur ce qui est ignoré et ce qui est ajouté, etc. Un point utile pour les rédacteurs de documentation technique du monde entier: aidez le lecteur à construire un modèle mental du système, ne vous contentez pas de lister les faits et les scénarios :-)
ashirley
84
Ceci est une réponse fabuleuse. Je pense que la documentation Docker devrait ajouter cette sous une section appelée CMDvs ENTRYPOINT.
Tarik
5
@Webman Non. Ce sont deux instructions différentes. S'ils existent tous les deux, CMD serait traité comme les paramètres de ENTRYPOINT.
Light.G
628

La ENTRYPOINTspécifie une commande qui sera toujours exécutée au démarrage du conteneur.

Le CMDspécifie les arguments qui seront fournis au ENTRYPOINT.

Si vous souhaitez créer une image dédiée à une commande spécifique, vous utiliserez ENTRYPOINT ["/path/dedicated_command"]

Sinon, si vous souhaitez créer une image à des fins générales, vous pouvez laisser ENTRYPOINTnon spécifié et utiliser CMD ["/path/dedicated_command"]car vous pourrez remplacer le paramètre en fournissant des arguments à docker run.

Par exemple, si votre Dockerfile est:

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

L'exécution de l'image sans aucun argument enverra une requête ping à l'hôte 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

Maintenant, l'exécution de l'image avec un argument exécutera un ping sur l'argument:

$ 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

À titre de comparaison, si votre Dockerfile est:

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

L'exécution de l'image sans aucun argument enverra une requête ping à l'hôte 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

Mais l'exécution de l'image avec un argument exécutera l'argument:

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

Voir cet article de Brian DeHamer pour encore plus de détails: https://www.ctl.io/developers/blog/post/dockerfile-entrypoint-vs-cmd/

Daishi
la source
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.est un bon résumé au point.
Jingguo Yao
1
ENTRYPOINT peut également être remplacé à l'aide de l'indicateur --entrypoint. par exemple docker run -it --entrypoint bash test
vuimurugan
2
J'aime vos exemples, c'est vraiment utile!
Chau Giang
2
@Jingguo Yao: Et si CMD contient une commande telle que - CMD ["nginx", "- g", "daemon", "off"]? Serait-il enchaîné?
KMC
@KMC CMD est l'argument par défaut de ENTRYPOINT, vous le remplacez en passant un nouvel argument lors de l'exécution de l'image.
MGP
237

Selon les documents Docker ,

Les instructions CMD et ENTRYPOINT définissent la commande à exécuter lors de l'exécution d'un conteneur. Il existe peu de règles décrivant leur coopération.

  1. Dockerfile doit spécifier au moins une des commandes CMDou ENTRYPOINT.
  2. ENTRYPOINT doit être défini lors de l'utilisation du conteneur comme exécutable.
  3. CMDdoit être utilisé comme un moyen de définir des arguments par défaut pour une ENTRYPOINTcommande ou pour exécuter une commande ad hoc dans un conteneur.
  4. CMD sera remplacé lors de l'exécution du conteneur avec des arguments alternatifs.

Les tableaux ci-dessous montrent quelle commande est exécutée pour différentes ENTRYPOINT/ CMDcombinaisons :

- 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
la source
Que sont px_cmd et exec_entry? Que signifie quand ils sont sur la même ligne d'exécution? Ils sont passés en argument les uns aux autres? Même lorsque le /bin/sh -cest impliqué?
Danielo515
1
@ Danielo515 'px_cmd' et 'exec_entry' ne sont ici que des chaînes factices. Vous remarquerez /bin/sh -cpeut-être que CMD serait ajouté en tant que préfixe alors que CMD serait écrit en syntaxe exécutable (et non en syntaxe de liste).
Light.G
1
@royki Si l'utilisateur spécifie des arguments à exécuter par docker, il remplacera la valeur par défaut spécifiée dans CMD.
donrondadon
2
ENTRYPOINT exec_entry p1_enta été mal expliqué. Le formulaire shell empêche l'utilisation de tout argument CMD ou d'exécution de ligne de commande - docs.docker.com/engine/reference/builder/#entrypoint
Mariusz Miesiak
1
@MariuszMiesiak est maintenant mis à jour. Merci pour vos commentaires.
Rafaf Tahsin
170

Oui, c'est une bonne question. Je ne le comprends pas encore tout à fait, mais:

Je comprends que ENTRYPOINTc'est le binaire qui est exécuté. Vous pouvez remplacer le point d'entrée par --entrypoint = "".

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

CMD est l'argument par défaut du conteneur. Sans point d'entrée, l'argument par défaut est la commande qui est exécutée. Avec entrypoint, cmd est passé à entrypoint comme argument. Vous pouvez émuler une commande avec point d'entrée.

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

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

Ainsi, le principal avantage est qu'avec le point d'entrée, vous pouvez passer des arguments (cmd) à votre conteneur. Pour ce faire, vous devez utiliser les deux:

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

et

docker build -t=cat .

alors vous pouvez utiliser:

docker run cat /etc/passwd
#              ^^^^^^^^^^^
#                   CMD
#          ^^^      
#          image (tag)- using the default ENTRYPOINT
Jiri
la source
@Blauhirn Dans votre cas, vous devez ajouter des arguments à CMD dans la syntaxe de liste et vous assurer que le point d'entrée que vous avez spécifié pourrait analyser vos arguments dans CMD. Habituellement, j'ajoute un argument «-h» au point d'entrée. Ensuite, je peux exécuter docker run image_name -hpour afficher des informations d'aide sur cette image.
Light.G
1
Ceci est la réponse la plus simple et la plus claire.
Eric Wang
44

Différence entre CMD et ENTRYPOINT par intuition :

  • ENTRYPOINT: commande à exécuter au démarrage du conteneur.
  • CMD: commande à exécuter au démarrage du conteneur ou arguments à ENTRYPOINT si spécifié.

Oui, ça se mélange.

Vous pouvez remplacer l'un d'eux lors de l'exécution de Docker Run.

Différence entre CMD et ENTRYPOINT par exemple :

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

Plus sur la différence entre CMDet ENTRYPOINT:

Un argument docker runtel que / bin / bash remplace toute commande CMD que nous avons écrite dans Dockerfile.

ENTRYPOINT ne peut pas être remplacé lors de l'exécution avec des commandes normales telles que docker run [args]. À argsla fin de docker run [args]sont fournis comme arguments à ENTRYPOINT. De cette façon, nous pouvons créer un containerqui est comme un binaire normal tel que ls.

Ainsi, CMD peut agir comme paramètres par défaut pour ENTRYPOINT, puis nous pouvons remplacer les arguments CMD à partir de [args].

ENTRYPOINT peut être remplacé par --entrypoint.

Tomer Ben David
la source
38

En un mot:

  • CMD définit la commande et / ou les paramètres par défaut, qui peuvent être remplacés à partir de la ligne de commande lors de l'exécution du conteneur Docker.
  • La commande et les paramètres ENTRYPOINT ne seront pas remplacés à partir de la ligne de commande. Au lieu de cela, tous les arguments de ligne de commande seront ajoutés après les paramètres ENTRYPOINT.

Si vous avez besoin de plus de détails ou souhaitez voir une différence sur l'exemple, il y a un article de blog qui compare de manière complète CMD et ENTRYPOINT avec de nombreux exemples - http://goinbigdata.com/docker-run-vs-cmd-vs-entrypoint/

upitau
la source
21

J'ajouterai ma réponse comme exemple 1 qui pourrait vous aider à mieux comprendre la différence.

Supposons que nous voulons créer une image qui exécutera toujours une commande sleep au démarrage. Nous allons créer notre propre image et spécifier une nouvelle commande:

FROM ubuntu
CMD sleep 10

Maintenant, nous construisons l'image:

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

Et si nous voulons changer le nombre de secondes? Nous devrions changer la Dockerfilecar la valeur y est codée en dur, ou remplacer la commande en fournissant une autre:

docker run custom_sleep sleep 20

Bien que cela fonctionne, ce n'est pas une bonne solution, car nous avons une commande redondante "sleep" (le but du conteneur est de dormir , donc avoir à spécifier explicitement la sleepcommande n'est pas une bonne pratique).

Essayons maintenant d'utiliser l' ENTRYPOINTinstruction:

FROM ubuntu
ENTRYPOINT sleep

Cette instruction spécifie le programme qui sera exécuté au démarrage du conteneur .

Maintenant, nous pouvons exécuter:

docker run custom_sleep 20

Et une valeur par défaut? Eh bien, vous l'avez deviné:

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

Le ENTRYPOINTest le programme qui sera exécuté, et la valeur transmise au conteneur sera rajoutée.

Le ENTRYPOINTpeut être remplacé en spécifiant un --entrypointindicateur, suivi du nouveau point d'entrée que vous souhaitez utiliser.

Pas le mien, j'ai regardé une fois un tutoriel qui a fourni cet exemple

Maroun
la source
1
Voici un lien vers le tutoriel: youtu.be/OYbEWUbmk90 . Il pourrait être utile aux futurs utilisateurs.
ChiPlusPlus
7

Commentaires sur la fonction EntryPoint dans le code

// POINT D'ENTREE / usr / sbin / nginx.

// Définissez le point d'entrée (par défaut sh -c) sur / usr / sbin / nginx.

// Acceptera le CMD comme arguments de / usr / sbin / nginx.

Une autre référence de documents

Vous pouvez utiliser la forme d'exécution de ENTRYPOINT pour définir des commandes et des arguments par défaut assez stables , puis utiliser CMD pour définir des valeurs par défaut supplémentaires qui sont plus susceptibles d'être modifiées.

Exemple:

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

Build : 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: en présence d'EntréePoint, CMD conservera les arguments à transmettre à EntryPoint. En l'absence d'EntréePoint, CMD sera la commande qui sera exécutée.

Tahir Rauf
la source
3

CMDLa commande mentionnée dans le Dockerfilefichier peut être remplacée via la docker runcommande alors qu'elle ENTRYPOINTne peut pas l'être.

anshul
la source
4
docker run --helpla commande dit le contraire:--entrypoint string Overwrite the default ENTRYPOINT of the image
iomv
3

J'ai lu toutes les réponses et je veux résumer pour une meilleure compréhension à première vue comme suit:

Tout d'abord, la commande entière qui est exécutée dans le conteneur comprend deux parties: la commande et les arguments

  • ENTRYPOINT définit l'exécutable appelé au démarrage du conteneur (pour la commande)

  • CMD spécifie les arguments qui sont passés au ENTRYPOINT (pour les arguments)

Dans le livre Kubernetes In Action, il y a une note importante à ce sujet. (Chapitre 7)

Bien que vous puissiez utiliser l' instruction CMD pour spécifier la commande que vous souhaitez exécuter lorsque l'image est exécutée, la manière correcte consiste à le faire via l' instruction ENTRYPOINT et à spécifier uniquement le CMD si vous souhaitez définir les arguments par défaut.

Vous pouvez également lire cet article pour une grande explication d'une manière simple

fgul
la source
2

CMD:

  • CMD ["executable","param1","param2"]: ["executable","param1","param2"]est le premier processus.
  • CMD command param1 param2: /bin/sh -c CMD command param1 param2est le premier processus. CMD command param1 param2est issu du premier processus.
  • CMD ["param1","param2"]: Ce formulaire est utilisé pour fournir des arguments par défaut pour ENTRYPOINT.

ENTRYPOINT (la liste suivante ne prend pas en compte le cas où CMD et ENTRYPOINT sont utilisés ensemble):

  • ENTRYPOINT ["executable", "param1", "param2"]: ["executable", "param1", "param2"]est le premier processus.
  • ENTRYPOINT command param1 param2: /bin/sh -c command param1 param2est le premier processus. command param1 param2est issu du premier processus.

Comme l'a dit creack , CMD a été développé en premier. Ensuite, ENTRYPOINT a été développé pour plus de personnalisation. Puisqu'ils ne sont pas conçus ensemble, il existe des chevauchements de fonctionnalités entre CMD et ENTRYPOINT, ce qui confond souvent les gens.

Jingguo Yao
la source
2

La plupart des gens l'expliquent parfaitement ici, donc je ne répéterai pas toutes les réponses. Mais pour avoir une bonne impression, je vous suggère de le tester vous-même en regardant les processus dans le conteneur.

Créez un petit Dockerfile du formulaire:

FROM ubuntu:latest
CMD /bin/bash

Construisez-le, exécutez-le avec docker run -it theimageet exécutez-le ps -eo ppid,pid,argsdans le conteneur. Comparez cette sortie à la sortie que vous recevez de ps lorsque vous utilisez:

  • docker run -it theimage bash
  • Reconstruire l'image mais avec ENTRYPOINT /bin/bashet l'exécuter dans les deux sens
  • En utilisant CMD ["/bin/bash"]
  • ...

De cette façon, vous verrez facilement les différences entre toutes les méthodes possibles.

Garo
la source
0

La documentation officielle des meilleures pratiques Dockerfile explique très bien les différences. Meilleures pratiques Dockerfile

CMD:

L'instruction CMD doit être utilisée pour exécuter le logiciel contenu dans votre image, ainsi que tous les arguments. CMD devrait presque toujours être utilisé sous la forme de CMD ["executable", "param1", "param2"…]. Ainsi, si l'image est destinée à un service, comme Apache et Rails, vous exécutez quelque chose comme CMD ["apache2","-DFOREGROUND"]. En effet, cette forme d'instruction est recommandée pour toute image de service.

POINT D'ACCÈS:

La meilleure utilisation pour ENTRYPOINT est de définir la commande principale de l'image, permettant à cette image d'être exécutée comme s'il s'agissait de cette commande (puis d'utiliser CMD comme indicateurs par défaut).

MIYUKI NARAHARA
la source