Я помітив, що багато сценаріїв entrypoint.sh для docker роблять щось подібне:
#!/bin/bash
set -e
... code ...
exec "$@"
Що таке set -e
і exec "$@"
для чого?
Відповіді:
В основному він приймає будь-які аргументи командного рядка, передані entrypoint.sh
та виконує їх як команду. Намір полягає в основному "Зробити все в цьому скрипті .sh, а потім у тій самій оболонці запустити команду, яку користувач передає в командному рядку".
Подивитися:
exec "$@"
поточний процес буде замінено новим процесом, породженим для переданих аргументів. Важливо для сигналізації Docker: stackoverflow.com/a/32261019/99717
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 "$@"
test
, яка позначає -a
застарілі. [ "$#" -gt 1 ] && [ "$1" = /bin/sh ]
є правильною заміною (немає необхідності в x"$1"
хакерстві, коли використовується лише неактуальний синтаксис).
shift 2; set -- $1
це зовсім не те саме, як eval
буде проводитися синтаксичний аналіз рядка. Подумайте /bin/sh -c 'printf "%s\n" "hello world" "goodbye world"'
, якщо вам потрібен конкретний тестовий приклад, і переконайтеся, що Bash не аналізує лапки при перетворенні рядка в аргументи .
eval
, що я все ще хочу, щоб це відображало поведінку, яке /bin/sh -c
було б на рядку, але, будь ласка, дайте мені знати, якщо я щось пропускаю.
set -e
- скрипт виходу, якщо якась команда не вдається (ненульове значення)
exec "$@"
- буде переспрямовувати вхідні змінні, докладніше див. тут
exec
безумовно, є режим використання, де він здійснює переспрямування, але це не той режим.
set -e
вважається набагато схильнішим до помилок, ніж рукописне оброблення помилок. (Якщо поспішаєте, пропустіть аналогію вгорі для вправ нижче).