Warum kann ich Docker CMD nicht mehrmals verwenden, um mehrere Dienste auszuführen?


96

Ich habe ein Basis-Image aus Dockerfile mit dem Namen centos + ssh erstellt. In der Docker-Datei von centos + ssh verwende ich CMD, um den ssh-Dienst auszuführen.

Dann möchte ich ein Image erstellen, das einen anderen Dienst namens rabbitmq, die Docker-Datei, ausführt:

FROM centos+ssh
EXPOSE 22
EXPOSE 4149
CMD /opt/mq/sbin/rabbitmq-server start

Um den rabbitmq-Container zu starten, führen Sie Folgendes aus:

docker run -d -p 222:22 -p 4149:4149 rabbitmq

Aber der SSH-Dienst funktioniert nicht. Er erkennt, dass die Dockerfile-CMD von rabbitmq die CMD von centos überschreibt.

  1. Wie funktioniert CMD im Docker-Image?
  2. Wie geht es, wenn ich mehrere Dienste ausführen möchte? Supervisor verwenden?

Antworten:


62

Obwohl CMD in der Docker-Datei notiert ist, handelt es sich tatsächlich um Laufzeitinformationen. Genau wie EXPOSE, aber im Gegensatz zu zB RUN und ADD. Damit meine ich, dass Sie es später überschreiben können, in einer erweiterten Docker-Datei oder einfach in Ihrem Ausführungsbefehl, was Sie erleben. Es kann immer nur eine CMD geben.

Wenn Sie mehrere Dienste ausführen möchten, würde ich in der Tat Supervisor verwenden. Sie können für jeden Dienst eine Supervisor-Konfigurationsdatei erstellen, diese in einem Verzeichnis hinzufügen und den Supervisor mit ausführen supervisord -c /etc/supervisor, um auf eine Supervisor-Konfigurationsdatei zu verweisen, die alle Ihre Dienste lädt und so aussieht

[supervisord]
nodaemon=true

