In Dockerfiles gibt es zwei Befehle, die für mich ähnlich aussehen: "CMD" und "ENTRYPOINT". Aber ich vermute, dass es einen (subtilen?) Unterschied zwischen ihnen gibt - sonst würde es keinen Sinn machen, zwei Befehle für ein und dieselbe Sache zu haben.
In der Dokumentation steht für CMD
Der Hauptzweck eines CMD ist es, Standardeinstellungen für einen ausführenden Container bereitzustellen.
und für ENTRYPOINT
:
Ein ENTRYPOINT hilft Ihnen, einen Container zu konfigurieren, den Sie als ausführbare Datei starten können.
Was ist also der Unterschied zwischen diesen beiden Befehlen?
Docker hat einen Standard-Einstiegspunkt, der /bin/sh -c
ist, aber keinen Standard-Befehl hat.
Wenn Sie Docker wie folgt ausführen:
docker run -i -t ubuntu bash
ist der Einstiegspunkt der Standardwert /bin/sh -c
, das Image ist ubuntu
und der Befehl ist bash
.
Der Befehl wird über den Einstiegspunkt ausgeführt, d.h. das, was tatsächlich ausgeführt wird, ist /bin/sh -c bash
. Dies ermöglichte es Docker, RUN
schnell zu implementieren, indem es sich auf den Parser der Shell verließ.
Später baten die Leute darum, dies anpassen zu können, also wurden ENTRYPOINT
und --entrypoint
eingeführt.
Alles nach ubuntu
im obigen Beispiel ist der Befehl und wird an den Einstiegspunkt übergeben. Wenn Sie die Anweisung CMD
verwenden, ist es genau so, als ob Sie docker run -i -t ubuntu <cmd>
ausführen würden.
Das gleiche Ergebnis erhalten Sie auch, wenn Sie stattdessen den Befehl docker run -i -t ubuntu
eingeben. Sie werden immer noch eine Bash-Shell im Container starten, weil das ubuntu Dockerfile eine Standard-CMD angegeben hat: CMD ["bash"]
Da alles an den Einstiegspunkt übergeben wird, können Sie ein sehr schönes Verhalten von Ihren Images haben. Das Beispiel von @Jiri ist gut, es zeigt, wie man ein Bild als "Binärdatei" verwendet. Wenn man ["/bin/cat"]
als Einstiegspunkt verwendet und dann docker run img /etc/passwd
ausführt, ist /etc/passwd
der Befehl und wird an den Einstiegspunkt übergeben, so dass das Endergebnis der Ausführung einfach /bin/cat /etc/passwd
ist.
Ein anderes Beispiel wäre, einen beliebigen Kli als Einstiegspunkt zu haben. Wenn Sie zum Beispiel ein Redis-Image haben, können Sie, anstatt docker run redisimg redis -H something -u toto get key
auszuführen, einfach ENTRYPOINT ["redis", "-H", "something", "-u", "toto"]
eingeben und dann wie folgt ausführen, um das gleiche Ergebnis zu erhalten: docker run redisimg get key
.
Der ENTRYPOINT
gibt einen Befehl an, der immer ausgeführt wird, wenn der Container startet.
Der CMD
gibt Argumente an, die an den ENTRYPOINT
übergeben werden.
Wenn Sie ein Image für einen bestimmten Befehl erstellen wollen, verwenden Sie ENTRYPOINT ["/pfad/gewidmetes_kommando"]
.
Wenn Sie ein Image für allgemeine Zwecke erstellen wollen, können Sie ENTRYPOINT
nicht angeben und CMD ["/pfad/dedizierter_befehl"]
verwenden, da Sie in der Lage sein werden, die Einstellung zu überschreiben, indem Sie Argumente an docker run
übergeben.
Wenn Ihr Dockerfile zum Beispiel lautet:
FROM debian:wheezy
ENTRYPOINT ["/bin/ping"]
CMD ["localhost"]
Wenn Sie das Image ohne Argumente ausführen, wird der localhost angepiept:
$ 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
Wenn Sie nun das Image mit einem Argument ausführen, wird das Argument angepiept:
$ 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
Zum Vergleich: Wenn Ihr Dockerfile lautet:
FROM debian:wheezy
CMD ["/bin/ping", "localhost"]
Wenn Sie das Image ohne Argumente ausführen, wird der localhost angepiept:
$ 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
Wird das Bild jedoch mit einem Argument ausgeführt, wird das Argument ausgeführt:
docker run -it test bash
root@e8bb7249b843:/#
In diesem Artikel von Brian DeHamer finden Sie weitere Einzelheiten: https://www.ctl.io/developers/blog/post/dockerfile-entrypoint-vs-cmd/
Ja, das ist eine gute Frage. Ich verstehe sie noch nicht ganz, aber:
Ich habe verstanden, dass ENTRYPOINT
die Binärdatei ist, die ausgeführt wird. Sie können den Einstiegspunkt mit --entrypoint="" überschreiben.
docker run -t -i --entrypoint="/bin/bash" ubuntu
CMD ist das Standardargument für den Container. Ohne entrypoint ist das Standardargument der Befehl, der ausgeführt wird. Mit entrypoint wird cmd als Argument an entrypoint übergeben. Sie können einen Befehl mit entrypoint emulieren.
# no entrypoint
docker run ubuntu /bin/cat /etc/passwd
# with entry point, emulating cat command
docker run --entrypoint="/bin/cat" ubuntu /etc/passwd
Der Hauptvorteil ist also, dass man mit entrypoint Argumente (cmd) an den Container übergeben kann. Um dies zu erreichen, müssen Sie beides verwenden:
# Dockerfile
FROM ubuntu
ENTRYPOINT ["/bin/cat"]
und
docker build -t=cat .
dann können Sie verwenden:
docker run cat /etc/passwd
# ^^^^^^^^^^^
# CMD
# ^^^
# image (tag)- using the default ENTRYPOINT