Übergeben von Argumenten an Shell Script über Docker Run

131

Ich bin neu in der Docker-Welt. Ich muss ein Shell-Skript aufrufen, das Befehlszeilenargumente über einen Docker-Container akzeptiert. Beispiel: Mein Shell-Skript sieht folgendermaßen aus:

#!bin/bash
echo $1

Dockerfile sieht folgendermaßen aus:

FROM ubuntu:14.04
COPY ./file.sh /
CMD /bin/bash file.sh

Ich bin nicht sicher, wie ich die Argumente beim Ausführen des Containers übergeben soll

Akash Mehta
quelle

Antworten:

61

Verwenden Sie das gleiche file.sh

#!/bin/bash
echo $1

Erstellen Sie das Image mit der vorhandenen Docker-Datei:

docker build -t test .

Führen Sie das Bild mit Argumenten abcoder xyzoder etwas anderes.

docker run -ti test /file.sh abc

docker run -ti test /file.sh xyz
BMW
quelle
27
Ich denke, ENTRYPOINT ist der richtige Weg, wenn Sie nicht möchten, dass der Endbenutzer direkt über file.sh informiert wird.
Greg.kindel
Wie können Sie nur ein Skript wie folgt starten docker run -ti test /file.sh abc. Ich habe das Gefühl, dass das Skript nicht ausgeführt wird, weil es sein sollte docker run -ti test sh /file.sh abc. sh oder / bin / sh wird es richtig ausführen.
Vamsidhar Muggulla
1
Für alle anderen, die hierher kommen. Der Trick / usr / bin / env ist eine optionale Stilvoreinstellung, die nicht erforderlich ist, damit dies funktioniert. Auch der #! Zeile gibt an, welcher Interpreter Buy Default verwenden soll. Es kann also einfach durch Aufrufen des Skripts ausgeführt werden.
Woher kam dieser Name vom
162

mit diesem Skript in file.sh

#!/bin/bash
echo Your container args are: "$@"

und das Dockerfile

FROM ubuntu:14.04
COPY ./file.sh /
ENTRYPOINT ["/file.sh"]

du solltest in der Lage sein zu:

% docker build -t test .
% docker run test hello world
Your container args are: hello world
Teilweise wolkig
quelle
9
Wenn Sie das "" um "/file.sh" wie ich vergessen, wird es nicht funktionieren.
Kev
6
Aus irgendeinem Grund funktioniert dies nicht mitENTRYPOINT ./file.sh
phil294
6
Vergessen Sie nicht, chmod +x file.shdas Flag für ausführbare Dateien zu setzen.
Topskip
1
@kev, weißt du warum es so ist? Was ist der Unterschied zwischen ["/file.sh"]und /file.shoder sogar[/file.sh]
Nitzankin
1
@Nitzankin siehe meine Antwort, warum die richtige JSON-Formatierung erforderlich ist.
BMitch
60

Mit Docker können Umgebungsvariablen ordnungsgemäß über diese Art von Informationen übergeben werden.

Ändern Sie das Skript mit derselben Docker-Datei in

#!/bin/bash
echo $FOO

Verwenden Sie nach dem Erstellen den folgenden Docker-Befehl:

