Wie starte ich einen gestoppten Docker-Container mit einem anderen Befehl?

250

Ich möchte einen gestoppten Docker-Container mit einem anderen Befehl starten, da der Standardbefehl abstürzt. Dies bedeutet, dass ich den Container nicht starten und dann 'docker exec' verwenden kann.

Grundsätzlich möchte ich eine Shell starten, damit ich den Inhalt des Containers überprüfen kann.

Zum Glück habe ich den Container mit der Option -it erstellt!

aaa90210
quelle

Antworten:

380

Suchen Sie Ihre gestoppte Container-ID

docker ps -a

Übernehmen Sie den gestoppten Container:

Dieser Befehl speichert den geänderten Containerstatus in einem neuen Image user/test_image

docker commit $CONTAINER_ID user/test_image

Starten / Ausführen mit einem anderen Einstiegspunkt:

docker run -ti --entrypoint=sh user/test_image

Beschreibung des Einstiegspunktarguments: https://docs.docker.com/engine/reference/run/#/entrypoint-default-command-to-execute-at-runtime

Hinweis:

Die obigen Schritte starten einfach einen gestoppten Container mit demselben Dateisystemstatus. Das ist großartig für eine schnelle Untersuchung. Umgebungsvariablen, Netzwerkkonfiguration, angehängte Volumes und anderes Personal werden jedoch nicht vererbt. Sie sollten alle diese Argumente explizit angeben.

Schritte zum Starten eines gestoppten Containers wurden von hier ausgeliehen: (letzter Kommentar) https://github.com/docker/docker/issues/18078

Dmitriusan
quelle
1
Nein, Bilder sind schreibgeschützt. Es speichert geänderten Containerstatus in einem neuen Bild test_image
Dmitriusan
4
Dies vermisst fast die gesamte Konfiguration über env, Volumes, UID, ... Alles, was es mit dem gestoppten Container gemeinsam hat, ist das Dateisystem (was für einige vielleicht ausreicht)
Florian Klein
4
Es wäre großartig, wenn ich irgendwie die gleiche Umgebung, Netzwerkkonfiguration und angeschlossene Volumes bekommen könnte. Ist es möglich, die inspectAusgabe in eine Konfiguration zu konvertieren, die beim nachfolgenden Lauf verwendet wird?
Otheus
2
@Webman, ja, aber das gilt nicht für Volumes, die vor dem Stoppen eines Containers bereitgestellt wurden. Sie müssen die gleichen Volumes explizit anhängen, wenn Sie den Container das nächste Mal starten
Dmitriusan
1
@ EmreTapcı, ich denke, das ist gegen die Docker-Ideologie. Container sind im Gegensatz zu virtuellen Maschinen als Einweg-Run-and-Throw-Away-Entität gedacht. Sie können versuchen, der Antwort aaa90210 zu folgen , aber es wäre ein Hack.
Dmitriusan
126

Bearbeiten Sie diese Datei (entsprechend Ihrem gestoppten Container):

vi /var/lib/docker/containers/923...4f6/config.json

Ändern Sie den Parameter "Pfad" so, dass er auf Ihren neuen Befehl zeigt, z. B. / bin / bash. Sie können auch den Parameter "Args" festlegen, um Argumente an den Befehl zu übergeben.

Starten Sie den Docker-Dienst neu (beachten Sie, dass dadurch alle laufenden Container gestoppt werden):

service docker restart

Listen Sie Ihre Container auf und stellen Sie sicher, dass sich der Befehl geändert hat:

docker ps -a

Starten Sie den Container und befestigen Sie ihn, Sie sollten jetzt in Ihrer Shell sein!

docker start -ai mad_brattain

Arbeitete an Fedora 22 mit Docker 1.7.1.

HINWEIS: Wenn Ihre Shell nicht interaktiv ist (z. B. Sie haben den ursprünglichen Container nicht mit der Option -it erstellt), können Sie stattdessen den Befehl in "/ bin / sleep 600" oder "/ bin / tail -f / dev / null" ändern. um Ihnen genügend Zeit zu geben, "docker exec -it CONTID / bin / bash" als eine andere Möglichkeit zum Abrufen einer Shell auszuführen.

HINWEIS 2: Neuere Versionen von Docker haben config.v2.json, wo Sie entweder Entrypoint oder Cmd ändern müssen (danke user60561).

