Warum Docker Container sofort beendet wird


239

Ich starte einen Container im Hintergrund mit

 docker run -d --name hadoop h_Service

es geht schnell. Aber wenn ich im Vordergrund renne, funktioniert es gut. Ich habe die Protokolle mit überprüft

docker logs hadoop

Es gab keinen Fehler. Irgendwelche Ideen?

DOCKERFILE

 FROM java_ubuntu_new
 RUN wget http://archive.cloudera.com/cdh4/one-click-install/precise/amd64/cdh4-repository_1.0_all.deb
 RUN dpkg -i cdh4-repository_1.0_all.deb
 RUN curl -s http://archive.cloudera.com/cdh4/ubuntu/precise/amd64/cdh/archive.key | apt-key add -
 RUN  apt-get update
 RUN apt-get install -y hadoop-0.20-conf-pseudo
 RUN dpkg -L hadoop-0.20-conf-pseudo
 USER hdfs
 RUN hdfs namenode -format
 USER root
 RUN apt-get install -y sudo
 ADD . /usr/local/
 RUN chmod 777 /usr/local/start-all.sh
 CMD ["/usr/local/start-all.sh"]

start-all.sh

 #!/usr/bin/env bash
 /etc/init.d/hadoop-hdfs-namenode start
 /etc/init.d/hadoop-hdfs-datanode start
 /etc/init.d/hadoop-hdfs-secondarynamenode start
 /etc/init.d/hadoop-0.20-mapreduce-tasktracker start
 sudo -u hdfs hadoop fs -chmod 777 /
 /etc/init.d/hadoop-0.20-mapreduce-jobtracker start
 /bin/bash

1
Die goldene Regel lautet, dass Sie verhindern sollten, dass Ihre Docker-Server dämonisiert werden. Die meisten Serverpakete haben Optionen, um sie in den Vordergrund zu stellen, da Daemonisierung der Normalfall ist.
Arnaud Meuret

Was immer Sie erreichen wollen, chmod 777ist unsicher und falsch. Sie sollten zu normalen Berechtigungen zurückkehren (in diesem Fall wahrscheinlich 755).
Tripleee

Antworten:


125

Ein Docker-Container wird beendet, wenn sein Hauptprozess abgeschlossen ist.

In diesem Fall wird es beendet, wenn Ihr start-all.shSkript endet. Ich weiß nicht genug über Hadoop, um Ihnen zu sagen, wie es in diesem Fall geht, aber Sie müssen entweder etwas im Vordergrund laufen lassen oder einen Prozessmanager wie Runit oder Supervisord verwenden, um die Prozesse auszuführen.

Ich denke, Sie müssen sich irren, wenn Sie nicht angeben -d; es sollte genau den gleichen Effekt haben. Ich vermute, Sie haben es mit einem etwas anderen Befehl gestartet oder mit einem Befehl, -itder die Dinge ändert.

Eine einfache Lösung könnte darin bestehen, Folgendes hinzuzufügen:

while true; do sleep 1000; done

bis zum Ende des Skripts. Ich mag das jedoch nicht, da das Skript wirklich die Prozesse überwachen sollte, die es gestartet hat.

