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

问题描述:

我是Docker的新手,我很难根据需要设置Docker容器。我有一个nodejs应用程序在启动时可以带两个参数。例如,我可以使用使用docker run命令将参数传递给Dockerfile中的CMD

node server.js 0 dev

node server.js 1 prod

到和之间的生产模式和开发模式切换确定是否应该打开群集。现在,我想创建一个参数做类似的事情泊坞窗的形象,我可以迄今唯一能做的就是调整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“环境”命令和“集群”的论点,所以我并不需要改变Dockerfile和重建泊坞窗任何更多。我怎样才能做到这一点?

确保您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

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 form:

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

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

Builder RUN用同样的想法(适用于CMD以及):

不同于壳的形式中,EXEC形式不调用命令壳。
这意味着正常的shell处理不会发生。

例如,RUN [ "echo", "$HOME" ]将不会在$HOME上进行变量替换。如果需要shell处理,则使用shell窗体或直接执行shell,例如:RUN [ "sh", "-c", "echo $HOME" ]

当使用exec表单并直接执行一个shell(如shell格式的情况)时,它是在执行环境变量扩展的shell,而不是docker。

+0

如何在Docker文件CMD中使用ENV,你能举个例子吗? – Jaaaaaaay

+0

@Jaaaaaaay'ENV'是您的'Dockerfile'中的声明(请阅读https://docs.docker.com/engine/reference/builder/#/env),然后将通过'docker run -e myvar = myvalue' – VonC

+0

@Jaaaaaaay我编辑了答案来解决你的问题。 – VonC

在Docker容器做到这一点的典型方法是在环境变量传递:

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

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

使用这种方法,您Dockerfile看起来像

FROM ... 

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

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

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

和PROD运行它,你会传递的参数运行命令

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

您可能希望完全忽略CMD,并始终将0 dev1 prod作为参数传递给运行命令。这样你就不会无意中在产品的开发或开发容器中启动产品容器。