Co set -e i exec „$ @” robią dla skryptów punktu wejścia Dockera?

90

Zauważyłem, że wiele skryptów entrypoint.sh dla dockera robi coś takiego:

#!/bin/bash
set -e

... code ...

exec "$@"

Do czego służą set -ei exec "$@"do czego?

Nathan
źródło
2
Zobacz BashFAQ # 105 re: Whyset -e jest uważany za znacznie bardziej podatny na błędy niż ręczna obsługa błędów. (Jeśli się spieszysz, pomiń analogię u góry dotyczącą poniższych ćwiczeń).
Charles Duffy

Odpowiedzi:

70

W zasadzie pobiera wszelkie argumenty wiersza poleceń przekazane do entrypoint.shi wykonuje je jako polecenie. Intencją jest w zasadzie „Zrób wszystko w tym skrypcie .sh, a następnie w tej samej powłoce uruchom polecenie, które użytkownik podaje w wierszu poleceń”.

Widzieć:

Mateusz
źródło
1
Zauważ również, że exec "$@"spowoduje to zastąpienie aktualnie działającego procesu nowym procesem utworzonym dla przekazanych argumentów. Ważne dla sygnalizacji Docker: stackoverflow.com/a/32261019/99717
Hawkeye Parker
34

set -eustawia opcję powłoki na natychmiastowe zakończenie, jeśli dowolne uruchamiane polecenie kończy działanie z niezerowym kodem zakończenia. Skrypt zwróci kod zakończenia polecenia, które zakończyło się niepowodzeniem. Ze strony podręcznika bash:

ustaw -e:

Zakończ natychmiast, jeśli potok (który może składać się z pojedynczego prostego polecenia), lista lub polecenie złożone (zobacz powyżej GRAMATURA POWŁOKI), kończy działanie z niezerowym statusem. Powłoka nie kończy działania, jeśli polecenie, które się nie powiedzie, jest częścią listy poleceń występujących bezpośrednio po słowie kluczowym while lub until, częścią testu następującą po zastrzeżonych słowach if lub elif, częścią dowolnego polecenia wykonanego w a && lub || list z wyjątkiem polecenia następującego po ostatnim && lub ||, dowolnym poleceniu w potoku oprócz ostatniego lub jeśli wartość zwracana polecenia jest odwracana za pomocą!. Jeśli polecenie złożone inne niż podpowłoka zwraca stan niezerowy, ponieważ polecenie zakończyło się niepowodzeniem, podczas gdy -e było ignorowane, powłoka nie kończy działania. Pułapka na ERR, jeśli jest ustawiona, jest wykonywana przed zakończeniem działania powłoki.

Jeśli polecenie złożone lub funkcja powłoki są wykonywane w kontekście, w którym -e jest ignorowane, ustawienie -e nie będzie miało wpływu na żadne z poleceń wykonywanych w poleceniu złożonym lub treści funkcji, nawet jeśli -e jest ustawione, a polecenie zwraca wartość stan awarii. Jeśli polecenie złożone lub funkcja powłoki ustawia wartość -e podczas wykonywania w kontekście, w którym -e jest ignorowane, to ustawienie nie będzie miało żadnego efektu, dopóki polecenie złożone lub polecenie zawierające wywołanie funkcji nie zostanie zakończone.


exec "$@"jest zwykle używany do przejścia przez punkt wejścia, a następnie uruchamia polecenie docker. Zastąpi bieżącą uruchomioną powłokę poleceniem, na które "$@"wskazuje. Domyślnie ta zmienna wskazuje argumenty wiersza poleceń.

Jeśli masz obraz z punktem wejścia wskazującym na entrypoint.sh i uruchamiasz kontener jako docker run my_image server start, to przełoży się to na działanie entrypoint.sh server startw kontenerze. W linii exec entrypoint.sh, powłoka działająca jako pid 1 zastąpi się poleceniem server start.

Ma to kluczowe znaczenie dla obsługi sygnału. Bez użycia exec, server startw powyższym przykładzie działałby jako inny pid, a po zakończeniu wróciłbyś do skryptu powłoki. W przypadku powłoki w pid 1, SIGTERM będzie domyślnie ignorowany. Oznacza to, że wdzięczny sygnał stop, który docker stopwysyła do twojego kontenera, nigdy nie zostałby odebrany przez serverproces. Po 10 sekundach (domyślnie) docker stopzrezygnowałby z wdzięcznego zamknięcia i wysłał SIGKILL, który zmusi twoją aplikację do wyjścia, ale z potencjalną utratą danych lub zamkniętymi połączeniami sieciowymi, które twórcy aplikacji mogliby zakodować, gdyby otrzymali sygnał. Oznacza to również, że zatrzymanie pojemnika zawsze zajmie 10 sekund.

Zauważ, że za pomocą poleceń powłoki, takich jak shifti set --, możesz zmienić wartość "$@". Np. Tutaj jest krótka część skryptu, który usuwa /bin/sh -c "..."polecenie z polecenia, które może się pojawić, jeśli użyjesz składni powłoki Dockera dla 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 "$@"
BMitch
źródło
1
Zobacz specyfikację POSIXtest , która oznacza -aprzestarzałe. [ "$#" -gt 1 ] && [ "$1" = /bin/sh ]jest poprawnym zamiennikiem (nie ma potrzeby x"$1"hakowania, gdy używasz tylko nieaktualnej składni).
Charles Duffy
Ponadto shift 2; set -- $1nie jest tym samym, co sposób, w jaki evalprzeanalizuje ciąg. Zastanów się /bin/sh -c 'printf "%s\n" "hello world" "goodbye world"', czy chcesz mieć konkretny przypadek testowy i zobacz, że Bash nie analizuje cudzysłowów podczas konwersji ciągu znaków na argumenty .
Charles Duffy
@CharlesDuffy dzięki za wskazówkę na temat przestarzałej opcji, jestem pewien, że znowu popełnię ten błąd, stare nawyki umierają. Wydaje evalmi się, że nadal chcę, aby odzwierciedlało to zachowanie /bin/sh -cna strunie, ale daj mi znać, jeśli czegoś brakuje.
BMitch
30

set -e - wyjdź ze skryptu, jeśli jakiekolwiek polecenie nie powiedzie się (wartość niezerowa)

exec "$@"- przekieruje zmienne wejściowe, zobacz więcej tutaj

agilob
źródło
„Czy przekieruje zmienne wejściowe”? Ech? execz pewnością ma tryb użycia, w którym wykonuje przekierowania, ale to nie jest ten tryb.
Charles Duffy