Jaka jest różnica między CMD a ENTRYPOINT w Dockerfile?

1696

W Dockerfiles są dwa polecenia, które wyglądają podobnie do mnie: CMDi ENTRYPOINT. Ale wydaje mi się, że istnieje (subtelna?) Różnica między nimi - w przeciwnym razie nie byłoby sensu mieć dwóch poleceń dla tej samej rzeczy.

Dokumentacja stwierdza dla CMD

Głównym celem CMD jest zapewnienie wartości domyślnych dla wykonującego kontenera.

i dla ENTRYPOINT:

ENTRYPOINT pomaga skonfigurować kontener, który można uruchomić jako plik wykonywalny.

Jaka jest różnica między tymi dwoma poleceniami?

Golo Roden
źródło
12
Ten post na blogu zawiera dobry opis różnic i sposobu, w jaki można je również wykorzystać razem: crosbymichael.com/dockerfile-best-practices.html .
slm
2
^ to! Dzięki @slm. Oto inne bardzo podobne odniesienie, które może być nieco bardziej aktualne: docs.docker.com/reference/builder/#entrypoint
Adam Monsen
5
Jak mylące jako różnicę między ADDiCOPY
Raedwald
1
Ten link zapewnia różnicę między RUN, CMD i ENTRYPOINT: goinbigdata.com/docker-run-vs-cmd-vs-entrypoint
prafi
Zauważ tylko, że CMDi ENTRYPOINToba mają różne formy do napisania, exec i shell . Więc wyświadcz sobie przysługę i zrozum subtelne różnice w zachowaniu w zależności od używanej formy. Następnie przeczytaj docs.docker.com/engine/reference/builder/… .
Jaime Hablutzel,

Odpowiedzi:

1733

Docker ma domyślny punkt wejścia, który jest, /bin/sh -cale nie ma domyślnego polecenia.

Po uruchomieniu dokera w ten sposób: docker run -i -t ubuntu bash punktem wejściowym jest wartość domyślna /bin/sh -c, obraz to ubuntui polecenie to bash.

Polecenie jest uruchamiane przez punkt wejścia. tzn. faktyczną rzeczą, która zostanie wykonana, jest /bin/sh -c bash. To pozwoliło Dockerowi na RUNszybką implementację , polegając na parserze powłoki.

Później, ludzie pytali, aby móc dostosować to, więc ENTRYPOINTi --entrypointzostały wprowadzone.

Wszystko ubuntuw powyższym przykładzie jest poleceniem i jest przekazywane do punktu wejścia. Podczas korzystania z CMDinstrukcji jest dokładnie tak, jakbyś to robił docker run -i -t ubuntu <cmd>. <cmd>będzie parametrem punktu wejścia.

Ten sam wynik otrzymasz również, jeśli zamiast tego wpiszesz to polecenie docker run -i -t ubuntu. Nadal uruchomisz powłokę bash w kontenerze, ponieważ plik Docker w Ubuntu określił domyślną CMD:CMD ["bash"]

Ponieważ wszystko jest przekazywane do punktu wejścia, możesz mieć bardzo ładne zachowanie ze swoich zdjęć. @Jiri przykład jest dobry, pokazuje, jak używać obrazu jako „pliku binarnego”. Gdy używasz ["/bin/cat"]jako punktu wejścia, a następnie robisz docker run img /etc/passwd, dostajesz go, /etc/passwdjest to polecenie i jest przekazywane do punktu wejścia, więc wykonanie wyniku końcowego jest po prostu /bin/cat /etc/passwd.

Innym przykładem byłoby posiadanie dowolnego cli jako punktu wejścia. Na przykład, jeśli masz obraz Redis, zamiast biegać docker run redisimg redis -H something -u toto get key, można po prostu mieć ENTRYPOINT ["redis", "-H", "something", "-u", "toto"], a następnie uruchomić w ten sposób do tego samego rezultatu: docker run redisimg get key.

