Dans Dockerfiles, deux commandes me ressemblent: CMD
et ENTRYPOINT
. Mais je suppose qu’il existe une différence (subtile?) Entre eux - sinon, cela n’aurait aucun sens d’avoir deux commandes pour la même chose.
La documentation indique pour CMD
L'objet 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?
Docker a un point d’entrée par défaut qui est /bin/sh -c
mais 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 le paramètre par défaut /bin/sh -c
, l’image est ubuntu
et la commande est bash
.
La commande est exécutée via le point d'entrée. c'est-à-dire que ce qui est exécuté est /bin/sh -c bash
. Cela a permis à Docker d’implémenter RUN
rapidement en s’appuyant sur l’analyseur du shell.
Plus tard, les gens ont demandé à pouvoir personnaliser cela, donc ENTRYPOINT
et --entrypoint
ont été introduits.
Tout ce qui suit ubuntu
dans l'exemple ci-dessus est la commande et est transmis au point d'entrée. Lorsque vous utilisez l'instruction CMD
, c'est exactement comme si vous utilisiez 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 allez toujours démarrer un shell bash dans le conteneur à cause du bocku Dockerfile spécifié un CMD par défaut: CMD ["bash"]
Comme tout est passé au point d'entrée, vous pouvez avoir un très joli comportement de vos images. @Jiri exemple est bon, il montre comment utiliser une image en tant que "binaire". Lorsque vous utilisez ["/bin/cat"]
comme point d'entrée, puis que vous exécutez docker run img /etc/passwd
, vous l'obtenez, /etc/passwd
est la commande et est transmis au point d'entrée. Ainsi, le résultat final est simplement /bin/cat /etc/passwd
.
Un autre exemple serait d'avoir n'importe quelle cli comme point d'entrée. Par exemple, si vous avez une image redis, au lieu d'exécuter docker run redisimg redis -H something -u toto get key
, vous pouvez simplement avoir ENTRYPOINT ["redis", "-H", "something", "-u", "toto"]
puis le lancer comme ceci pour le même résultat: docker run redisimg get key
.
La ENTRYPOINT
spécifie une commande qui sera toujours exécutée au démarrage du conteneur.
Le CMD
spécifie les arguments qui seront envoyés au ENTRYPOINT
.
Si vous voulez 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 ENTRYPOINT
non spécifiée et utiliser CMD ["/path/dedicated_command"]
, car vous pourrez remplacer le paramètre en fournissant des arguments à docker run
.
Par exemple, si votre fichier Dockerfile est:
FROM debian:wheezy
ENTRYPOINT ["/bin/ping"]
CMD ["localhost"]
Si vous exécutez l'image sans aucun argument, vous devez envoyer 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, exécuter l'image avec un argument fera un ping de 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 fichier Dockerfile est:
FROM debian:wheezy
CMD ["/bin/ping", "localhost"]
Si vous exécutez l'image sans aucun argument, vous devez envoyer 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 exécuter l'image avec un argument lancera l'argument:
docker run -it test bash
root@e8bb7249b843:/#
Voir cet article de Brian DeHamer pour plus de détails: https://www.ctl.io/developers/blog/post/dockerfile-entrypoint-vs-cmd/
Selon docker docs ,
Les instructions CMD et ENTRYPOINT déterminent quelle commande doit être exécutée lors de l'exécution d'un conteneur. Peu de règles décrivent leur coopération.
- Dockerfile doit spécifier au moins une des commandes
CMD
ouENTRYPOINT
.ENTRYPOINT
devrait être défini lors de l'utilisation du conteneur en tant qu'exécutable.CMD
doit être utilisé pour définir les arguments par défaut d'une commandeENTRYPOINT
ou pour exécuter une commande ad-hoc dans un conteneur.CMD
sera remplacé lors de l'exécution du conteneur avec des arguments alternatifs.
Les tableaux ci-dessous indiquent la commande exécutée pour différentes combinaisons 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 exec_cmd p1_cmd ║
╟────────────────────────────╫───────────────────────────────────────────────────────────╢
║ CMD [“p1_cmd”, “p2_cmd”] ║ /bin/sh -c exec_entry p1_entry p1_cmd p2_cmd ║
╟────────────────────────────╫───────────────────────────────────────────────────────────╢
║ CMD exec_cmd p1_cmd ║ /bin/sh -c exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd ║
╚════════════════════════════╩═══════════════════════════════════════════════════════════╝
_
- 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 ║
╚════════════════════════════╩═════════════════════════════════════════════════╝
_
Oui, c'est une bonne question. Je ne comprends pas encore tout à fait, mais:
Je comprends que ENTRYPOINT
est le binaire en cours d’exécution. Vous pouvez outrepasser le point d’entrée avec --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 en tant qu'argument. Vous pouvez émuler une commande avec entrypoint.
# no entrypoint
docker run ubuntu /bin/cat /etc/passwd
# with entry point, emulating cat command
docker run --entrypoint="/bin/cat" ubuntu /etc/passwd
Donc, le principal avantage est qu'avec entrypoint, 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
Différence entre CMD et ENTRYPOINT par intuition:
Oui, ça se mélange.
Vous pouvez remplacer n'importe lequel d'entre 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 CMD
et ENTRYPOINT
:
L'argument à docker run
tel que/bin/bash annule toute commande CMD que nous avons écrite dans Dockerfile.
ENTRYPOINT ne peut pas être annulé au moment de l'exécution avec des commandes normales telles que docker run [args]
. Les args
à la fin de docker run [args]
sont fournis en tant qu'arguments à ENTRYPOINT. De cette façon, nous pouvons créer un container
qui ressemble à un binaire normal tel que ls
.
Ainsi, CMD peut agir comme paramètre par défaut pour ENTRYPOINT, puis nous pouvons redéfinir les arguments de CMD à partir de [args].
ENTRYPOINT peut être remplacé par --entrypoint
.
En un mot:
Si vous avez besoin de plus de détails ou si vous souhaitez voir des exemples différents, voici un article de blog qui compare de manière exhaustive CMD et ENTRYPOINT avec de nombreux exemples - http://goinbigdata.com/docker-run-vs-cmd- vs-entrypoint /
La réponse acceptée est fabuleuse pour expliquer l'histoire. Je trouve ce tableau très bien expliqué par doc officiel sur 'l'interaction entre CMD et ENTRYPOINT' :
Commentaires sur la fonction EntryPoint dans code
// ENTRYPOINT/usr/sbin/nginx.
// Définissez le point d'entrée (par défaut, sh -c) sur/usr/sbin/nginx.
// Acceptera le CMD en tant qu'arguments dans/usr/sbin/nginx.
Une autre référence de documents
Vous pouvez utiliser la forme exec de ENTRYPOINT pour définir des commandes et des arguments par défaut relativement stables , puis utiliser CMD pour définir des valeurs par défaut supplémentaires susceptibles d'être modifiées.
Exemple:
FROM ubuntu:14.04.3
ENTRYPOINT ["/bin/ping"]
CMD ["localhost", "-c", "2"]
Construire : 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
p.s: En présence de EntryPoint, CMD conservera les arguments à transmettre à EntryPoint. En l'absence de EntryPoint, CMD sera la commande qui sera exécutée.
La commande CMD
mentionnée dans le fichier Dockerfile
peut être remplacée par la commande docker run
alors que ENTRYPOINT
ne peut pas l'être.
CMD:
CMD ["executable","param1","param2"]
: ["executable","param1","param2"]
est le premier processus.CMD command param1 param2
: /bin/sh -c CMD command param1 param2
est le premier processus. CMD command param1 param2
est créé à partir du premier processus.CMD ["param1","param2"]
: Ce formulaire permet de fournir des arguments par défaut pour ENTRYPOINT
.ENTRYPOINT (La liste suivante ne considère pas 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 param2
est le premier processus. command param1 param2
est créé à partir du premier processus.Comme creack , CMD a été développé en premier. Ensuite, ENTRYPOINT a été développé pour plus de personnalisation. Comme ils ne sont pas conçus ensemble, certaines fonctionnalités se chevauchent entre CMD et ENTRYPOINT, ce qui confond souvent les utilisateurs.
La plupart des gens l'expliquent parfaitement ici, alors je ne vais pas répéter toutes les réponses. Mais pour avoir une bonne impression, je suggérerais de le tester vous-même en examinant les processus décrits dans le conteneur.
Créez un petit fichier Docker de la forme:
FROM ubuntu:latest
CMD /bin/bash
Construisez-le, exécutez-le avec docker run -it theimage
et exécutez ps -eo ppid,pid,args
dans le conteneur. Comparez cette sortie à celle que vous recevez de ps lorsque vous utilisez:
docker run -it theimage bash
ENTRYPOINT /bin/bash
et exécution dans les deux sensCMD ["/bin/bash"]
De cette façon, vous verrez facilement les différences entre toutes les méthodes possibles pour vous-même.
Je vais ajouter ma réponse à titre d'exemple1 cela pourrait vous aider à mieux comprendre la différence.
Supposons que nous voulions créer une image qui toujours exécutera une commande de veille 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
Que faire si nous voulons changer le nombre de secondes? Nous devrions changer le Dockerfile
car la valeur y est codée en dur, ou remplacer la commande en fournissant un autre:
docker run custom_sleep sleep 20
Bien que cela fonctionne, ce n'est pas une bonne solution, car nous avons une commande "sleep" redondante (le conteneur a pour but de sleep, il est donc inutile de spécifier explicitement la commande sleep
entraine toi).
Essayons maintenant d’utiliser l’instruction ENTRYPOINT
:
FROM ubuntu
ENTRYPOINT sleep
Cette instruction spécifie le programme qui sera exécuté au démarrage du conteneur.
Maintenant nous pouvons courir:
docker run custom_sleep 20
Qu'en est-il d'une valeur par défaut? Eh bien, vous l'avez bien compris:
FROM ubuntu
ENTRYPOINT ["sleep"]
CMD ["10"]
La ENTRYPOINT
est le programme qui sera exécuté et la valeur transmise au conteneur lui sera ajoutée.
La ENTRYPOINT
peut être remplacée en spécifiant un indicateur --entrypoint
, suivi du nouveau point d'entrée que vous souhaitez utiliser.
Pas le mien, j'ai déjà regardé un tutoriel qui fournissait cet exemple