aaa90210
quelle
44
meine Augen. meine Augen. Ich hoffe, dies ist eine Feature-Anfrage, um dies in Docker richtig zu handhaben.
Gertvdijk
2
@AlexeyStrakh Sie könnten versuchen, "/ usr / bin / sleep 600" auszuführen und dann "docker exec -it / bin / bash" ausführen, um eine Shell zu erhalten. Obwohl ich nicht sicher bin, wie ich Parameter auf diese Pfadvariable setzen soll. Versuchen Sie andernfalls, einen anderen Befehl zu finden, der lange genug am Leben bleibt, damit Sie eine Ausführung ausführen können, oder sehen Sie die Antwort von Dmitriusan.
aaa90210
3
Das ist die einzig wirklich genaue Antwort auf die Frage: Alle anderen Vorschläge führen einen "fast gleichen" Container aus, aber sie vergessen die Volumes, env, UIDs, ...
Florian Klein
3
In meinem Fall war / usr / bin / sleep nicht verfügbar. Ich hatte Erfolg mit..."Path":"tail","Args":["-f","/dev/null"]...
Nevrome
4
Neuere Versionen von Docker haben config.v2.json, wo Sie entweder Entrypointoder ändern müssen Cmd.
user60561
20

Fügen Sie oben in Ihrem Entrypoint-Skript ein Häkchen hinzu

Docker muss dies wirklich als neue Funktion implementieren. Hier ist jedoch eine weitere Problemumgehungsoption für Situationen, in denen Sie einen Entrypoint haben, der nach Erfolg oder Misserfolg beendet wird, was das Debuggen erschweren kann.

Wenn Sie noch kein Entrypoint-Skript haben, erstellen Sie eines, das alle Befehle ausführt, die Sie für Ihren Container benötigen. Fügen Sie dann oben in dieser Datei die folgenden Zeilen hinzu entrypoint.sh:

# Run once, hold otherwise
if [ -f "already_ran" ]; then
    echo "Already ran the Entrypoint once. Holding indefinitely for debugging."
    cat
fi
touch already_ran

# Do your main things down here

Um sicherzustellen, dass catdie Verbindung besteht, müssen Sie möglicherweise eine TTY bereitstellen. Ich führe den Container mit meinem Entrypoint-Skript folgendermaßen aus:

docker run -t --entrypoint entrypoint.sh image_name

Dadurch wird das Skript einmal ausgeführt und eine Datei erstellt, die angibt, dass es bereits ausgeführt wurde (im virtuellen Dateisystem des Containers). Sie können den Container dann neu starten, um das Debuggen durchzuführen:

docker start container_name

Wenn Sie den Container neu starten, wird die already_ranDatei gefunden, wodurch das Entrypoint-Skript zum Stillstand kommt cat(das nur für immer auf Eingaben wartet, die niemals kommen, aber den Container am Leben erhalten). Sie können dann eine Debugging- bashSitzung ausführen :

docker exec -i container_name bash

Während der Container ausgeführt wird, können Sie already_randas entrypoint.shSkript auch entfernen und manuell ausführen, um es erneut auszuführen , wenn Sie auf diese Weise debuggen müssen.

Ethan T.
quelle
3
Außerdem können Sie den Einstiegspunkt /bin/shanstelle von ausführen lassen cat- dann können Sie immer nur neu starten. Ihre Lösung rockt!
Danny Dulai
4

Mein Problem:

  • Ich habe einen Container mit gestartet docker run <IMAGE_NAME>
  • Und dann einige Dateien zu diesem Container hinzugefügt
  • Dann schloss ich den Container und versuchte ihn mit demselben Befehl wie oben erneut zu starten.
  • Aber als ich die neuen Dateien überprüfte, fehlten sie
  • Wenn ich renne, kann docker ps -aich zwei Container sehen.
  • Das bedeutet, dass jedes Mal, wenn ich einen docker run <IMAGE_NAME>Befehl ausführte, ein neues Image erstellt wurde