[include]
files = /etc/supervisor/conf.d/*.conf

Wenn Sie weitere Informationen wünschen, habe ich hier einen Blog zu diesem Thema geschrieben: http://blog.trifork.com/2014/03/11/using-supervisor-with-docker-to-manage-processes-supporting-image- Erbe/


Vielen Dank, Supervisor ist eine gute Idee, aber ich frage mich, wie CMD in Docker Image
funktioniert

2
Sie haben zwei Fragen gestellt: 2. zum Ausführen mehrerer Dienste. Wenn Sie sich fragen, wie CMD funktioniert, erläutern Sie bitte, was Sie speziell wissen möchten. Ich habe bereits erwähnt, dass es sich um Laufzeitinformationen handelt und von jedem neuen CMD überschrieben wird.
Qkrijger

118

Sie haben Recht, die zweite Docker-Datei überschreibt den CMDBefehl der ersten. Docker führt immer einen einzelnen Befehl aus, nicht mehr. Am Ende Ihrer Docker-Datei können Sie einen Befehl zum Ausführen angeben . Nicht mehr.

Sie können jedoch beide Befehle in einer Zeile ausführen:

FROM centos+ssh
EXPOSE 22
EXPOSE 4149
CMD service sshd start && /opt/mq/sbin/rabbitmq-server start

Was Sie auch tun können, um Ihre Docker-Datei ein wenig sauberer zu machen, können Sie Ihre CMD-Befehle in eine zusätzliche Datei einfügen:

FROM centos+ssh
EXPOSE 22
EXPOSE 4149
CMD sh /home/centos/all_your_commands.sh

Und eine Datei wie diese:

service sshd start &
/opt/mq/sbin/rabbitmq-server start

1
Vielen Dank, ich denke, Use Supervisor ist besser. Aber warum Docker nur eine CMD ausführen? Was passiert im Inneren?
Edwardsbean

1
Ich weiß nicht, was drinnen passiert. Aber ich denke, es ist einfach so gestaltet. Wenn Sie ein Image haben und einen Befehl darin ausführen (z. B. mit CMD), wird ein Container gestartet. Der Container wird ausgeführt, solange der Befehl ausgeführt wird. Sobald der Befehl beendet ist, stoppt auch der Container. Jeder Container repräsentiert also einen einzelnen (laufenden) Befehl.
Thomas Uhrig

Ich denke, vielleicht liegt es an lcx oder etwas anderem
edwardsbean

2
@ Tyguy7 .. weil ................?
StartupGuy

1
&&Die Technik funktioniert nur mit nicht interaktiven Diensten (die im Hintergrund beginnen können), andernfalls wird nur der erste ausgeführt.
Noraj

26

Obwohl ich die Antwort von qkrijger respektiere, in der erklärt wird, wie Sie dieses Problem umgehen können, denke ich, dass wir noch viel mehr darüber lernen können, was hier vor sich geht ...

Um Ihre Frage nach dem " Warum " tatsächlich zu beantworten ... Ich denke, es wäre hilfreich, wenn Sie verstehen würden, wie der docker stopBefehl funktioniert und dass alle Prozesse sauber heruntergefahren werden sollten , um Probleme beim Neustart zu vermeiden (Dateibeschädigung usw.).

Problem: Was passiert , wenn Docker hat Anfang SSH von ihm Befehl und RabbitMQ aus Ihrer Docker Datei gestartet? " Der Docker-Stopp-Befehl versucht, einen laufenden Container zuerst zu stoppen, indem ein SIGTERM-Signal an den Root-Prozess (PID 1) im Container gesendet wird. " Welcher Prozess verfolgt Docker als PID 1, der das SIGTERM erhält? Wird es SSH oder Rabbit sein? "Gemäß dem Unix-Prozessmodell erbt der Init-Prozess - PID 1 - alle verwaisten untergeordneten Prozesse und muss sie ernten. Die meisten Docker-Container verfügen nicht über einen Init-Prozess, der dies korrekt ausführt, und infolgedessen werden ihre Container mit gefüllt Zombie-Prozesse im Laufe der Zeit. "

Antwort: Docker nimmt einfach das letzte CMD als dasjenige , das als Root-Prozess mit PID 1 gestartet wird und von dem das SIGTERM abgerufen wird docker stop.

Lösungsvorschlag: Sie sollten ein Basis-Image verwenden (oder erstellen), das speziell für die Ausführung mehrerer Dienste erstellt wurde, z. B. Phusion / Baseimage

Es sollte wichtig sein zu beachten, dass tini genau aus diesem Grund existiert. Ab Docker 1.13 und höher ist tini offiziell Teil von Docker, was uns sagt, dass das Ausführen von mehr als einem Prozess in Docker GÜLTIG ist . Selbst wenn jemand dies behauptet Seien Sie in Bezug auf Docker geschickter und bestehen Sie darauf, dass Sie absurd sind, wenn Sie daran denken, dies zu tun, und wissen, dass Sie es nicht sind. Dafür gibt es durchaus gültige Situationen.

Gut zu wissen:


3

Die offizielle Docker-Antwort auf Mehrere Dienste in einem Container ausführen .

Es wird erklärt, wie Sie dies mit einem Init-System (systemd, sysvinit, upstart), einem Skript ( CMD ./my_wrapper_script.sh) oder einem Supervisor wie tun können supervisord.

Die &&Problemumgehung kann nur für Dienste verwendet werden, die im Hintergrund beginnen (Daemons) oder die ohne Interaktion schnell ausgeführt werden und die Eingabeaufforderung freigeben. Wenn Sie dies mit einem interaktiven Dienst tun (der die Eingabeaufforderung beibehält), wird nur der erste Dienst gestartet.


0

Um herauszufinden, warum CMD nur einen Dienst pro Container ausführen soll, wollen wir uns nur vorstellen, was passieren würde, wenn die sekundären Server, die im selben Container ausgeführt werden, nicht trivial / auxiliary, sondern "major" sind (z. B. mit der Frontend-App gebündelter Speicher). Für den Anfang würde es mehrere wichtige Containerisierungsfunktionen wie horizontale (automatische) Skalierung und Neuplanung zwischen Knoten aufschlüsseln, die beide davon ausgehen, dass es nur eine Anwendung (Quelle der CPU-Auslastung) pro Container gibt. Dann gibt es das Problem der Sicherheitslücken - mehr Server in einem Container bedeuten häufigeres Patchen von CVEs ...

Lassen Sie uns also zugeben, dass es ein "Anstoß" von Docker- (und Kubernetes / Openshift-) Designern zu bewährten Praktiken ist und wir Problemumgehungen nicht neu erfinden sollten (SSH ist nicht erforderlich - wir haben docker exec / kubectl exec / oc rshentworfen, um es zu ersetzen).

  • Mehr Info

/devops/447/why-it-is-recommended-to-run-only-one-process-in-a-container

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.