skrzyp
źródło
3
Ani trochę. ENTRYPOINT ustawia metadane, które mogą (ale mogą zostać zastąpione) w czasie wykonywania, więc jeśli niczego nie zmienisz, po uruchomieniu kontenera wynik będzie taki sam, jednak RUN zostanie wyegzekwowany w czasie kompilacji i bez względu na to, co zrobić w czasie wykonywania, będzie tutaj.
creack
8
Domyślnie nie ma ENTRYPOINT; to, czy używana jest powłoka, zależy od użytej formy CMDpolecenia ( docs.docker.com/engine/reference/builder/#cmd ).
Blaisorblade,
19
Dzięki za to kontekst historyczny bardzo mi pomaga, ponieważ starałem się zapamiętać pozornie tajemne zasady dotyczące tego, co jest nadpisywane, a co dołączane itp. Przydatny punkt dla autorów dokumentacji technicznej na całym świecie: pomóż czytelnikowi zbudować model mentalny systemu, nie tylko wymieniaj fakty i scenariusze :-)
ashirley
84
To wspaniała odpowiedź. Myślę, że dokumentacja Docker powinien dodać ten ramach sekcji o nazwie CMDvs ENTRYPOINT.
Tarik
5
@ Webman Nie. Są to dwie różne instrukcje. Jeśli oba istnieją, CMD będzie traktowane jako parametry ENTRYPOINT.
Light.G
627

W ENTRYPOINTOkreśla polecenie, które zawsze będą wykonywane podczas uruchamiania pojemnika.

W CMDOkreśla argumenty, które zostaną wykorzystane do ENTRYPOINT.

Jeśli chcesz zrobić obraz dedykowany do konkretnego polecenia, którego użyjesz ENTRYPOINT ["/path/dedicated_command"]

W przeciwnym razie, jeśli chcesz stworzyć obraz do ogólnego celu, możesz pozostawić ENTRYPOINTnieokreślony i użyć, CMD ["/path/dedicated_command"]ponieważ będziesz w stanie zastąpić ustawienie, podając argumenty do docker run.

Na przykład, jeśli Twój plik Docker to:

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

Uruchomienie obrazu bez żadnego argumentu spowoduje wysłanie polecenia ping do hosta lokalnego:

$ 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

Teraz uruchomienie obrazu z argumentem spowoduje wysłanie polecenia ping do argumentu:

$ 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

Dla porównania, jeśli Twój plik Docker to:

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

Uruchomienie obrazu bez żadnego argumentu spowoduje wysłanie polecenia ping do hosta lokalnego:

$ 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

Ale uruchomienie obrazu z argumentem spowoduje uruchomienie argumentu:

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

Zobacz ten artykuł Briana DeHamera, aby uzyskać jeszcze więcej szczegółów: https://www.ctl.io/developers/blog/post/dockerfile-entrypoint-vs-cmd/

Daishi
źródło
218
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.jest dobrym podsumowaniem.
Jingguo Yao
1
ENTRYPOINT można również zastąpić za pomocą opcji --entrypoint. na przykład docker run -it --entrypoint bash test
seenimurugan
2
Lubię twoje przykłady, to naprawdę pomocne!
Chau Giang,
2
@Jingguo Yao: Co jeśli CMD zawiera polecenie takie jak - CMD [„nginx”, „- g”, „daemon”, „off”]? Czy byłby przykuty?
KMC
@KMC CMD jest domyślnym argumentem ENTRYPOINT, zastępujesz go przekazując nowy argument podczas uruchamiania obrazu.
MGP
237

Zgodnie z docs Döcker ,

Zarówno instrukcje CMD, jak i ENTRYPOINT określają, jakie polecenie zostanie wykonane podczas uruchamiania kontenera. Istnieje kilka zasad opisujących ich współpracę.

  1. Plik Docker powinien określać co najmniej jedno z poleceń CMDlub ENTRYPOINT.
  2. ENTRYPOINT należy zdefiniować, gdy używasz kontenera jako pliku wykonywalnego.
  3. CMDpowinien być używany jako sposób definiowania domyślnych argumentów dla ENTRYPOINTpolecenia lub wykonywania polecenia ad-hoc w kontenerze.
  4. CMD zostanie zastąpione podczas uruchamiania kontenera z alternatywnymi argumentami.

