Kakšna je razlika med CMD in ENTRYPOINT v datoteki Docker?

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?

Rešitev

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. `` 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.

Komentarji (12)

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/.

Komentarji (4)

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
Komentarji (3)