Используйте команду запуска docker для передачи аргументов CMD в Dockerfile
Я новичок в Docker, и мне сложно установить контейнер докеров, как я хочу. У меня приложение nodejs может принимать два параметра при запуске. Например, я могу использовать
node server.js 0 dev
или
node server.js 1 prod
для переключения между режимом работы и режимом dev и определить, нужно ли включить кластер. Теперь я хочу создать изображение докеров с аргументами, чтобы сделать подобное, единственное, что я могу сделать до сих пор, - настроить Dockerfile на строку
CMD [ "node", "server.js", "0", "dev"]
и
docker build -t me/app .
, чтобы построить докер.
Затем docker run -p 9000:9000 -d me/app
для запуска докера.
Но если я хочу перейти в режим prod, мне нужно изменить Dockerfile CMD на
CMD [ "node", "server.js", "1", "prod"]
,
и мне нужно убить старого, прослушивающего порт 9000, и перестроить изображение.
Хотел бы я иметь что-то вроде
docker run -p 9000:9000 environment=dev cluster=0 -d me/app
чтобы создать образ и запустить команду nodejs с аргументами "среда" и "кластер", поэтому мне больше не нужно менять файл Docker и перестраивать докеры. Как я могу это сделать?
Ответы
Ответ 1
Убедитесь, что ваш файл Dockerfile объявляет переменную окружения с ENV
:
ENV environment default_env_value
ENV cluster default_cluster_value
Форма ENV <key> <value>
может быть заменена встроенной.
Затем вы можете передать переменную окружения с запуском docker
docker run -p 9000:9000 -e environment=dev -e cluster=0 -d me/app
Или вы можете установить их через свой файл компоновки:
node:
environment:
- environment=dev
- cluster=0
Ваш Dockerfile CMD
может использовать эту переменную среды, но, как упоминалось в issue 5509, вам нужно сделать это в sh -c
форма:
CMD ["sh", "-c", "node server.js ${cluster} ${environment}"]
Объяснение заключается в том, что оболочка отвечает за расширение переменных среды, а не Docker. Когда вы используете синтаксис JSON, вы явно запрашиваете, чтобы ваша команда обошла оболочку и выполнялась напрямую.
Такая же идея с Builder RUN (относится также к CMD
):
В отличие от формы оболочки форма exec не вызывает командную оболочку.
Это означает, что нормальной обработки оболочки не происходит.
Например, RUN [ "echo", "$HOME" ]
не будет выполнять замену переменных на $HOME
. Если вы хотите обработать оболочку, то либо используйте форму оболочки, либо выполните оболочку напрямую, например: RUN [ "sh", "-c", "echo $HOME" ]
.
При использовании формы exec и непосредственного выполнения оболочки, как и в случае с формой оболочки, это оболочка, которая выполняет расширение переменной среды, а не докер.
Ответ 2
Другой вариант - использовать ENTRYPOINT
, чтобы указать, что node
- исполняемый файл для запуска, и CMD
, чтобы предоставить аргументы. В документах есть пример в Exec form ENTRYPOINT пример.
Используя этот подход, ваш файл Docker будет выглядеть примерно так:
FROM ...
ENTRYPOINT [ "node", "server.js" ]
CMD [ "0", "dev" ]
Запуск в dev будет использовать ту же команду
docker run -p 9000:9000 -d me/app
и запустив его в prod, вы передадите параметры команде запуска
docker run -p 9000:9000 -d me/app 1 prod
Вы можете полностью опустить CMD
и всегда передавать в 0 dev
или 1 prod
в качестве аргументов команды запуска. Таким образом, вы случайно не запускаете контейнер prod в dev или dev-контейнере в prod.
Ответ 3
Типичный способ сделать это в контейнерах Docker - передать переменные среды:
docker run -p 9000:9000 -e NODE_ENV=dev -e CLUSTER=0 -d me/app