Cosa fanno set -e ed exec "$ @" per gli script del punto di ingresso del docker?


95

Ho notato che molti script entrypoint.sh per docker fanno qualcosa del genere:

#!/bin/bash
set -e

... code ...

exec "$@"

A cosa servono set -ee exec "$@"?


2
Vedi BashFAQ # 105 re: why 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).
Charles Duffy

Risposte:


71

Fondamentalmente accetta qualsiasi argomento della riga di comando passato entrypoint.she 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:


1
Nota anche che 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
Hawkeye Parker

35

set -eimposta 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 startnel 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 startnell'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 stopinvia al tuo contenitore non verrebbe mai ricevuto dal serverprocesso. Dopo 10 secondi (per impostazione predefinita), docker stoprinuncerebbe 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 shifte 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 "$@"

1
Vedere la testspecifica POSIX , che contrassegna come -aobsoleta. [ "$#" -gt 1 ] && [ "$1" = /bin/sh ]è la sostituzione corretta (non c'è bisogno x"$1"dell'hackery quando si utilizza solo la sintassi non obsoleta).
Charles Duffy

Inoltre, shift 2; set -- $1non è affatto lo stesso di come evalanalizzerà 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 .
Charles Duffy

@CharlesDuffy grazie per il suggerimento sull'opzione obsoleta, sono sicuro che farò di nuovo questo errore, le vecchie abitudini sono dure a morire. Con il eval, credo di volere ancora che rispecchi il comportamento di /bin/sh -cavrebbe sulla stringa, ma per favore fatemi sapere se mi manca qualcosa.
BMitch

30

set -e - esci dallo script se un comando fallisce (valore diverso da zero)

exec "$@"- reindirizzerà le variabili di input, vedere di più qui


"Reindirizzerà le variabili di input"? Eh? execcertamente ha una modalità di utilizzo in cui esegue i reindirizzamenti, ma questa non è quella modalità.
Charles Duffy
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.