Что делают set -e и exec «$ @» для скриптов точки входа докеров?

90

Я заметил, что многие скрипты entrypoint.sh для docker делают что-то вроде этого:

#!/bin/bash
set -e

... code ...

exec "$@"

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

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

Ответы:

70

Он в основном принимает любые переданные аргументы командной строки entrypoint.shи выполняет их как команду. Смысл в основном такой: «Сделайте все в этом сценарии .sh, а затем в той же оболочке выполните команду, которую пользователь передает в командной строке».

Увидеть:

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

set -eустанавливает параметр оболочки для немедленного выхода, если какая-либо выполняемая команда завершается с ненулевым кодом выхода. Сценарий вернется с кодом выхода невыполненной команды. На странице руководства bash:

установить -e:

Немедленно выйти, если конвейер (который может состоять из одной простой команды), список или составная команда (см. ГРАММАТУРА ОБОЛОЧКИ выше) завершается с ненулевым статусом. Оболочка не завершает работу, если команда, которая завершилась ошибкой, является частью списка команд сразу после ключевого слова while или until, частью теста, следующей за зарезервированными словами if или elif, частью любой команды, выполняемой в && или || list, кроме команды, следующей за последним && или ||, любой команды в конвейере, кроме последней, или если возвращаемое значение команды инвертируется с помощью!. Если составная команда, отличная от подоболочки, возвращает ненулевое состояние из-за сбоя команды при игнорировании -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 "..."из команды, которая может появиться, если вы используете синтаксис оболочки докера для 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
источник
1
См в POSIX 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 не анализирует кавычки при преобразовании строки в аргументы .
Чарльз Даффи
@CharlesDuffy, спасибо за подсказку по поводу устаревшего варианта, я уверен, что повторю эту ошибку снова, старые привычки умирают с трудом. С eval, я считаю , что я все еще хочу, чтобы отразить поведение /bin/sh -cбудет иметь на шпагат, но , пожалуйста , дайте мне знать , если я что - то не хватает.
BMitch 04
30

set -e - выйти из скрипта в случае сбоя какой-либо команды (ненулевое значение)

exec "$@"- перенаправит входные переменные, подробнее см. здесь

Agilob
источник
«Будут перенаправлять входные переменные»? А? execконечно, есть режим использования, в котором выполняется перенаправление, но это не тот режим.
Чарльз Даффи