Dans les Dockerfiles, il y a deux commandes qui me semblent similaires : CMD
et ENTRYPOINT
. Mais je suppose qu'il y a une différence (subtile ?) entre elles - sinon cela n'aurait aucun sens d'avoir deux commandes pour la même chose.
La documentation indique pour CMD
que
Le but principal d'une 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 comme un 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 lancez Docker comme ceci :
docker run -i -t ubuntu bash
le point d'entrée est le /bin/sh -c
par défaut, 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 la chose qui est exécutée est /bin/sh -c bash
. Cela permet à Docker d'implémenter rapidement RUN
en s'appuyant sur l'analyseur syntaxique 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 passé au point d'entrée. Lorsque vous utilisez l'instruction CMD
, c'est exactement comme si vous 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 à la place cette commande docker run -i -t ubuntu
. Vous lancerez toujours un shell bash dans le conteneur car le [ubuntu Dockerfile][1] spécifie un CMD par défaut : CMD ["bash"]
.
Comme tout est passé au point d'entrée, vous pouvez avoir un comportement très agréable de vos images. L'exemple de @Jiri est bon, il montre comment utiliser une image comme un "binaire". Lorsque vous utilisez ["/bin/cat"]
comme point d'entrée et que vous faites docker run img /etc/passwd
, vous l'obtenez, /etc/passwd
est la commande et est passée au point d'entrée donc le résultat final de l'exécution est simplement /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 d'exécuter docker run redisimg redis -H something -u toto get key
, vous pouvez simplement avoir ENTRYPOINT ["redis", "-H", "something", "-u", "toto"]
et ensuite exécuter comme ceci pour le même résultat : docker run redisimg get key
.
[1] : https://github.com/dockerfile/ubuntu/blob/master/Dockerfile
Le ENTRYPOINT
spécifie une commande qui sera toujours exécutée au démarrage du conteneur.
Le CMD
spécifie les arguments qui seront fournis à l'ENTRYPOINT
.
Si vous voulez faire une image dédiée à une commande spécifique, vous utiliserez ENTRYPOINT ["/path/dedicated_command"]
.
Sinon, si vous voulez faire une image pour un usage général, vous pouvez laisser ENTRYPOINT
non spécifié et utiliser CMD ["/path/dedicated_command"]
car vous serez en mesure de passer outre ce 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 provoquera un ping sur 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 va envoyer un ping à 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"]
En exécutant l'image sans aucun argument, vous ferez un ping sur 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 en exécutant l'image avec un argument, l'argument sera exécuté :
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/
Oui, c'est une bonne question. Je ne la comprends pas encore complètement, mais.. :
Je comprends que ENTRYPOINT
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 entrypoint.
# no entrypoint
docker run ubuntu /bin/cat /etc/passwd
# with entry point, emulating cat command
docker run --entrypoint="/bin/cat" ubuntu /etc/passwd
Ainsi, l'avantage principal 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