Poniższe tabele pokazują, jakie polecenie jest wykonywane dla różnych ENTRYPOINT/ CMDkombinacji :

- 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
źródło
Co to są px_cmd i exec_entry? Co oznacza, że ​​znajdują się na tej samej linii wykonania? Są przekazywane sobie jako argument? Nawet jeśli /bin/sh -cjest zaangażowany?
Danielo515
1
@ Danielo515 Zarówno „px_cmd”, jak i „exec_entry” są tutaj tylko obojętnymi ciągami znaków. Możesz po prostu zauważyć, że /bin/sh -czostałby dodany do CMD jako przedrostek, podczas gdy CMD jest napisane w wykonywalnej składni (nie w składni listy).
Light.G
1
@royki Jeśli użytkownik określi argumenty do uruchomienia dokera, zastąpią one domyślną określoną w CMD.
donrondadon
2
ENTRYPOINT exec_entry p1_entzostało źle wyjaśnione. Forma powłoki zapobiega użyciu jakichkolwiek argumentów CMD lub wiersza poleceń - docs.docker.com/engine/reference/builder/#entrypoint
Mariusz Miesiak
1
@MariuszMiesiak jest teraz zaktualizowany. Dziękuję za twój komentarz.
Rafaf Tahsin
170

Tak, to dobre pytanie. Jeszcze tego nie rozumiem, ale:

Rozumiem, że ENTRYPOINTto plik binarny, który jest wykonywany. Możesz pominąć punkt wejścia przez --entrypoint = "".

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

CMD jest domyślnym argumentem kontenera. Bez punktu wejścia domyślnym argumentem jest wykonywane polecenie. W przypadku punktu wejścia cmd jest przekazywane do punktu wejścia jako argument. Możesz emulować polecenie za pomocą punktu wejścia.

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

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

Główną zaletą jest to, że za pomocą punktu wejścia można przekazać argumenty (cmd) do kontenera. Aby to osiągnąć, musisz użyć obu:

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

i

docker build -t=cat .

wtedy możesz użyć:

docker run cat /etc/passwd
#              ^^^^^^^^^^^
#                   CMD
#          ^^^      
#          image (tag)- using the default ENTRYPOINT
Jiri
źródło
@Blauhirn W twoim przypadku musisz dodać argumenty do CMD w składni listy i upewnić się, że punkt wejścia, który określiłeś, może przeanalizować twoje argumenty w CMD. Zwykle do punktu wejścia dodam argument „-h”. Następnie mogę wykonać, docker run image_name -haby wyświetlić informacje pomocy dla tego obrazu.
Light.G
1
To najprostsza i jasna odpowiedź.
Eric Wang,
44

Różnica między CMD a ENTRYPOINT według intuicji :

  • ENTRYPOINT: komenda uruchamiana przy uruchomieniu kontenera.
  • CMD: polecenie uruchamiane podczas uruchamiania kontenera lub argumenty ENTRYPOINT, jeśli są określone.

Tak, to się miesza.

Możesz zastąpić dowolny z nich podczas uruchamiania okna dokowanego.

Różnica między CMD a ENTRYPOINT według przykładów :

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

Więcej na temat różnicy między CMDi ENTRYPOINT:

Argument docker runtaki jak / bin / bash zastępuje wszelkie polecenia CMD, które napisaliśmy w Dockerfile.

ENTRYPOINT nie może być nadpisany w czasie wykonywania zwykłymi poleceniami, takimi jak docker run [args]. Na argskońcu docker run [args]są podane jako argumenty dla ENTRYPOINT. W ten sposób możemy stworzyć containernormalny plik binarny, taki jak ls.

