Come passare argomenti a Shell Script tramite la finestra mobile


132

Sono nuovo nel mondo delle docker. Devo invocare uno script di shell che accetta gli argomenti della riga di comando attraverso un contenitore finestra mobile. Esempio: il mio script shell ha il seguente aspetto:

#!bin/bash
echo $1

Il file Docker è simile al seguente:

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

Non sono sicuro di come passare gli argomenti durante l'esecuzione del contenitore

Risposte:


61

Usa lo stesso file.sh

#!/bin/bash
echo $1

Costruisci l'immagine usando il Dockerfile esistente:

docker build -t test .

Esegui l'immagine con argomenti abco xyzo qualcos'altro.

docker run -ti test /file.sh abc

docker run -ti test /file.sh xyz

27
Penso che ENTRYPOINT sia la strada da percorrere se non vuoi che l'utente finale sappia direttamente di file.sh.
greg.kindel,

Come puoi iniziare una sceneggiatura come questa docker run -ti test /file.sh abc. Sento che la sceneggiatura non verrà eseguita perché dovrebbe essere docker run -ti test sh /file.sh abc. sh o / bin / sh lo eseguiranno correttamente.
Vamsidhar Muggulla,

1
Per chiunque venga qui. Il trucco / usr / bin / env è una preferenza di stile facoltativa, non un requisito per farlo funzionare. Anche il #! la riga indica quale interprete utilizzare acquista default. Quindi può essere eseguito semplicemente chiamando lo script.
wheredidthatnamecomeda

165

con questo script in file.sh

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

e questo Dockerfile

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

dovresti essere capace di:

% docker build -t test .
% docker run test hello world
Your container args are: hello world

9
Se dimentichi "" around "/file.sh" come ho fatto io, non funzionerà.
kev

6
per qualche motivo, questo non funziona conENTRYPOINT ./file.sh
phil294

6
Non dimenticare di chmod +x file.shimpostare il flag eseguibile.
topskip

1
@kev, sai perché è così? qual è la differenza tra ["/file.sh"]e /file.sho addirittura[/file.sh]
Nitzankin,

1
@Nitzankin vedi la mia risposta sul perché è necessaria una corretta formattazione json.
BMitch

60

Con Docker, il modo corretto di trasmettere questo tipo di informazioni è attraverso le variabili di ambiente.

Quindi, con lo stesso Dockerfile, cambia lo script in

#!/bin/bash
echo $FOO

Dopo la creazione, utilizzare il seguente comando finestra mobile:

docker run -e FOO="hello world!" test

20
Perché questa è la risposta più votata? Le varie ambientali sono un altro modo per trasmettere informazioni, ma non è ciò che OP chiede. E naturalmente non c'è assolutamente nulla di inappropriato nel desiderio di OP di passare argomenti al container.
Parzialmente nuvoloso

8
@PartlyCloudy Penso che alla gente piaccia questo perché pretende di dare la risposta "corretta", nonostante sia ovviamente sbagliato. Un importante principio progettuale di Docker è quello di dare priorità al dogma rispetto al buon senso.
agosto

1
@augurar: Per migliorare questa risposta, forse spieghi perché pensi che questa risposta sia "ovviamente sbagliata"?
Emil Stenström,

2
Ci sono un sacco di problemi XY da chiedere a SO. Da quando l'OP ha dichiarato di essere nuovo su Docker, è perfettamente ragionevole che una risposta mostri il modo raccomandato per raggiungere un obiettivo. Rendendola così un'ottima risposta.
colm.anseo,

1
Il modo più semplice per fare il lavoro invece di passare le variabili come build args e tutto quel casino. Molto utile per passare segreti come variabili d'ambiente.
Arvind Sridharan,

32

