Dockerfiles: RUN vs. CMD vs. ENTRYPOINT
Ein Thema, das bei Einsteigern regelmäßig für Verwirrung sorgt, ist die Verwendung von
RUN
Da
Mit
CMD
Im Gegensatz zu
Dieses Dockerfile verwendet Alpine Linux als Basis und führt beim Start eines entsprechenden Containers den
Nach dem Erstellen eines Images mit
Das Besondere an
Dieses Feature wird gleich noch wichtig sein.
ENTRYPOINT
Auch
Jedoch liegt die Mächtigkeit von Entrypoints darin, dass eine
Nachdem ich das Image neu baue, sieht die Ausführung trotz Aufteilung des
Der Einstiegspunkt für einen Container, nämlich
Fazit
Der Anwendungsfall für
Eine
Ein Thema, das bei Einsteigern regelmäßig für Verwirrung sorgt, ist die Verwendung von
RUN
, CMD
und ENTRYPOINT
in Dockerfiles. Grund für die Verwirrung ist wohl, dass alle der genannten Dockerfile-Anweisungen einen CLI-Befehl oder eine ausführbare Datei ausführen. Was machen die Anweisungen und wann sollte ich welche Anweisung verwenden? Darauf möchte ich hier eingehen.RUN
RUN
ist der Befehl, der sich am stärksten von den anderen beiden unterscheidet: Ziel des Dockerfiles ist es, auf Grundlage des Basis-Images ein Dateisystem zu schaffen, in welchem das eigene Projekt ausgeführt werden kann. Um diesen Zustand zu erreichen, müssen Verzeichnisse angelegt, Pakete installiert und Abhängigkeiten heruntergeladen werden. All dies geschieht mit dem RUN
-Befehl im Dockerfile.Da
RUN
das zugrunde liegende Dateisystem modifiziert, wird bei jedem Aufruf des Befehls ein neuer Image-Layer erstellt, der die Änderung im Dateisystem beinhaltet. Für RUN npm ci
wäre die Änderung im Dateisystem beispielsweise ein neu erstelltes node_modules
-Verzeichnis.Mit
RUN
werden also Skripte und Befehle ausgeführt, die man normalerweise als Administrator verwenden würde, um das Betriebssystem einzurichten - oder solche, die man als Entwickler ausführt, um seinen Code lauffähig zu machen.CMD
Im Gegensatz zu
RUN
wird CMD
nicht mehrere Male aufgerufen, um das finale Image vorzubereiten. Stattdessen legt CMD
für das Image ein Default-Kommando fest, das beim Start eines Containers ausgeführt werden soll.
Dockerfile:
FROM alpine:3.9
CMD ["echo", "Hallo vom CMD!"]
Dieses Dockerfile verwendet Alpine Linux als Basis und führt beim Start eines entsprechenden Containers den
echo
-Befehl aus. Dabei könnte auch eine eigene ausführbare Datei aufgerufen werden, wie z. B. ein zuvor kompiliertes Projekt. In der hier verwendeten Exec Form werden die Argumente für das Kommando kommasepariert angehängt.Nach dem Erstellen eines Images mit
docker image build -t my-alpine .
kann ich einen darauf basierenden Container ausführen:
Bash:
$ docker container run my-alpine
Hallo vom CMD!
Das Besondere an
CMD
ist, dass diese Angabe beim Start eines Containers überschrieben werden kann. Die Syntax zum Start eines Containers lautet docker container run [OPTIONS] IMAGE [COMMAND] [ARG...]
, es kann also ein optionaler Befehl mit Argumenten an den Image-Namen angehängt werden, der dann die CMD
-Anweisung des Images überschreibt:
Apache-Konfiguration:
$ docker container run my-alpine echo "Hallo von der Konsole!"
Hallo von der Konsole!
Dieses Feature wird gleich noch wichtig sein.
ENTRYPOINT
Auch
ENTRYPOINT
legt einen Befehl fest, der beim Start eines Containers ausgeführt werden soll. Anders als CMD
wird er jedoch nicht von docker container run
überschrieben. Damit eignen sich Entrypoints gut für Container, die immer das selbe Programm ausführen sollen, also selbst als eine Art Executable fungieren.Jedoch liegt die Mächtigkeit von Entrypoints darin, dass eine
CMD
-Anweisung immer an die ENTRYPOINT
-Anweisung angehängt wird. Mit einem einfachen Dockerfile lässt sich das bestätigen:
Dockerfile:
FROM alpine:3.9
ENTRYPOINT ["echo"]
CMD ["Hallo vom CMD"]
Nachdem ich das Image neu baue, sieht die Ausführung trotz Aufteilung des
echo
-Befehls wie folgt aus:
Bash:
$ docker container run my-alpine
Hallo vom CMD
CMD
ist dabei aber nach wie vor überschreibbar. Das bedeutet, dass ich hier die Argumente für echo
überschreiben kann, da der "Command" genau wie vorher einfach an den Entrypoint angehängt wird.
Bash:
$ docker container run my-alpine "Hallo von der Konsole"
Hallo von der Konsole
Der Einstiegspunkt für einen Container, nämlich
ENTRYPOINT
, bleibt also immer gleich. So ist es möglich, für einen Container einen fixen Befehl als Entrypoint festzulegen, der immer ausgeführt wird - und zusätzlich mit CMD
Default-Argumente dafür anzugeben, die mit docker container run
überschrieben werden können.Fazit
Der Anwendungsfall für
RUN
sollte klar sein.ENTRYPOINT
sollte bei Containern verwendet werden, deren einziger Zweck es ist, einen bestimmten Dienst auszuführen. Der entsprechende Befehl sollte als Entrypoint definiert werden. Mit CMD
können dann Default-Argumente für diesen Befehl angegeben und bei Bedarf vom Nutzer überschrieben werden.Eine
CMD
-Anweisung ohne zugehörigem Entrypoint kann dann sinnvoll sein, wenn standardmäßig ein bestimmter Befehl ausgeführt werden soll, der aber jederzeit vollständig mit docker container run
überschrieben werden kann.