(Ich sollte sagen, ich habe diesen Code von https://github.com/sequenceiq/hadoop-docker/blob/master/bootstrap.sh gestohlen. )


217

Das hat den Trick für mich getan:

docker run -dit ubuntu

Danach habe ich nach folgenden Prozessen gesucht:

docker ps -a

Zum erneuten Anbringen des Behälters

docker attach CONTAINER_NAME

TIPP: Zum Beenden ohne Anhalten des Containertyps: ^P^Q


15
@Tommy, von docs.docker.com/engine/reference/commandline/run -d, --detach Freistehender Modus: Befehl im Hintergrund ausführen, -i, --interactive STDIN offen halten, auch wenn nicht angehängt, -t, - -tty Ein Pseudo-TTY -dit

3
@ am17torres richtig, sorry, lass mich meine verwirrende Frage klären; d ist losgelöst und ich bin interaktiv, daher ist die Kombination von d und i für mich verwirrend. Ich dachte, ich würde es als Hintergrundprozess (nicht interaktiv) starten.
Tommy

2
@Tommy Wenn diese Optionen kombiniert werden, wechselt der Container im Hintergrund in den interaktiven Modus .
Yon

2
@ Tommy, @ am17torres -diist das erforderliche Minimum, die -tOption ist redundant, wenn sie verwendet wird, -dwenn ich das richtig verstehe
Renaud

2
Eigentlich können Sie Ihre Eingabeaufforderung nicht sehen, wenn Sie sie ohne Aktivierung wieder -tanbringen ... aber da ich normalerweise execjedes Mal eine neue Bash bekomme, merke ich es nicht. Ich hatte Probleme, mich von einem Mac zu lösen, aber vielleicht mache ich das falsch.
Renaud

65

Ich möchte erweitern oder es wagen zu sagen, die von Camposer erwähnte Antwort zu verbessern

Wenn du rennst

docker run -dit ubuntu

Grundsätzlich führen Sie den Container im interaktiven Modus im Hintergrund aus.

Wenn Sie den Container mit STRG + D anhängen und verlassen (am häufigsten), stoppen Sie den Container, weil Sie gerade den Hauptprozess abgebrochen haben, den Sie mit dem obigen Befehl gestartet haben.

Wenn ich einen bereits laufenden Container ausnutzen würde, würde ich einfach einen weiteren Bash-Prozess abspalten und ein Pseudo-TTY erhalten, indem ich Folgendes ausführe:

docker exec -it <container ID> /bin/bash

29

Wann immer ich möchte, dass ein Container nach Abschluss der Skriptausführung, die ich hinzufüge, aktiv bleibt

&& tail -f /dev/null

am Ende des Befehls. So sollte es sein:

/usr/local/start-all.sh && tail -f /dev/null

19

Warum wird der Docker-Container sofort verlassen?

Wenn Sie das Image zum Herumhängen zwingen möchten (um etwas zu debuggen oder den Status des Dateisystems zu überprüfen), können Sie den Einstiegspunkt überschreiben, um ihn in eine Shell zu ändern:

docker run -it --entrypoint=/bin/bash myimagename

18

Ein guter Ansatz wäre, Ihre Prozesse und Dienste zu starten, die sie im Hintergrund ausführen, und den wait [n ...]Befehl am Ende Ihres Skripts zu verwenden. In bash erzwingt der Befehl wait den aktuellen Prozess zu:

Warten Sie auf jeden angegebenen Prozess und geben Sie seinen Beendigungsstatus zurück. Wenn n nicht angegeben wird, wird auf alle derzeit aktiven untergeordneten Prozesse gewartet, und der Rückgabestatus ist Null.

Ich habe diese Idee von Sébastien Pujadas 'Startskript für seinen Elchbau bekommen .

Ausgehend von der ursprünglichen Frage würde Ihre start-all.sh ungefähr so ​​aussehen ...

 #!/usr/bin/env bash
 /etc/init.d/hadoop-hdfs-namenode start &
 /etc/init.d/hadoop-hdfs-datanode start &
 /etc/init.d/hadoop-hdfs-secondarynamenode start &
 /etc/init.d/hadoop-0.20-mapreduce-tasktracker start &
 sudo -u hdfs hadoop fs -chmod 777 /
 /etc/init.d/hadoop-0.20-mapreduce-jobtracker start &
 wait

5

Fügen Sie dies am Ende von Dockerfile hinzu:

CMD tail -f /dev/null

Beispiel-Docker-Datei:

FROM ubuntu:16.04

# other commands

CMD tail -f /dev/null

Referenz


CMD tail -f /dev/nullläuft es durch sh -c "...". Können wir execstattdessen das Formular verwenden? DhCMD ["tail", "-f", "/dev/null"]
Meglio

4

Meine Praxis ist, in der Docker-Datei eine Shell zu starten, die nicht sofort beendet wird CMD [ "sh", "-c", "service ssh start; bash"], und dann auszuführen docker run -dit image_name. Auf diese Weise werden der (ssh) -Dienst und der Container ausgeführt.


1

Ich habe readam Ende eine Shell-Anweisung hinzugefügt . Dadurch bleibt der Hauptprozess des Containers - Start-Shell-Skript - ausgeführt.


1

Hinzufügen

exec "$@"

Am Ende meines Shell-Skripts war mein Fix!


Das bedeutet nur, dass Ihr Cmd ausgeführt wird. Wenn Ihr Cmd nur "Bash" ist, funktioniert es immer noch nicht
Shardj

1

Wenn Sie Dockerfile aus Containern überprüfen, z. B. fballiano / magento2-apache-php

Sie werden sehen, dass er am Ende seiner Datei den folgenden Befehl hinzufügt: while true; schlafe 1; getan

Was ich jetzt empfehle, ist, dass Sie dies tun

docker container ls --all | grep 127

Dann werden Sie sehen, ob Ihr Docker-Image einen Fehler hatte. Wenn es mit 0 beendet wird, benötigt es wahrscheinlich einen dieser Befehle, der für immer schlafen wird.


0

Es gibt viele Möglichkeiten, einen Docker sofort zu beenden. Für mich war es das Problem mit meinem Dockerfile. Es gab einen Fehler in dieser Datei. Ich hatte ENTRYPOINT ["dotnet", "M4Movie_Api.dll]statt ENTRYPOINT ["dotnet", "M4Movie_Api.dll"]. Wie Sie sehen, hatte ich am Ende ein Zitat (") verpasst.

Um das Problem zu analysieren, startete ich meinen Container und befestigte meinen Container schnell, damit ich sehen konnte, was genau das Problem war.

C:\SVenu\M4Movie\Api\Api>docker start 4ea373efa21b


C:\SVenu\M4Movie\Api\Api>docker attach 4ea373efa21b

Wobei 4ea373efa21b meine Container-ID ist. Dies bringt mich zum eigentlichen Problem.

Geben Sie hier die Bildbeschreibung ein

Nachdem ich das Problem gefunden hatte, musste ich meinen Container erneut erstellen, wiederherstellen und veröffentlichen.


0

Aufgrund von Duplikaten sehe ich hier keine Antwort, die sich mit dem sehr häufigen Antipattern befasst, Ihre Hauptarbeitslast als Hintergrundjob auszuführen und sich dann zu fragen, warum Docker beendet wird.

In einfachen Worten, wenn Sie haben

my-main-thing &

Nehmen Sie dann entweder das heraus &, um den Job im Vordergrund auszuführen, oder fügen Sie hinzu

wait

am Ende des Skripts, damit es auf alle Hintergrundjobs wartet.

Es wird dann immer noch beendet, wenn die Hauptarbeitslast beendet wird. Führen Sie dies also möglicherweise in a aus while true Schleife aus, um einen Neustart für immer zu erzwingen:

while true; do
    my-main-thing &
    other things which need to happen while the main workload runs in the background
    maybe if you have such things
    wait
done

(Beachten Sie auch, wie man schreibt while true. Es ist üblich, alberne Dinge zu sehen, wie while [ true ]oder while [ 1 ]die zufällig funktionieren, aber meinen Sie nicht, was der Autor wahrscheinlich gedacht hat, dass sie bedeuten sollten.)


0

Sie müssen es mit dem Flag -d ausführen, damit es als Daemon im Hintergrund ausgeführt wird.

Docker run -d -it Ubuntu Bash


-5

Sie können den Container mit diesem Neustart-Flag ausführen.

docker run -d --name=<some-name> -p xxxx:xxxx ... <image-name> --restart=unless-stopped

-8

Da es sich bei dem Image um ein Linux handelt, müssen Sie überprüfen, ob alle im Container verwendeten Shell-Skripte Unix-Zeilenenden haben. Wenn sie am Ende ein ^ M haben, sind sie Windows-Zeilenenden. Eine Möglichkeit, sie zu beheben, besteht darin, sie mit dos2unix unter /usr/local/start-all.sh von Windows nach Unix zu konvertieren. Wenn Sie das Docker im interaktiven Modus ausführen, können Sie andere Probleme herausfinden. Sie könnten einen Dateinamen-Tippfehler haben oder so. Siehe https://en.wikipedia.org/wiki/Newline

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.