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

guykilcj  于 2023-04-05  发布在  Docker
关注(0)|答案(8)|浏览(417)

我是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
创建镜像,并使用“environment”和“cluster”参数运行nodejs命令,这样我就不需要再修改Dockerfile和重新构建docker了。如何才能完成?

lskq00tm

lskq00tm1#

确保Dockerfile使用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

或者你可以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。
正如Pwnstar在评论中所指出的:
当你使用shell命令时,这个过程将 * 不 * 用id=1启动。

0aydgbwb

0aydgbwb2#

另一种选择是使用ENTRYPOINT指定node是要运行的可执行文件,CMD提供参数。文档中有一个Exec表单ENTRYPOINT示例。
使用这种方法,您的Dockerfile将类似于

FROM ...

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

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

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

然后在prod中运行它,您将把参数传递给run命令

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

您可能希望完全省略CMD,并始终将0 dev1 prod作为参数传递给run命令。这样您就不会意外地启动dev中的prod容器或prod中的dev容器。

vsaztqbk

vsaztqbk3#

选项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 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 run -p 9000:9000 -d me/app 0 dev
hgc7kmma

hgc7kmma4#

在Docker容器中实现这一点的典型方法是传入环境变量:

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

pkbketx95#

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

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

carvr3hs6#

这里有一个漂亮的技巧,你可以用来设置默认的命令行参数,同时也支持用自定义参数覆盖默认参数:
步骤#1在你的dockerfile中调用你的程序,如下所示:

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

Step#2 When现在可以像这样调用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支持多种单行结构来帮助你实现这个目标。
希望这个技巧能帮助一些人保存几个小时的挠头时间。

a11xaf1n

a11xaf1n7#

不确定这是否有帮助,但我已经用过这种方式,它的工作就像一个魅力
CMD ["node", "--inspect=0.0.0.0:9229", "--max-old-space-size=256", "/home/api/index.js"]

3duebb1j

3duebb1j8#

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

停靠-编写.yml

version: '2'

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

应用程序.py

import os

print(os.environ["BAR"])

相关问题