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

Posted

技术标签:

【中文标题】使用 docker run 命令将参数传递给 Dockerfile 中的 CMD【英文标题】:Use docker run command to pass arguments to CMD in Dockerfile 【发布时间】:2017-04-13 21:05:49 【问题描述】:

我是 Docker 新手,我很难根据需要设置 docker 容器。我有一个 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。

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

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

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

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

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

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

【问题讨论】:

【参考方案1】:

我在docker-compose not setting environment variables with flask找到了这个

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

【讨论】:

【参考方案2】:

不确定这是否有帮助,但我已经以这种方式使用它,它就像一个魅力

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

【讨论】:

【参考方案3】:

确保你的 Dockerfile 声明了一个环境变量 with ENV:

ENV environment default_env_value
ENV cluster default_cluster_value

ENV <key> <value> 表单可以是 replaced inline。

那你可以pass an environment variable with docker run。请注意,每个变量都需要一个特定的-e 标志才能运行。

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

或者你可以set them through your compose file:

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。

【讨论】:

如何在docker文件CMD中使用ENV,可以举个例子吗? @Jaaaaaaay ENV 是您的Dockerfile 中的声明(阅读docs.docker.com/engine/reference/builder/#/env),然后将由docker run -e myvar=myvalue 评估【参考方案4】:

选项 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

【讨论】:

【参考方案5】:

有点跑题了,构建参数的存在允许您在构建时传递参数,这些参数表现为环境变量,以便在您的 docker 映像构建过程中使用:

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

【讨论】:

这就是我要找的……!!【参考方案6】:

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

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

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 dev1 prod 作为参数传递给运行命令。这样您就不会意外在 dev 中启动 prod 容器或在 prod 中启动 dev 容器。

【讨论】:

【参考方案7】:

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

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

【讨论】:

以上是关于使用 docker run 命令将参数传递给 Dockerfile 中的 CMD的主要内容,如果未能解决你的问题,请参考以下文章

将命令行参数传递给在 Docker 中运行的 Java 应用程序(Spring Boot)

docker run 参数说明

如何在谷歌云构建中将参数传递给 docker run

Fastlane 将参数传递给插件

使用 Azure DevOps 构建管道将机密传递给容器时,Docker BuildKit 返回“/run/secrets/<secret-id>:没有这样的文件或目录”

如何将命令行参数传递给 vue.config.js?