Ho notato che molti script entrypoint.sh per docker fanno qualcosa del genere:
#!/bin/bash
set -e
... code ...
exec "$@"
A cosa servono set -e
e exec "$@"
?
Risposte:
Fondamentalmente accetta qualsiasi argomento della riga di comando passato entrypoint.sh
e lo esegue come comando. L'intenzione è fondamentalmente "Fai tutto in questo script .sh, quindi nella stessa shell esegui il comando che l'utente passa sulla riga di comando".
Vedere:
exec "$@"
sostituirà il processo attualmente in esecuzione con il nuovo processo generato per gli argomenti passati. Importante per la segnalazione Docker: stackoverflow.com/a/32261019/99717
set -e
imposta un'opzione della shell per uscire immediatamente se un qualsiasi comando in esecuzione esce con un codice di uscita diverso da zero. Lo script tornerà con il codice di uscita del comando non riuscito. Dalla pagina man di bash:
set -e:
Esci immediatamente se una pipeline (che può consistere in un singolo comando semplice), una lista o un comando composto (vedi GRAMMATICA DELLA SHELL sopra), esce con uno stato diverso da zero. La shell non esce se il comando che fallisce fa parte dell'elenco dei comandi immediatamente dopo una parola chiave while o until, parte del test che segue le parole riservate if o elif, parte di qualsiasi comando eseguito in && o || list tranne il comando che segue la finale && o ||, qualsiasi comando in una pipeline tranne l'ultimo, o se il valore di ritorno del comando viene invertito con!. Se un comando composto diverso da una subshell restituisce uno stato diverso da zero perché un comando non è riuscito mentre -e veniva ignorato, la shell non esce. Una trap su ERR, se impostata, viene eseguita prima che la shell esca.
Se un comando composto o una funzione di shell viene eseguito in un contesto in cui -e viene ignorato, nessuno dei comandi eseguiti all'interno del comando composto o del corpo della funzione sarà influenzato dall'impostazione -e, anche se -e è impostato e un comando restituisce un stato di guasto. Se un comando composto o una funzione di shell imposta -e durante l'esecuzione in un contesto in cui -e viene ignorato, tale impostazione non avrà alcun effetto fino al completamento del comando composto o del comando contenente la chiamata di funzione.
exec "$@"
viene in genere utilizzato per rendere il punto di ingresso un passaggio che quindi esegue il comando docker. Sostituirà la shell in esecuzione corrente con il comando a cui "$@"
punta. Per impostazione predefinita, quella variabile punta agli argomenti della riga di comando.
Se hai un'immagine con un punto di ingresso che punta a entrypoint.sh e esegui il contenitore come docker run my_image server start
, ciò si tradurrà in esecuzione entrypoint.sh server start
nel contenitore. Alla riga exec entrypoint.sh
, la shell in esecuzione come pid 1 si sostituirà con il comando server start
.
Questo è fondamentale per la gestione del segnale. Senza l'uso exec
, server start
nell'esempio precedente verrebbe eseguito come un altro pid e, una volta terminato, si tornerà allo script della shell. Con una shell in pid 1, un SIGTERM verrà ignorato per impostazione predefinita. Ciò significa che il grazioso segnale di arresto che docker stop
invia al tuo contenitore non verrebbe mai ricevuto dal server
processo. Dopo 10 secondi (per impostazione predefinita), docker stop
rinuncerebbe allo spegnimento regolare e invierà un SIGKILL che costringerà la tua app a uscire, ma con potenziale perdita di dati o connessioni di rete chiuse, gli sviluppatori di app avrebbero potuto codificare se avessero ricevuto il segnale. Significa anche che il tuo contenitore impiegherà sempre 10 secondi per fermarsi.
Nota che con comandi di shell come shift
e set --
, puoi modificare il valore di "$@"
. Ad esempio, ecco una breve parte di uno script che rimuove /bin/sh -c "..."
dal comando che può apparire se si utilizza la sintassi della shell di Docker per CMD
:
# convert `/bin/sh -c "server start"` to `server start`
if [ $# -gt 1 ] && [ x"$1" = x"/bin/sh" ] && [ x"$2" = x"-c" ]; then
shift 2
eval "set -- $1"
fi
....
exec "$@"
test
specifica POSIX , che contrassegna come -a
obsoleta. [ "$#" -gt 1 ] && [ "$1" = /bin/sh ]
è la sostituzione corretta (non c'è bisogno x"$1"
dell'hackery quando si utilizza solo la sintassi non obsoleta).
shift 2; set -- $1
non è affatto lo stesso di come eval
analizzerà la stringa. Considera /bin/sh -c 'printf "%s\n" "hello world" "goodbye world"'
, se vuoi un test case concreto, e vedi Bash non analizza le virgolette quando converte una stringa in argomenti .
eval
, credo di volere ancora che rispecchi il comportamento di /bin/sh -c
avrebbe sulla stringa, ma per favore fatemi sapere se mi manca qualcosa.
set -e
- esci dallo script se un comando fallisce (valore diverso da zero)
exec "$@"
- reindirizzerà le variabili di input, vedere di più qui
exec
certamente ha una modalità di utilizzo in cui esegue i reindirizzamenti, ma questa non è quella modalità.
set -e
è considerato molto più soggetto a errori rispetto alla gestione degli errori scritti a mano. (Se hai fretta, salta l'analogia in alto per gli esercizi sotto).