Lösung: Um an demselben Container zu arbeiten, den Sie zuerst erstellt haben, führen Sie die folgenden Schritte aus

  • docker ps um Container von Ihrem Container zu bekommen
  • docker container start <CONTAINER_ID> vorhandenen Container starten
  • Dann können Sie dort weitermachen, wo Sie abgereist sind. z.Bdocker exec -it <CONTAINER_ID> /bin/bash
  • Sie können dann entscheiden, ein neues Bild daraus zu erstellen
Amit Dudhbade
quelle
Dies beantwortet die Frage nicht. Das OP möchte wissen, wie der Container neu docker run <containerID>
gestartet wird,
2

Ich nahm die Antwort von @ Dmitriusan und machte daraus einen Alias:

alias docker-run-prev-container = 'prev_container_id = "$ (docker ps -aq | head -n1)" && docker commit "$ prev_container_id" "prev_container / $ prev_container_id" && docker run -it --entrypoint = bash "prev_container / $ prev_container_id "'

Fügen Sie dies zu Ihrer ~/.bashrcAliase-Datei hinzu, und Sie erhalten einen raffinierten neuen docker-run-prev-containerAlias, der Sie in eine Shell im vorherigen Container einfügt.

Hilfreich beim Debuggen fehlgeschlagen docker builds.

Dean Rather
quelle
2

Dies ist nicht genau das, wonach Sie fragen, aber Sie können es docker exportfür einen gestoppten Container verwenden, wenn Sie nur die Dateien überprüfen möchten.

mkdir $TARGET_DIR
docker export $CONTAINER_ID | tar -x -C $TARGET_DIR
Lars Christian Jensen
quelle
1

Es wurde nicht angegeben, ob der Container beendet wird, nur dass Ihr Code abstürzt und Sie sehen müssen, was im Container vor sich geht. Wenn es nicht beendet wird, finden Sie hier eine weitere mögliche Lösung.

Holen Sie sich die Container-ID mit docker ps

docker exec -it 665b4a1e17b6 /bin/sh

Wenn der Einstiegspunkt auf etwas Problematisches eingestellt ist, kann er auch überschrieben werden, wie in Dmitriusans Antwort vorgeschlagen. Es sollte auch beachtet werden, dass Sie an jeden laufenden Container mit anhängen können docker attach. So viele Lösungen verschiedene Lösungen. Ich sehe einfach keine Notwendigkeit, mich auf das Bild festzulegen. Es scheint unnötig.

Dokumente für Docker exec - https://docs.docker.com/engine/reference/commandline/exec/

Dokumente für Docker anhängen - https://docs.docker.com/engine/reference/commandline/attach/

Deadbabykitten
quelle
-12

Ich bin mit diesen beiden Antworten eigentlich nicht einverstanden. Wenn Sie nur sehen möchten, was sich im Container befindet, können Sie diesen Befehl ausführen, um eine Shell zu erhalten. Es ist nicht erforderlich, den Einstiegspunkt oder irgendwelche Konfigurationen zu ändern.

docker run -it <image_name> bash
Deadbabykitten
quelle
12
Dies funktioniert nicht, da die Operation nach einem Container fragt, nicht nach einem Bild.
Peter Vrabel
Ich nehme an, Sie haben Recht, sehen aber keinen Grund dafür. Sie können Protokolle an stdout weiterleiten und erhalten docker logs <container_id> --followdas, was Sie benötigen. Eine andere Alternative besteht darin, den obigen Befehl zu verwenden und dann den Absturzdienst für dieses Image mit demselben Befehl in der Docker-Datei zu starten und von dort aus zu debuggen.
Deadbabykitten
4
Der Befehl run erstellt einen neuen Container aus einem Image. Es wird kein gestoppter Container gestartet.
Waleed Abdulla
2
Ähm, ... ist das nicht der Sinn von Docker, dass jedes Bild auf genau die gleiche Weise gedreht werden kann? Dies negiert Ihr Argument. Er muss keinen gestoppten Container starten. Jeder Container ist genau der gleiche, daher spielt es keine Rolle, welchen er startet oder stoppt. Er versucht nur, den Inhalt zu überprüfen. Der einfachste Weg, dies zu tun, besteht darin, den Befehl oder die Pipe-Ausgabe des Befehls in die Protokolle einzuschlagen und auszuführen. Ihr findet manchmal die komplexesten Lösungen für einfache Probleme.
Deadbabykitten
-12
docker container start <CONTAINER_ID>
Oscar Calderón
quelle