使用 docker run 命令将参数传递给 Dockerfile 中的 CMD

问题描述 投票:0回答:8

我有一个nodejs应用程序在启动时可以接受两个参数。例如,我可以使用

node server.js 0 dev

node server.js 1 prod

在生产模式和开发模式之间切换并确定是否应该打开集群。现在我想创建带有参数的 docker 映像来执行类似的操作。到目前为止我唯一能做的就是调整 Dockerfile 来增加一行

CMD [ "node", "server.js", "0", "dev"]

docker build -t me/app .
docker run -p 9000:9000 -d me/app

构建并运行 docker 镜像。

但是如果我想切换到生产模式,我需要将 Dockerfile CMD 更改为:

CMD [ "node", "server.js", "1", "prod"]

我需要终止侦听端口 9000 的旧版本并重建映像。 我希望我能拥有类似的东西

docker run -p 9000:9000 environment=dev cluster=0 -d me/app 

创建一个镜像并使用“环境”和“集群”参数运行nodejs命令,这样我就不需要再更改Dockerfile并重建docker了。我怎样才能做到这一点?

node.js docker dockerfile
8个回答
138
投票

确保您的 Dockerfile 声明了一个环境变量 with

ENV
:

ENV environment default_env_value
ENV cluster default_cluster_value

ENV <key> <value>
形式可以被替换为内联

然后您可以使用 docker run 传递环境变量。请注意,每个变量都需要特定的

-e
标志才能运行。

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}"]

解释是shell负责扩展环境变量,而不是Docker。当您使用 JSON 语法 时,您明确请求您的命令绕过 shell 并直接执行。

Builder RUN相同的想法(也适用于

CMD
):

与 shell 形式不同,exec 形式不调用命令 shell。
这意味着不会发生正常的 shell 处理。

例如,

RUN [ "echo", "$HOME" ]
不会对
$HOME
进行变量替换。如果你想要 shell 处理,那么要么使用 shell 形式,要么直接执行 shell,例如:
RUN [ "sh", "-c", "echo $HOME" ]
.

当使用exec形式直接执行shell时,就像shell形式一样,是shell在做环境变量扩展,而不是docker。

正如Pwnstar评论中所指出的:

当您使用 shell 命令时,此进程将不会

id=1
启动。


74
投票

另一个选项是使用

ENTRYPOINT
指定
node
是要运行的可执行文件,并使用
CMD
提供参数。该文档在Exec form ENTRYPOINT example中有一个示例。

使用这种方法,您的 Dockerfile 将类似于

FROM ...

ENTRYPOINT [ "node",  "server.js" ]
CMD [ "0", "dev" ]

在开发环境中运行它会使用相同的命令

docker run -p 9000:9000 -d me/app

并在产品中运行它,您会将参数传递给运行命令

docker run -p 9000:9000 -d me/app 1 prod

您可能希望完全省略

CMD
并始终将
0 dev
1 prod
作为运行命令的参数传递。这样您就不会意外地在 dev 中启动 prod 容器或在 prod 中启动 dev 容器。


16
投票

选项 1)使用 ENV 变量

Dockerfile

# we need to specify default values
ENV ENVIRONMENT=production
ENV CLUSTER=1

# there is no need to use parameters array
CMD node server.js ${CLUSTER} ${ENVIRONMENT}

Docker 运行

$ docker run -d -p 9000:9000 -e ENVIRONMENT=dev -e CLUSTER=0 -me/app

选项 2)传递参数

Dockerfile

# use entrypoint instead of CMD and do not specify any arguments
ENTRYPOINT node server.js

Docker 运行

在 docker 镜像名称后传递参数

$ docker run -p 9000:9000 -d me/app 0 dev

6
投票

在 Docker 容器中执行此操作的典型方法是传入环境变量:

docker run -p 9000:9000 -e NODE_ENV=dev -e CLUSTER=0 -d me/app

6
投票

迟到加入讨论。这是一个漂亮的技巧,您可以使用它来设置默认命令行参数,同时还支持使用自定义参数覆盖默认参数:

Step#1 在你的 dockerfile 中像这样调用你的程序:

ENV DEFAULT_ARGS "--some-default-flag=123 --foo --bar"
CMD ["/bin/bash", "-c", "./my-nifty-executable   ${ARGS:-${DEFAULT_ARGS}}"]

Step#2 现在什么时候可以像这样调用 docker-image:

# this will invoke it with DEFAULT_ARGS
docker run mydockerimage   

# but this will invoke the docker image with custom arguments
docker run   --env  ARGS="--alternative-args  --and-then-some=123"   mydockerimage 

您还可以调整此技术以进行更复杂的论证评估,但您认为合适。 Bash 支持多种单行结构来帮助您实现这一目标。

希望这项技术可以帮助一些人节省几个小时的时间。


4
投票

稍微偏离主题,构建参数的存在允许您在构建时传递参数,这些参数表现为环境变量以在 docker 镜像构建过程中使用:

$ docker build --build-arg HTTP_PROXY=http://10.20.30.2:1234 .

3
投票

不确定这是否有帮助,但我已经这样使用过,而且效果非常好

CMD ["node", "--inspect=0.0.0.0:9229", "--max-old-space-size=256", "/home/api/index.js"]


2
投票

我发现这个在 docker-compose not setenvironmentvariables withflask

docker-compose.yml

version: '2'

services:
  app:
      image: python:2.7
      environment:
        - BAR=FOO
      volumes:
        - ./app.py:/app.py
      command: python app.py

app.py

import os

print(os.environ["BAR"])
© www.soinside.com 2019 - 2024. All rights reserved.