docker run -e FOO="hello world!" test
Michael
quelle
20
Warum ist dies die am höchsten gewählte Antwort? Env-Vars sind eine weitere Möglichkeit, Informationen weiterzugeben, aber nicht das, was OP verlangt. Und natürlich ist der Wunsch von OP, Argumente an den Container weiterzugeben, absolut nicht unangemessen.
Teilweise bewölkt
8
@PartlyCloudy Ich denke, die Leute mögen das, weil es vorgibt, die "richtige" Antwort zu geben, obwohl es offensichtlich falsch ist. Ein wichtiges Konstruktionsprinzip von Docker besteht darin, das Dogma vor dem gesunden Menschenverstand zu priorisieren.
August
1
@augurar: Um diese Antwort zu verbessern, erklären Sie vielleicht, warum Sie denken, dass diese Antwort "offensichtlich falsch" ist?
Emil Stenström
2
Es gibt eine Menge XY-Probleme bei SO. Da das OP angab, neu bei Docker zu sein, ist es durchaus vernünftig, dass eine Antwort den empfohlenen Weg zur Erreichung eines Ziels zeigt. Dies macht dies zu einer großartigen Antwort.
colm.anseo
1
Der einfachste Weg, um die Arbeit zu erledigen, anstatt die Variablen als Build-Argumente und all das Durcheinander zu übergeben. Sehr nützlich, um Geheimnisse als Umgebungsvariablen zu übergeben.
Arvind Sridharan
32

Hier interagieren einige Dinge:

  1. docker run your_image arg1 arg2ersetzt den Wert von CMDdurch arg1 arg2. Dies ist ein vollständiger Ersatz für das CMD, ohne dass weitere Werte daran angehängt werden. Aus diesem Grund wird häufig docker run some_image /bin/basheine Bash-Shell im Container ausgeführt.

  2. Wenn Sie sowohl einen ENTRYPOINT- als auch einen CMD-Wert definiert haben, startet Docker den Container, indem es die beiden verkettet und diesen verketteten Befehl ausführt. Wenn Sie also Ihren Einstiegspunkt als definieren file.sh, können Sie den Container jetzt mit zusätzlichen Argumenten ausführen, die als Argumente an übergeben werden file.sh.

  3. Einstiegspunkte und Befehle in Docker haben zwei Syntaxen, eine Zeichenfolgensyntax, mit der eine Shell gestartet wird, und eine JSON-Syntax, mit der eine Ausführung ausgeführt wird. Die Shell ist nützlich, um Dinge wie die E / A-Umleitung, das Verketten mehrerer Befehle (mit Dingen wie &&), das Ersetzen von Variablen usw. zu handhaben . Diese Shell behindert jedoch die Signalverarbeitung (wenn Sie jemals eine Verzögerung von 10 Sekunden zum Stoppen gesehen haben ein Container, dies ist oft die Ursache) und mit der Verkettung eines Einstiegspunkts und eines Befehls zusammen. Wenn Sie Ihren Einstiegspunkt als Zeichenfolge definieren, wird er ausgeführt /bin/sh -c "file.sh", was allein in Ordnung ist. Wenn Sie jedoch einen Befehl auch als Zeichenfolge definiert haben, wird /bin/sh -c "file.sh" /bin/sh -c "arg1 arg2"der Befehl in Ihrem Container nicht so gut gestartet. In der Tabelle hier finden Sie weitere Informationen zur Interaktion dieser beiden Optionen

  4. Die Shell- -cOption akzeptiert nur ein einziges Argument. Alles danach würde bestanden werden als $1,$2 usw., auf das einzelne Argument, aber nicht in einen eingebetteten Shell - Skript , wenn Sie explizit die Argumente übergeben. Dh /bin/sh -c "file.sh $1 $2" "arg1" "arg2"würde funktionieren, /bin/sh -c "file.sh" "arg1" "arg2"würde aber nicht da file.shohne Argumente aufgerufen werden.

Alles in allem lautet das gemeinsame Design:

FROM ubuntu:14.04
COPY ./file.sh /
RUN chmod 755 /file.sh
# Note the json syntax on this next line is strict, double quotes, and any syntax
# error will result in a shell being used to run the line.
ENTRYPOINT ["file.sh"]

Und das führen Sie dann aus mit:

docker run your_image arg1 arg2

Es gibt einiges mehr Details dazu unter:

BMitch
quelle
1
Ich hatte versucht, meinen Einstiegspunkt so einzustellen, ["bash", "--login", "-c"]dass die Quelle / etc / profile im Bild angezeigt wird, fragte mich aber später, warum keine Argumente an ein Shell-Skript übergeben werden, das an Docker Run übergeben wird ... Ihre Antwort hat das geklärt, danke !
Apteryx
23

