V datotekah Dockerfiles sta dva ukaza, ki se mi zdita podobna: CMD
in ENTRYPOINT
. Toda domnevam, da med njima obstaja (subtilna?) razlika - sicer ne bi bilo smiselno imeti dva ukaza za isto stvar.
V dokumentaciji je za CMD
navedeno
Glavni namen CMD je zagotoviti privzete nastavitve za izvajalni vsebnik.
in za ENTRYPOINT
:
ENTRYPOINT vam pomaga konfigurirati vsebnik, ki ga lahko zaženete kot izvršilno datoteko.
Kakšna je torej razlika med tema dvema ukazoma?
Docker ima privzeto vstopno točko, ki je /bin/sh -c
, vendar nima privzetega ukaza.
Ko zaženete docker na naslednji način:
docker run -i -t ubuntu bash
je vstopna točka privzeta /bin/sh -c
, slika je ubuntu
, ukaz pa bash
.
Ukaz se zažene prek vstopne točke, tj. dejansko se izvede ukaz /bin/sh -c bash
. To je Dockerju omogočilo hitro izvajanje RUN
z zanašanjem na razčlenjevalnik lupine.
Kasneje so ljudje zahtevali, da bi lahko to prilagodili, zato sta bila uvedena ENTRYPOINT
in --entrypoint
.
Vse za ubuntu
v zgornjem primeru je ukaz in se posreduje vstopni točki. Pri uporabi navodila CMD
je to popolnoma enako, kot če bi naredili docker run -i -t ubuntu <cmd>
. <cmd>
bo parameter vstopne točke.
Enak rezultat boste dobili tudi, če namesto tega vnesete ta ukaz docker run -i -t ubuntu
. Še vedno boste v vsebniku zagnali lupino bash, saj je v datoteki ubuntu Dockerfile določen privzeti CMD: CMD ["bash"]
Ker je vse posredovano vstopni točki, se lahko vaše slike obnašajo zelo lepo. Primer @Jiri je dober, saj prikazuje, kako uporabiti sliko kot "binarno datoteko". Če kot vstopno točko uporabite ["/bin/cat"]
in nato izvedete docker run img /etc/passwd
, dobite, /etc/passwd
je ukaz in je posredovan vstopni točki, zato je končni rezultat izvedbe preprosto /bin/cat /etc/passwd
.
Drug primer bi bil, če bi kot vstopno točko imeli katerikoli cli. Če imate na primer sliko redis, lahko namesto docker run redisimg redis -H something -u toto get key
preprosto zaženete ENTRYPOINT ["redis", "-H", "something", "-u", "toto"]
in nato za enak rezultat izvedete takole: docker run redisimg get key
.
ENTRYPOINT
določa ukaz, ki se vedno izvede ob zagonu vsebnika.
Parameter CMD
določa argumente, ki bodo posredovani ukazu ENTRYPOINT
.
Če želite ustvariti sliko, namenjeno določenemu ukazu, uporabite ENTRYPOINT ["/path/dedicated_command"]
Če želite ustvariti sliko za splošne namene, lahko pustite ENTRYPOINT
neopredeljen in uporabite CMD ["/path/dedicated_command"]
, saj boste lahko to nastavitev prekrili z navedbo argumentov v docker run
.
Če je na primer vaša datoteka Docker:
FROM debian:wheezy
ENTRYPOINT ["/bin/ping"]
CMD ["localhost"]
Če zaženete sliko brez argumenta, bo ping na lokalnem gostitelju:
$ 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
Če zaženete sliko z argumentom, bo slika sporočila ping na 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
Za primerjavo, če je vaša datoteka Docker:
FROM debian:wheezy
CMD ["/bin/ping", "localhost"]
Če zaženete sliko brez argumenta, bo ping na lokalnem gostitelju:
$ 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
Če pa zaženete sliko z argumentom, se bo zagnal argument:
docker run -it test bash
root@e8bb7249b843:/#
Za še več podrobnosti si oglejte ta članek Briana DeHamerja: https://www.ctl.io/developers/blog/post/dockerfile-entrypoint-vs-cmd/.
Da, to je dobro vprašanje. Ne razumem ga še v celoti, vendar:
Razumem, da je ENTRYPOINT
binarni program, ki se izvaja. Vstopno točko lahko zamenjate z --entrypoint="".
docker run -t -i --entrypoint="/bin/bash" ubuntu
CMD je privzeti argument za vsebnik. Brez vstopne točke je privzeti argument ukaz, ki se izvede. Z vstopno točko se cmd posreduje vstopni točki kot argument. Z vstopno točko lahko posnemate ukaz.
# no entrypoint
docker run ubuntu /bin/cat /etc/passwd
# with entry point, emulating cat command
docker run --entrypoint="/bin/cat" ubuntu /etc/passwd
Glavna prednost je torej ta, da lahko z vstopno točko posodi posredujete argumente (cmd). Če želite to doseči, morate uporabiti oboje:
# Dockerfile
FROM ubuntu
ENTRYPOINT ["/bin/cat"]
in .
docker build -t=cat .
potem lahko uporabite:
docker run cat /etc/passwd
# ^^^^^^^^^^^
# CMD
# ^^^
# image (tag)- using the default ENTRYPOINT