Mehrere Befehle in der Docker-CMD-Direktive

Ich verstehe nicht, was passiert, wenn ich versuche, zwei Befehle zur Laufzeit über die CMD-Direktive in `Dockerfile' auszuführen. Ich nahm an, dass das funktionieren sollte:

CMD ["/etc/init.d/nullmailer", "start", ";", "/usr/sbin/php5-fpm"]

Aber es funktioniert nicht. Container hat nicht gestartet. Also musste ich es so machen:

CMD ["sh", "-c", "/etc/init.d/nullmailer start ; /usr/sbin/php5-fpm"]

Ich verstehe es nicht. Warum ist das so? Warum ist die erste Zeile nicht der richtige Weg? Kann mir jemand diese "CMD Shell Format vs JSON Format, etc" Sachen erklären. In einfachen Worten.

Nur zu beachten - das gleiche war mit command: richtlinie in docker-compose.yml, wie erwartet.

Ich glaube, der Unterschied könnte darin liegen, dass der zweite Befehl die Shell-Verarbeitung ausführt, während der erste dies nicht tut. Pro die offizielle Dokumentation, es gibt die exec und shell Forms. Ihr erster Befehl ist ein exec Form. Der exec formular erweitert Umgebungsvariablen nicht, während die shell die Form tut es. Es ist möglich, dass durch die Verwendung der exec formular Der Befehl schlägt aufgrund seiner Abhängigkeit von der Shell-Verarbeitung fehl. Sie können dies überprüfen, indem Sie ausführen docker logs CONTAINERID

Ihr zweiter Befehl, das Shell-Formular, entspricht -

CMD /etc/init.d/nullmailer start ; /usr/sbin/php5-fpm

Auszüge aus der Dokumentation -

Hinweis: Im Gegensatz zum Shell-Formular ruft das exec-Formular keine Befehlsshell auf. Dies bedeutet, dass keine normale Shell-Verarbeitung stattfindet. Beispielsweise, CMD [ "echo", "$HOME" ] wird keine Variablensubstitution durchführen $HOME. Wenn Sie eine Shell-Verarbeitung wünschen, verwenden Sie entweder das Shell-Formular oder führen Sie beispielsweise direkt eine Shell aus: CMD [ "sh", "-c", "echo", "$HOME" ].

Mach es dir nicht selbst schwer. Erstellen Sie einfach eine Bash-Datei "start.sh":

#!/bin/bash/usr/bin/command2 param1/usr/bin/command1

in deiner Docker-Datei mache:

ADD start.sh /RUN chmod +x /start.shCMD ["/start.sh"]

Die JSON-Syntax von CMD (und RUN und ENTRYPOINT) übergeben Sie die Argumente direkt als exec-Systemaufruf an den Kernel. Es gibt keine Trennung des Befehls von den Argumenten durch Leerzeichen, Escapen von Anführungszeichen, E / A-Umleitung, Variablenersetzung, Weiterleitung zwischen Befehlen, Ausführen mehrerer Befehle usw. im exec-Systemaufruf. Der Systemaufruf benötigt nur die ausführbare Datei und die Liste der Argumente, die an diese ausführbare Datei übergeben werden sollen, und führt sie aus.

Charaktere wie $ so erweitern Sie Variablen, ; um Befehle zu trennen, (Leerzeichen) zum Trennen von Argumenten, && und || um Befehle zu verketten, > für die Ausgabeumleitung, | pipe zwischen Befehlen usw. sind alle Funktionen der Shell und benötigen so etwas wie /bin/sh oder /bin/bash sie zu interpretieren und umzusetzen.


Wenn Sie zur String-Syntax von wechseln CMD, docker wird Ihren Befehl mit einer Shell ausführen:

CMD /etc/init.d/nullmailer start ; /usr/sbin/php5-fpm

Andernfalls macht Ihre zweite Syntax genau dasselbe:

CMD ["sh", "-c", "/etc/init.d/nullmailer start ; /usr/sbin/php5-fpm"]

Beachten Sie, dass ich nicht empfehle, mehrere Befehle auf diese Weise in einem Container auszuführen, da es keine Fehlerbehandlung gibt, wenn Ihr erster Befehl fehlschlägt, insbesondere wenn er im Hintergrund ausgeführt wird. Sie lassen auch eine Shell als pid 1 im Container laufen, wodurch die Signalverarbeitung unterbrochen wird, was zu einer Verzögerung von 10 Sekunden und einem ungnädigen Beenden Ihres Containers durch Docker führt. Die Signalbehandlung kann durch Verwendung der Shell gemildert werden exec Befehl:

CMD /etc/init.d/nullmailer start ; exec /usr/sbin/php5-fpm

Um jedoch Prozesse zu behandeln, die im Hintergrund stillschweigend fehlschlagen, müssen Sie zu einer Art Multi-Prozess-Manager wie Supervisord wechseln oder Ihre Anwendung vorzugsweise in mehrere Container aufteilen und diese mit so etwas wie docker-compose bereitstellen.

Ich denke, der erste Befehl schlägt fehl, weil im DOCKER-CMD-Formular nur der erste Parameter ausgeführt wird und der Rest in diesen Befehl eingegeben wird.

Die zweite Form funktioniert, weil alle Befehle, die mit ";" getrennt sind, in den Befehl sh eingegeben werden, der sie ausführt.

Stellen Sie sich beispielsweise vor, Sie müssen zwei Python-Befehle ausführen python init_reset.py und python app.py. Dann können Sie mit CMD die beiden Befehle mit dem einzelnen Befehl kombinieren

CMD python init_reset.py ; python app.py

In Docker Compose kann dies wie im folgenden Beispiel geschehen:

command: ["sh", "-c", "    apt update && apt install -y libldap-common;    cp /ca.crt /usr/local/share/ca-certificates/;    update-ca-certificates;    exec apache2-foreground  "]

Der exec schaltet den Kontext der ausführbaren Hauptdatei auf apache2-forground um.

Ich glaube nicht, dass Sie nach "Start" ein Semikomma setzen sollten

anstatt zu verwenden

CMD ["/etc/init.d/nullmailer", "start", ";", "/usr/sbin/php5-fpm"]

versuchen

CMD ["/etc/init.d/nullmailer", "start", "/usr/sbin/php5-fpm"]

da docker "sh -c" verwendet, wird der obige Befehl wie folgt ausgeführt

/etc/init.d/nullmailer start/etc/init.d/nullmailer /usr/sbin/php5-fpm