Ci sono alcune cose che interagiscono qui:

  1. docker run your_image arg1 arg2sostituirà il valore di CMDcon arg1 arg2. Questa è una sostituzione completa della CMD, senza aggiungere più valori ad essa. Questo è il motivo per cui si vede spesso docker run some_image /bin/basheseguire una shell bash nel contenitore.

  2. Quando sono definiti sia un ENTRYPOINT che un valore CMD, la finestra mobile avvia il contenitore concatenando i due ed eseguendo quel comando concatenato. Quindi, se si definisce il proprio entrypoint file.sh, ora è possibile eseguire il contenitore con argomenti aggiuntivi che verranno passati come argomenti file.sh.

  3. Entrypoints e comandi nella finestra mobile hanno due sintassi, una sintassi di stringa che avvierà una shell e una sintassi json che eseguirà un exec. La shell è utile per gestire cose come il reindirizzamento IO, concatenare più comandi insieme (con cose come &&), sostituzione di variabili, ecc. Tuttavia, quella shell si mette di mezzo con la gestione del segnale (se hai mai visto un ritardo di 10 secondi per fermarsi un contenitore, questa è spesso la causa) e con la concatenazione di un punto di accesso e comando insieme. Se definisci il tuo entrypoint come una stringa, verrebbe eseguito /bin/sh -c "file.sh", il che da solo va bene. Ma se hai anche un comando definito come una stringa, vedrai qualcosa come /bin/sh -c "file.sh" /bin/sh -c "arg1 arg2"il comando che viene lanciato nel tuo contenitore, non così bene. Vedi la tabella qui per ulteriori informazioni su come interagiscono queste due opzioni

  4. L' -copzione shell accetta solo un singolo argomento. Tutto ciò che segue sarebbe passato come $1, $2ecc., A quel singolo argomento, ma non in uno script di shell incorporato a meno che tu non abbia esplicitamente passato gli arg. Vale a dire che /bin/sh -c "file.sh $1 $2" "arg1" "arg2"avrebbe funzionato, ma /bin/sh -c "file.sh" "arg1" "arg2"da allora non file.shsarebbe stato chiamato senza argomenti.

Mettendo tutto insieme, il design comune è:

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"]

E poi lo esegui con:

docker run your_image arg1 arg2

C'è un po 'più di dettagli su questo in:


1
Avevo sperimentato di impostare il mio punto di accesso in modo ["bash", "--login", "-c"]da ottenere la sorgente / etc / profile nell'immagine, ma in seguito mi sono lasciato chiedermi perché nessun argomento sarebbe passato a uno script della shell passato alla finestra mobile ... La tua risposta è stata chiarita, grazie !
Apteryx

23

Quello che ho è un file di script che esegue effettivamente le cose. Questo file script potrebbe essere relativamente complicato. Chiamiamolo "run_container". Questo script accetta argomenti dalla riga di comando:

run_container p1 p2 p3

Un semplice run_container potrebbe essere:

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

Quello che voglio fare è che, dopo "docking", vorrei poter avviare questo contenitore con i parametri sulla riga comandi docker in questo modo:

docker run image_name p1 p2 p3

e far eseguire lo script run_container con p1 p2 p3 come parametri.

Questa è la mia soluzione:

Dockerfile:

FROM docker.io/ubuntu
ADD run_container /
ENTRYPOINT ["/bin/bash", "-c", "/run_container \"$@\"", "--"]

7
Sostituendo il terzo valore ENTRYPOINTnell'array con "/run_container \"$@\""mezzi gli argomenti contenenti spazi vengono gestiti correttamente (ad es docker run image_name foo 'bar baz' quux.).
davidchambers,

Dopo aver aggiunto le istruzioni switch / case al mio file bash, ENTRYPOINT ["run_container.sh"] non ha funzionato più per me, ma ENTRYPOINT ["sh", "-c", "run_container.sh"] non avrebbe più accettato i miei parametri. Questa soluzione (con il suggerimento di @davidchambers) ha funzionato per me.
rhamilton,

10

Se vuoi eseguirlo @build time:

CMD /bin/bash /file.sh arg1

se vuoi eseguirlo @run time:

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

Quindi nella shell host

docker build -t test .
docker run -i -t test

2
ENTRYPOINTè una buona risposta per l'OP che penso volesse il runtime, ma se vuoi davvero costruire variabili di tempo questa risposta è semplicemente rotta. Usa ARGe docker build --build-arg docs.docker.com/engine/reference/builder/#arg
greg.kindel

0

Un'altra opzione...

Per farlo funzionare

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

nel file docker

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

alcune osservazioni e limitazioni .... il comando con ":" necessita di modifiche in cut -d ':' e comandi come docker run -d --rm $ IMG_NAME "bash: echo $ PATH" mostrerà il valore del percorso dell'host invece dell'host one
wagnermarques,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.