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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/40873165/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 17:51:00  来源:igfitidea点击:

Use docker run command to pass arguments to CMD in Dockerfile

node.jsdockerdockerfile

提问by Jaaaaaaay

I'm new to Docker and I'm having a hard time to setup the docker container as I want. I have a nodejs app can take two parameters when start. For example, I can use

我是 Docker 的新手,我很难按照自己的意愿设置 Docker 容器。我有一个 nodejs 应用程序可以在启动时使用两个参数。例如,我可以使用

node server.js 0 dev

node server.js 0 dev

or

或者

node server.js 1 prod

node server.js 1 prod

to switch between production mode and dev mode and determine if it should turn the cluster on. Now I want to create docker image with arguments to do the similar thing, the only thing I can do so far is to adjust the Dockerfile to have a line

在生产模式和开发模式之间切换并确定是否应该打开集群。现在我想用参数来创建 docker 镜像来做类似的事情,到目前为止我唯一能做的就是调整 Dockerfile 以有一条线

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

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

and

docker build -t me/app .to build the docker.

docker build -t me/app .构建泊坞窗。

Then docker run -p 9000:9000 -d me/appto run the docker.

然后docker run -p 9000:9000 -d me/app运行docker。

But If I want to switch to prod mode, I need to change the Dockerfile CMD to be

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

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

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

and I need to kill the old one listening on port 9000 and rebuild the image. I wish I can have something like

我需要杀死在端口 9000 上侦听的旧的并重建映像。我希望我能有类似的东西

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

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

to create an image and run the nodejs command with "environment" and "cluster" arguments, so I don't need to change the Dockerfile and rebuild the docker any more. How can I accomplish this?

创建映像并使用“environment”和“cluster”参数运行 nodejs 命令,因此我不再需要更改 Dockerfile 并重建 docker。我怎样才能做到这一点?

回答by VonC

Make sure your Dockerfile declares an environment variable with ENV:

确保您的Dockerfile声明环境变量ENV

ENV environment default_env_value
ENV cluster default_cluster_value

The ENV <key> <value>form can be replaced inline.

ENV <key> <value>形式可以代替内联

Then you can pass an environment variable with docker run

然后你可以通过 docker run 传递一个环境变量

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

Or you can set them through your compose file:

或者您可以通过您的撰写文件设置它们

node:
  environment:
    - environment=dev
    - cluster=0

Your Dockerfile CMDcan use that environment variable, but, as mentioned in issue 5509, you need to do so in a sh -cform:

您的 DockerfileCMD可以使用该环境变量,但是,如issue 5509 中所述,您需要以一种sh -c形式这样做:

CMD ["sh", "-c", "node server.js ${cluster} ${environment}"]

The explanation is that the shell is responsible for expanding environment variables, not Docker. When you use the JSON syntax, you're explicitly requesting that your command bypass the shell and be executed directly.

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

Same idea with Builder RUN(applies to CMDas well):

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

Unlike the shell form, the exec form does not invoke a command shell.
This means that normal shell processing does not happen.

For example, RUN [ "echo", "$HOME" ]will not do variable substitution on $HOME. If you want shell processing then either use the shell form or execute a shell directly, for example: RUN [ "sh", "-c", "echo $HOME" ].

When using the exec form and executing a shell directly, as in the case for the shell form, it is the shell that is doing the environment variable expansion, not docker.

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

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

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

回答by R0MANARMY

Another option is to use ENTRYPOINTto specify that nodeis the executable to run and CMDto provide the arguments. The docs have an example in Exec form ENTRYPOINT example.

另一个选项是用于ENTRYPOINT指定node要运行的可执行文件并CMD提供参数。文档中有一个Exec 形式的示例 ENTRYPOINT example

Using this approach, your Dockerfile will look something like

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

FROM ...

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

Running it in dev would use the same command

在 dev 中运行它会使用相同的命令

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

and running it in prod you would pass the parameters to the run command

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

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


You may want to omit CMDentirely and always pass in 0 devor 1 prodas arguments to the run command. That way you don't accidentally start a prod container in dev or a dev container in prod.

您可能希望CMD完全省略并始终传入0 dev1 prod作为运行命令的参数。这样你就不会意外地在 dev 中启动一个 prod 容器或在 prod 中启动一个 dev 容器。

回答by Paul

The typical way to do this in Docker containers is to pass in environment variables:

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

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

回答by Ryan Augustine

Going a bit off topic, build arguments exist to allow you to pass in arguments at build time that manifest as environment variables for use in your docker image build process:

有点偏离主题,存在构建参数以允许您在构建时传递参数,这些参数显示为环境变量,以在您的 docker 映像构建过程中使用:

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