Was ich habe, ist eine Skriptdatei, die tatsächlich Dinge ausführt. Diese Skriptdatei ist möglicherweise relativ kompliziert. Nennen wir es "run_container". Dieses Skript übernimmt Argumente aus der Befehlszeile:

run_container p1 p2 p3

Ein einfacher run_container könnte sein:

#!/bin/bash
echo "argc = ${#*}"
echo "argv = ${*}"

Was ich tun möchte, ist, nach dem "Andocken" dies in der Lage zu sein, diesen Container mit den Parametern in der Docker-Befehlszeile wie folgt zu starten:

docker run image_name p1 p2 p3

und lassen Sie das Skript run_container mit p1 p2 p3 als Parametern ausführen.

Das ist meine Lösung:

Dockerfile:

FROM docker.io/ubuntu
ADD run_container /
ENTRYPOINT ["/bin/bash", "-c", "/run_container \"$@\"", "--"]
jkh
quelle
7
Das Ersetzen des dritten Werts im ENTRYPOINTArray durch Mittelwerte, "/run_container \"$@\""die Leerzeichen enthalten, wird korrekt behandelt (z docker run image_name foo 'bar baz' quux. B. ).
Davidchambers
Nach dem Hinzufügen von switch / case-Anweisungen zu meiner Bash-Datei funktionierte ENTRYPOINT ["run_container.sh"] nicht mehr für mich, aber ENTRYPOINT ["sh", "-c", "run_container.sh"] akzeptierte meine Parameter nicht mehr. Diese Lösung (mit dem Vorschlag von @davidchambers) hat bei mir funktioniert.
Rhamilton
10

Wenn Sie es @build time ausführen möchten:

CMD /bin/bash /file.sh arg1

Wenn Sie es @run time ausführen möchten:

ENTRYPOINT ["/bin/bash"]
CMD ["/file.sh", "arg1"]

Dann in der Host-Shell

docker build -t test .
docker run -i -t test
Gilles Quenot
quelle
2
ENTRYPOINTist eine gute Antwort für das OP, von dem ich denke, dass es Laufzeit haben möchte, aber wenn Sie wirklich Zeitvariablen erstellen möchten, ist diese Antwort einfach kaputt. Verwenden Sie ARGund docker build --build-arg docs.docker.com/engine/reference/builder/#arg
greg.kindel
0

Andere Option...

Damit das funktioniert

docker run -d --rm $IMG_NAME "bash:command1&&command2&&command3"

in Dockerfile

ENTRYPOINT ["/entrypoint.sh"]

in entrypoint.sh

#!/bin/sh

entrypoint_params=$1
printf "==>[entrypoint.sh] %s\n" "entry_point_param is $entrypoint_params"

PARAM1=$(echo $entrypoint_params | cut -d':' -f1) # output is 1 must be 'bash' it     will be tested    
PARAM2=$(echo $entrypoint_params | cut -d':' -f2) # the real command separated by     &&

printf "==>[entrypoint.sh] %s\n" "PARAM1=$PARAM1"
printf "==>[entrypoint.sh] %s\n" "PARAM2=$PARAM2"

if [ "$PARAM1" = "bash" ];
then
    printf "==>[entrypoint.sh] %s\n" "about to running $PARAM2 command"
    echo $PARAM2 | tr '&&' '\n' | while read cmd; do
        $cmd
    done    
fi
wagnermarques
quelle
Einige Anmerkungen und Einschränkungen .... Befehl mit ":" benötigt Änderungen in cut -d ':' und Befehle wie Docker run -d --rm $ IMG_NAME "bash: echo $ PATH" zeigt den Hostpfadwert anstelle des Hosts an one
wagnermarques