Ausführen eines Skripts in einem Docker-Container mithilfe eines Shell-Skripts

85

Ich versuche, ein Shell-Skript zum Einrichten eines Docker-Containers zu erstellen. Meine Skriptdatei sieht folgendermaßen aus:

#!bin/bash

docker run -t -i -p 5902:5902 --name "mycontainer" --privileged myImage:new /bin/bash

Durch Ausführen dieser Skriptdatei wird der Container in einer neu aufgerufenen Bash ausgeführt.

Jetzt muss ich eine Skriptdatei (test.sh) ausführen, die sich bereits im Container des oben angegebenen Shell-Skripts befindet (z. B. cd /path/to/test.sh && ./test.sh). Wie geht das?

zappy
quelle
1
Warum nicht WORKDIRund verwenden CMD?
Dharmit
1
Sie möchten --privileged hier wahrscheinlich nicht verwenden. Siehe: stackoverflow.com/questions/36425230/…
CMP

Antworten:

121

Sie können einen Befehl in einem laufenden Container ausführen, indem Sie docker exec [OPTIONS] CONTAINER COMMAND [ARG...]:

docker exec mycontainer /path/to/test.sh

Und um von einer Bash-Sitzung wegzulaufen:

docker exec -it mycontainer /bin/bash

Von dort aus können Sie Ihr Skript ausführen.

Javier Cortejoso
quelle
6
Was ist, wenn ich zuerst / bin / bash eingeben und dann den Befehl in dieser Bash ausführen muss?
Zappy
44
Sie können ein lokales Skript auch direkt vom Host aus ausführen. docker exec -i mycontainer bash < mylocal.sh Dadurch wird das lokale Hostskript gelesen und im Container ausgeführt. Sie können dies mit anderen Dingen tun (wie .tgz-Dateien, die in tar geleitet werden) - es wird nur das '-i' verwendet, um in die std-Eingabe des Containerprozesses zu leiten.
Marvin
@ Marvin Was ist das Äquivalent in PowerShell? Das Zeichen "<" wird nicht erkannt.
Nicekiwi
1
Ich bin kein Powershell-Guru (zum Glück), aber ich bin durch SO gewandert und habe stackoverflow.com/a/11788475/500902 gefunden . Also vielleicht Get-Content mylocal.sh | docker exec -i mycontainer bash. Ich weiß aber nicht, ob das funktioniert.
Marvin
97

Angenommen, Ihr Docker-Container ist aktiv, können Sie Befehle wie folgt ausführen:

docker exec mycontainer /bin/sh -c "cmd1;cmd2;...;cmdn"
Zyklop
quelle
2
Ich mag diese Antwort; Sie müssen sich nicht beim Docker-Container anmelden, um einen Befehl oder eine Reihe von Befehlen auszuführen. Vielen Dank!
Hatem Jaber
Wissen Sie, wie Sie noch einen Schritt weiter gehen und den gesamten Befehl ( /bin/sh -c "cmd1; cmd2; ...; cmdn") als Wert einer Shell-Variablen übergeben können? Ich frage, weil 'Docker Run' eher einen einzelnen Befehl und einzelne nicht zitierte Argumente als eine Zeichenfolge in Anführungszeichen zu erwarten scheint.
DavidA
@meowsqueak: In dieser Antwort erfahren Sie, wie Sie mehrere Befehle in einem bereits erstellten und ausgeführten Container ausführen, ohne sich in diesem Container anzumelden. Dies ist bei der Automatisierung hilfreich. Wenn Sie jedoch zum Zeitpunkt der Containererstellung mehrere Befehle ausführen möchten (PS: Docker-Befehl run erstellt und startet den Container), können Sie dies erreichen, indem Sie den Antworten in demselben Thread folgen. Stackoverflow.com/a/41363989/777617
Cyclops
Anstelle von cmd1muss ich eine ganze for-Schleife übergeben - aber es erwartet ;nach der Schleifenanweisung und der do- Anweisung. Wie kann ich die gesamte for-Schleife als einen einzigen Befehl ausführen, dh cmd1? Ist es möglich?
Nicholas K
18