Tak więc CMD może działać jako parametry domyślne dla ENTRYPOINT, a następnie możemy zastąpić argumenty CMD z [args].

ENTRYPOINT można zastąpić --entrypoint.

Tomer Ben David
źródło
38

W skrócie:

  • CMD ustawia domyślne polecenia i / lub parametry, które można zastąpić z wiersza poleceń, gdy uruchomiony jest kontener dokera.
  • Polecenie ENTRYPOINT i parametry nie zostaną nadpisane z wiersza polecenia. Zamiast tego wszystkie argumenty wiersza poleceń zostaną dodane po parametrach ENTRYPOINT.

Jeśli potrzebujesz więcej szczegółów lub chciałbyś zobaczyć różnicę na przykład, jest post na blogu, który kompleksowo porównuje CMD i ENTRYPOINT z wieloma przykładami - http://goinbigdata.com/docker-run-vs-cmd-vs-entrypoint/

upitau
źródło
21

Dodaję odpowiedź jako przykład 1 który może pomóc ci lepiej zrozumieć różnicę.

Załóżmy, że chcemy utworzyć obraz, który zawsze uruchamia polecenie uśpienia podczas uruchamiania. Stworzymy własny obraz i określimy nowe polecenie:

FROM ubuntu
CMD sleep 10

Teraz budujemy obraz:

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

Co jeśli chcemy zmienić liczbę sekund? Musielibyśmy zmienić wartość, Dockerfileponieważ wartość jest tam zapisana na stałe, lub zastąpić polecenie, podając inną:

docker run custom_sleep sleep 20

Chociaż to działa, nie jest to dobre rozwiązanie, ponieważ mamy nadmiarowe polecenie „uśpienia” (celem kontenera jest spanie , więc konieczność wyraźnego określenia sleeppolecenia nie jest dobrą praktyką).

Teraz spróbujmy użyć ENTRYPOINTinstrukcji:

FROM ubuntu
ENTRYPOINT sleep

Ta instrukcja określa program, który zostanie uruchomiony podczas uruchamiania kontenera .

Teraz możemy uruchomić:

docker run custom_sleep 20

Co z wartością domyślną? Dobrze zgadłeś:

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

Jest ENTRYPOINTto program, który zostanie uruchomiony, a wartość przekazana do kontenera zostanie do niego dołączona.

ENTRYPOINTMoże być zastąpiona przez określenie --entrypointflagę, a następnie nowy punkt wyjścia, którego chcesz użyć.

Nie mój, kiedyś obejrzałem samouczek z tym przykładem

Maroun
źródło
1
Oto link do samouczka: youtu.be/OYbEWUbmk90 . Może być przydatny dla przyszłych użytkowników.
ChiPlusPlus
7

Komentarze do funkcji EntryPoint w kodzie

// ENTRYPOINT / usr / sbin / nginx.

// Ustaw punkt wejścia (domyślnie sh-c) na / usr / sbin / nginx.

// Akceptuje CMD jako argumenty do / usr / sbin / nginx.

Kolejne odniesienie z dokumentów

Możesz użyć formularza exec ENTRYPOINT, aby ustawić dość stabilne domyślne polecenia i argumenty, a następnie użyć CMD, aby ustawić dodatkowe wartości domyślne, które prawdopodobnie zostaną zmienione.

Przykład:

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

Kompilacja : 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: W obecności EntryPoint, CMD przechowa argumenty do EntryPoint. Wbrew EntryPoint, CMD będzie poleceniem, które zostanie uruchomione.

Tahir Rauf
źródło
3

CMDpolecenie wspomniane w Dockerfilepliku może zostać zastąpione przez docker runpolecenie, podczas gdy ENTRYPOINTnie może być.

anshul
źródło
4
docker run --helppolecenie mówi inaczej:--entrypoint string Overwrite the default ENTRYPOINT of the image
iomv
3

Przeczytałem wszystkie odpowiedzi i chcę podsumować dla lepszego zrozumienia na pierwszy rzut oka:

Po pierwsze, całe polecenie wykonywane w kontenerze składa się z dwóch części: polecenia i argumentów

  • ENTRYPOINT definiuje plik wykonywalny wywoływany podczas uruchamiania kontenera (dla polecenia)

  • CMD określa argumenty przekazywane do ENTRYPOINT (dla argumentów)

W książce Kubernetes In Action wskazuje na to ważną uwagę. (Rozdział 7)

Chociaż możesz użyć instrukcji CMD, aby określić polecenie, które chcesz wykonać podczas uruchamiania obrazu, poprawnym sposobem jest wykonanie go za pomocą instrukcji ENTRYPOINT i podanie CMD tylko wtedy, gdy chcesz zdefiniować domyślne argumenty.

Możesz również przeczytać ten artykuł, aby uzyskać świetne wyjaśnienie w prosty sposób

FGUL
źródło
2

CMD:

  • CMD ["executable","param1","param2"]: ["executable","param1","param2"]to pierwszy proces.
  • CMD command param1 param2: /bin/sh -c CMD command param1 param2to pierwszy proces. CMD command param1 param2jest rozwidlony od pierwszego procesu.
  • CMD ["param1","param2"]: Ten formularz służy do podania domyślnych argumentów dla ENTRYPOINT.

ENTRYPOINT (Poniższa lista nie uwzględnia przypadku, w którym CMD i ENTRYPOINT są używane razem):

  • ENTRYPOINT ["executable", "param1", "param2"]: ["executable", "param1", "param2"]to pierwszy proces.
  • ENTRYPOINT command param1 param2: /bin/sh -c command param1 param2to pierwszy proces. command param1 param2jest rozwidlony od pierwszego procesu.

Jak powiedział Creack , najpierw opracowano CMD. Następnie opracowano ENTRYPOINT dla większej personalizacji. Ponieważ nie są one zaprojektowane razem, niektóre funkcje nakładają się między CMD i ENTRYPOINT, co często myli ludzi.

Jingguo Yao
źródło
2

Większość ludzi wyjaśnia to tutaj doskonale, więc nie powtórzę wszystkich odpowiedzi. Ale aby uzyskać dobre samopoczucie, sugerowałbym przetestowanie go samemu, patrząc na procesy w pojemniku.

Utwórz mały plik Docker formularza:

FROM ubuntu:latest
CMD /bin/bash

Zbuduj, uruchom docker run -it theimagei uruchom ps -eo ppid,pid,argsw kontenerze. Porównaj to wyjście z wyjściem otrzymanym z ps podczas używania:

  • docker run -it theimage bash
  • Przebudowa obrazu, ale z ENTRYPOINT /bin/bash i uruchamianie go na dwa sposoby
  • Za pomocą CMD ["/bin/bash"]
  • ...

W ten sposób z łatwością zobaczysz różnice między wszystkimi możliwymi metodami dla siebie.

Garo
źródło
0

Oficjalna dokumentacja najlepszych praktyk Dockerfile doskonale wyjaśnia różnice. Najlepsze praktyki dotyczące Dockerfile

CMD:

Do uruchomienia oprogramowania zawartego w obrazie należy użyć instrukcji CMD wraz z wszelkimi argumentami. CMD prawie zawsze powinno być stosowane w postaci CMD ["executable", "param1", "param2"…]. Zatem jeśli obraz dotyczy usługi, takiej jak Apache i Rails, uruchomiłbyś coś podobnegoCMD ["apache2","-DFOREGROUND"] . Rzeczywiście, ta forma instrukcji jest zalecana dla każdego obrazu opartego na usługach.

PUNKT WEJŚCIA:

Najlepszym zastosowaniem ENTRYPOINT jest ustawienie głównego polecenia obrazu, co pozwala na uruchomienie tego obrazu tak, jakby to było to polecenie (a następnie użycie CMD jako domyślnych flag).

MIYUKI NARAHARA
źródło