Що робить set -e та exec “$ @” для сценаріїв точки входу докера?


90

Я помітив, що багато сценаріїв entrypoint.sh для docker роблять щось подібне:

#!/bin/bash
set -e

... code ...

exec "$@"

Що таке set -eі exec "$@"для чого?


2
Див. BashFAQ # 105 re: чому set -eвважається набагато схильнішим до помилок, ніж рукописне оброблення помилок. (Якщо поспішаєте, пропустіть аналогію вгорі для вправ нижче).
Чарльз Даффі

Відповіді:


70

В основному він приймає будь-які аргументи командного рядка, передані entrypoint.shта виконує їх як команду. Намір полягає в основному "Зробити все в цьому скрипті .sh, а потім у тій самій оболонці запустити команду, яку користувач передає в командному рядку".

Подивитися:


1
Також зауважте, що exec "$@"поточний процес буде замінено новим процесом, породженим для переданих аргументів. Важливо для сигналізації Docker: stackoverflow.com/a/32261019/99717
Hawkeye Parker

34

set -eвстановлює опцію оболонки для негайного виходу, якщо будь-яка виконувана команда виходить із ненульовим кодом виходу. Сценарій повернеться з кодом виходу команди, що не працює. Зі сторінки керівництва bash:

set -e:

Негайно вийдіть, якщо конвеєр (який може складатися з однієї простої команди), списку або складеної команди (див. ГРАМАТИКУ SHELL вище) виходить із ненульовим статусом. Оболонка не виходить, якщо команда, яка не вдається, є частиною списку команд, що слідує відразу після ключового слова або до тих пір, частина тесту після зарезервованих слів if або elif, частина будь-якої команди, виконаної в && або || список, за винятком команди, що слідує за кінцевим && або ||, будь-якої команди в конвеєрі, крім останньої, або якщо повертається значення команди інвертується! Якщо складена команда, яка відрізняється від допоміжної оболонки, повертає ненульовий статус, оскільки команда не вдалася під час ігнорування -e, оболонка не виходить. Перехоплення ERR, якщо встановлено, виконується перед виходом оболонки.

Якщо складена команда або функція оболонки виконується в контексті, де -e ігнорується, жодна з команд, що виконуються в складеній команді або тілі функції, не буде впливати на параметр -e, навіть якщо встановлено -e і команда повертає статус відмови. Якщо складена команда або функція оболонки встановлює -e під час виконання в контексті, де -e ігнорується, це налаштування не матиме жодного ефекту до завершення складеної команди або команди, що містить виклик функції.


exec "$@"зазвичай використовується для проходження точки входу, після чого запускається команда docker. Він замінить поточну запущену оболонку командою, на яку "$@"вказує. За замовчуванням ця змінна вказує на аргументи командного рядка.

Якщо у вас є зображення з точкою входу, що вказує на entrypoint.sh, і ви запускаєте свій контейнер як docker run my_image server start, це означає, що він працює entrypoint.sh server startв контейнері. У рядку exec entrypoint.shоболонка, що працює як pid 1, замінить себе командою server start.

Це критично важливо для обробки сигналів. Без використання exec, server startу наведеному вище прикладі буде виконуватися як інший pid, і після його виходу ви повернетесь до свого сценарію оболонки. З оболонкою в pid 1, SIGTERM буде ігноруватися за замовчуванням. Це означає, що витончений сигнал зупинки, який docker stopнадходить до вашого контейнера, ніколи не буде отриманий serverпроцесом. Через 10 секунд (за замовчуванням) docker stopвідмовиться від витонченого вимкнення та надішле SIGKILL, який змусить ваш додаток вийти, але з потенційною втратою даних або закритими мережевими з’єднаннями, які розробники програм могли б закодувати, якщо отримали сигнал. Це також означає, що на ваш контейнер завжди знадобиться 10 секунд, щоб зупинитися.

Зверніть увагу, що за допомогою команд оболонки типу shiftі set --ви можете змінити значення "$@". Наприклад, ось коротка частина сценарію, який видаляє /bin/sh -c "..."команду, яка може з’явитися, якщо ви використовуєте синтаксис оболонки docker для 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
Дивіться специфікацію POSIXtest , яка позначає -aзастарілі. [ "$#" -gt 1 ] && [ "$1" = /bin/sh ]є правильною заміною (немає необхідності в x"$1"хакерстві, коли використовується лише неактуальний синтаксис).
Чарльз Даффі

Крім того, shift 2; set -- $1це зовсім не те саме, як evalбуде проводитися синтаксичний аналіз рядка. Подумайте /bin/sh -c 'printf "%s\n" "hello world" "goodbye world"', якщо вам потрібен конкретний тестовий приклад, і переконайтеся, що Bash не аналізує лапки при перетворенні рядка в аргументи .
Чарльз Даффі

@CharlesDuffy дякую за підказку щодо застарілого варіанту, я впевнений, що знову зроблю цю помилку, старі звички важко вмирають. Зважаючи на те eval, що я все ще хочу, щоб це відображало поведінку, яке /bin/sh -cбуло б на рядку, але, будь ласка, дайте мені знати, якщо я щось пропускаю.
BMitch

30

set -e - скрипт виходу, якщо якась команда не вдається (ненульове значення)

exec "$@"- буде переспрямовувати вхідні змінні, докладніше див. тут


"Чи буде переспрямовувати вхідні змінні"? А? execбезумовно, є режим використання, де він здійснює переспрямування, але це не той режим.
Чарльз Даффі
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.