Ich suchte nach einer Antwort auf dieselbe Frage und fand ENTRYPOINT in der Dockerfile- Lösung für mich.

Dockerfile

...
ENTRYPOINT /my-script.sh ; /my-script2.sh ; /bin/bash

Jetzt werden die Skripte ausgeführt, wenn ich den Container starte, und ich erhalte die Bash-Eingabeaufforderung, nachdem die Skripte ausgeführt wurden.

tojo
quelle
6

Sie können auch ein lokales Verzeichnis in Ihr Docker-Image einbinden und das Skript in Ihrem .bashrc. Vergessen Sie nicht, dass das Skript aus Funktionen bestehen muss, es sei denn, Sie möchten, dass es auf jeder neuen Shell ausgeführt wird. (Dies ist veraltet, siehe Update-Hinweis.)

Ich verwende diese Lösung, um das Skript außerhalb der Docker-Instanz aktualisieren zu können. Auf diese Weise muss ich das Bild nicht erneut ausführen, wenn Änderungen auftreten. Ich öffne einfach eine neue Shell. (Das erneute Öffnen einer Shell wurde vermieden - siehe Update-Hinweis)

So binden Sie Ihr aktuelles Verzeichnis:

docker run -it -v $PWD:/scripts $my_docker_build /bin/bash

Jetzt ist Ihr aktuelles Verzeichnis an /scriptsIhre Docker-Instanz gebunden .

(Veraltet) Um Ihre .bashrcÄnderungen zu speichern , schreiben Sie Ihr Arbeitsimage mit folgendem Befehl fest:

docker commit $container_id $my_docker_build

Aktualisieren

Um das Problem zu lösen und für jede Änderung eine neue Shell zu öffnen, gehe ich jetzt wie folgt vor:

In der Docker-Datei selbst füge ich hinzu RUN echo "/scripts/bashrc" > /root/.bashrc". Innerhalb zshrcexportiere ich das Skriptverzeichnis in den Pfad. Das Skriptverzeichnis enthält jetzt mehrere Dateien anstelle einer. Jetzt kann ich alle Skripte direkt aufrufen, ohne bei jeder Änderung eine Sub-Shell öffnen zu müssen.

Übrigens können Sie die Verlaufsdatei auch außerhalb Ihres Containers definieren. Auf diese Weise ist es nicht mehr erforderlich, eine Bash-Änderung vorzunehmen.

Devpool
quelle
Zu spät..! @javier zeigt bereits eine einfache Lösung !! Ich fühle, dass man noch besser ist.
Zappy
2
@zappy Die Lösung von Javier hat dieses Problem für mich nicht bequem gelöst - aber meine Lösung hat es geschafft. Ich dachte, es wäre interessant für diejenigen, die ein ähnliches Problem hatten, bei dem sie die Docker-Images nicht neu starten möchten, um a zu aktualisieren Ansichtsfunktionen, die sie benötigen. Wenn Sie beispielsweise mehrere Docker-Images gleichzeitig verwenden, um einen Entwicklungscluster hochzufahren, möchten Sie sie nicht ständig neu starten.
Devpool
3

Falls Sie keinen laufenden Container möchten (oder haben), können Sie Ihr Skript direkt mit dem runBefehl aufrufen .

Entfernen Sie die iterativen tty- -i -tArgumente und verwenden Sie Folgendes :

    $ docker run ubuntu:bionic /bin/bash /path/to/script.sh

Dies funktioniert (nicht getestet) auch für andere Skripte:

    $ docker run ubuntu:bionic /usr/bin/python /path/to/script.py
Thomio
quelle
0

Wenn Sie denselben Befehl auf mehreren Instanzen ausführen möchten, können Sie Folgendes tun:

for i in c1 dm1 dm2 ds1 ds2 gtm_m gtm_sl; do docker exec -it $i /bin/bash -c "service sshd start"; done
DMin
quelle