#docker #dockerfile
Вопрос:
У меня есть файл настройки, в котором я запускаю исполняемый файл с такими аргументами по умолчанию, как этот:
ENTRYPOINT ["executable", "cmd"]
CMD ["--param1=1", "--param2=2"]
Это отлично работает, и я могу запустить контейнер с аргументами по умолчанию:
docker run image_name
или с пользовательскими аргументами:
docker run image_name --param1=a --param2=2
Теперь я хотел бы, чтобы параметр по умолчанию зависел от переменной среды или по умолчанию имел значение deafult (1) , подобное этому:
--param1='${PARAM1:-1}'
Я понимаю, что
ENTRYPOINT ["executable", "cmd"]
CMD ["--param1='${PARAM1:-1}'", "--param2=2"]
не работает, так как CMD находится в форме exec и не вызывает командную оболочку и не может заменять переменные среды.
Но если я использую CMD в форме оболочки:
ENTRYPOINT ["executable", "cmd"]
CMD "--param1='${PARAM1:-1}' --param2=2"
Я получаю no such option: -c
Поэтому мой вопрос таков:
Как я могу архивировать замену переменных среды в аргументах по умолчанию в CMD для моей ТОЧКИ входа?
Ответ №1:
Одним из способов было бы потерять CMD и перенести все значения по умолчанию в пользовательскую точку входа. Я стараюсь избегать этого, но иногда это кажется самым чистым способом, и вы можете быть намного более гибкими:
Докерфайл:
COPY 'my-entrypoint.sh' '/somewhere/in/path/my-entrypoint'
ENTRYPOINT ['my-entrypoint']
my-entrypoint.sh
#!/bin/sh
ARGS="${@}"
if [ -z "${ARGS}" ]; then
ARGS="--param1=${PARAM1:-1} --param2=2"
fi
executable cmd $ARGS
Комментарии:
1. Спасибо за эту подсказку, она хорошо работает, но мне пришлось изменить последнюю строку с
executable cmd "${ARGS}"
наexecutable cmd $ARGS
. В противном случае строка ARGS была обрезана и, следовательно, неполной. Чего я не могу понять. Я проверялecho "${ARGS}"
иecho $ARGS
раньшеexecutable cmd $ARGS
, и оба выглядели завершенными.2. Я скорректировал свой ответ, чтобы отразить эту трудность. Однако я также не понимаю проблемы и могу подтвердить, что успешно использую аналогичные методы с синтаксисом переменной в кавычках.
Ответ №2:
Вы не можете сделать это так, как вы описываете, по причинам, которые вы изложили в вопросе. ENTRYPOINT
И CMD
просто объединяются вместе, образуя единую командную строку, и если одна или обе эти части являются строкой, а не массивом JSON, он автоматически преобразуется sh -c 'the string'
.
ENTRYPOINT ["executable", "cmd"]
CMD "--param1='${PARAM1:-1}' --param2=2"
# Equivalently:
ENTRYPOINT ["executable", "cmd", "/bin/sh", "-c", ""--param1=...""]
CMD []
Есть два метода, которые я бы предложил для решения этой проблемы, хотя оба они требуют потенциально существенных изменений в настройке.
В Docker и Kubernetes, как правило, оказывается более удобным передавать параметры через переменные среды, чем в командной строке. Это означает, что вашему приложению необходимо знать, как искать эти переменные, и указать некоторые из значений по умолчанию, которые вы описываете здесь. Некоторые библиотеки анализа аргументов поддерживают это из коробки, но не все. argparse
Например, стандартная библиотека Python напрямую не поддерживает переменные среды, но вы все равно можете легко поддерживать их:
import argparse
import os
parser = argparse.ArgumentParser()
parser.add_argument('param1', default=os.environ.get('PARAM1', '1'))
args = parser.parse_args()
print(args.param1)
# Uses --param1 option, or else $PARAM1 variable, or else default "1"
Другой подход, который я обычно рекомендую,-это создать CMD
хорошо сформированную команду оболочки; не пытайтесь разделить команду между CMD
и ENTRYPOINT
. Это позволяет избежать проблемы, связанной с тем, что докер вставляет sh -c
оболочку в середину строки.
# no ENTRYPOINT
CMD executable cmd --param1="${PARAM1:-1}" --param2=2
ENTRYPOINT
Шаблон, который я нахожу полезным, состоит в том, чтобы использовать сценарий-оболочку для предоставления значений по умолчанию и выполнения других настроек в первый раз. Если этот сценарий является сценарием оболочки Bourne и заканчивается exec "$@"
, то он будет выполняться CMD
как основной процесс контейнера.
#!/bin/sh
# docker-entrypoint.sh
# In Docker specifically, default $PARAM1 to "docker", not "1".
: ${PARAM1:=docker}
# Run the main container command.
exec "$@"
ENTRYPOINT ["/docker-entrypoint.sh"] # must be a JSON array
CMD executable cmd --param2=2
(Нет необходимости иметь ENTRYPOINT
. Создание ENTRYPOINT
интерпретатора и ввод имени сценария CMD
не приносит никакой пользы и затрудняет выполнение таких команд отладки, как docker run --rm my-image ls -l /app
.)