如何在Dockerfile CMD中使用变量?

dav*_*vid 69 docker dockerfile

在我的Dockerfile中:

ENV PROJECTNAME mytestwebsite
CMD ["django-admin", "startproject", "$PROJECTNAME"]
Run Code Online (Sandbox Code Playgroud)

错误:

CommandError: '$PROJECTNAME' is not a valid project name
Run Code Online (Sandbox Code Playgroud)

什么是最快的解决方法?Docker是否有计划在更高版本的Docker中"修复"或引入此功能?

注意:如果我从Docker文件中删除CMD行然后运行Docker容器,我可以从容器内部手动运行Django-admin startproject $ PROJECTNAME,它将创建项目...

lar*_*sks 116

当您使用执行列表时,如...

CMD ["django-admin", "startproject", "$PROJECTNAME"]
Run Code Online (Sandbox Code Playgroud)

...然后Docker将直接执行给定的命令,而不涉及shell.由于没有涉及shell,这意味着:

  • 没有可变扩展
  • 没有通配符扩展
  • 没有I/O重定向功能>,<,|
  • 没有多个命令通过 command1; command2
  • 等等.

如果您希望CMD扩展变量,则需要安排shell.你可以这样做:

CMD ["sh", "-c", "django-admin startproject $PROJECTNAME"]
Run Code Online (Sandbox Code Playgroud)

或者您可以使用简单的字符串而不是执行列表,这会使您获得与前一个示例大致相同的结果:

CMD django-admin startproject $PROJECTNAME
Run Code Online (Sandbox Code Playgroud)

  • @mr.bjerre 我想,应该使用 `exec` 来替换 bash 的新进程。可能与接收信号和CTRL+C有关。像`CMD ["sh", "-c", "exec django-admin startproject $PROJECTNAME"]`之类的东西。 (5认同)
  • 如果我使用这些技巧之一,那么我将无法再使用 CTRL+C 停止我的容器。有人找到解决方案吗? (4认同)
  • 在Docker的问题跟踪器中阅读更多内容:https://github.com/docker/docker/issues/5509 (2认同)

小智 34

如果要在运行时使用该值,请ENVDockerfile. 如果你想在构建时使用它,那么你应该使用ARG.

例子 :

ARG value
ENV envValue=$value
CMD ["sh", "-c", "java -jar ${envValue}.jar"]
Run Code Online (Sandbox Code Playgroud)

在构建命令中传递值:

ARG value
ENV envValue=$value
CMD ["sh", "-c", "java -jar ${envValue}.jar"]
Run Code Online (Sandbox Code Playgroud)


小智 31

您还可以使用exec 这是处理信号并同时使用环境变量的唯一已知方法。根据 Docker github尝试实现优雅关闭之类的东西时,它会很有帮助

例子:

ENV PROJECTNAME mytestwebsite 
CMD exec django-admin startproject $PROJECTNAME
Run Code Online (Sandbox Code Playgroud)

  • 没有人看到你的答案(我想添加),但这是迄今为止最好的解决方案;) (3认同)
  • 这是正确的答案,而不是当前接受的答案,它不能正确处理操作系统信号!将操作系统信号传播到可执行文件非常重要。例如,在 Kubernetes 中,信号用于正常关闭。我只想补充一点,[“json array”] 语法通常是 CMD 的首选,例如一些 linters 强制执行它:https://github.com/hadolint/hadolint/wiki/DL3025 所以我会更改示例以使用它句法。 (3认同)

Fla*_*llo 7

假设您要在容器内启动Java进程:

Dockerfile示例摘录:

ENV JAVA_OPTS -XX +UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=1 -XshowSettings:vm 
... 
ENTRYPOINT ["/sbin/tini", "--", "entrypoint.sh"] 
CMD ["java", "${JAVA_OPTS}", "-myargument=true"]
Run Code Online (Sandbox Code Playgroud)

示例entrypoint.sh摘录:

#!/bin/sh 
... 
echo "*** Startup $0 suceeded now starting service using eval to expand CMD variables ***"
exec su-exec mytechuser $(eval echo "$@")
Run Code Online (Sandbox Code Playgroud)