在Dockerfile中覆盖inheritance的CMD并不总是工作?

我在派生的Dockerfile中覆盖CMD时遇到了一些不一致的行为。

基本的Dockerfile看起来像这样:

FROM myVeryBaseImage ENV WEBAPP_CONTEXT=my-app WORKDIR /opt/${WEBAPP_CONTEXT} COPY app/*.jar ./${WEBAPP_CONTEXT}.jar COPY baseconfig/* ./config/${WEBAPP_CONTEXT}/ CMD java -jar ${WEBAPP_CONTEXT}.jar --Dspring.profiles.active=docker 

这个基础图像是由另一个团队提供的,很难改变它。 我现在正在编写一堆容器,我想要多次运行相同的应用程序,但使用不同的configuration。

所以我想我会延长图像复制一些更多的configuration到它并运行一个不同的弹簧configuration文件:

 FROM baseImage COPY config/application-*.properties ./config/${WEBAPP_CONTEXT}/ CMD java -jar ${WEBAPP_CONTEXT}.jar -Dspring.profiles.active=${PROFILE} 

在docker-compose.yml中:

 myapp-foo: build: ./myapp-custom image: myapp-custom environment: PROFILE: foo volumes: - /opt/my-app/foo:/opt/my-app myapp-bar: image: myapp-custom environment: PROFILE: bar volumes: - /opt/my-app/bar:/opt/my-app 

我希望有两个容器运行,分别使用application-foo.propertiesapplication-bar.properties

看起来,虽然,都使用appplication-docker.properties,即在基础Dockerfile中定义的dockerconfiguration文件。

如果我完全改变派生的Dockerfile中的CMD,它将起作用:

 CMD echo "${PROFILE}" 

输出分别是“foo”和“bar”。 任何提示可能会发生什么?

我的版本是:

 docker-compose version 1.8.1, build 878cff1 Docker version 1.12.3, build 6b644ec 

更新:
在@ blackibiza的build议之后,我将派生的Dockerfile更改为

 FROM baseImage COPY config/application-*.properties ./config/${WEBAPP_CONTEXT}/ ENTRYPOINT /opt/jdk1.8.0_102/bin/java CMD ["-jar", "${WEBAPP_CONTEXT}.jar", "-Dspring.profiles.active=foo"] 

没有docker-compose的东西,只是为了看看派生的图像是怎么样的。 我从java获得错误消息,试图运行容器。 检查图像给出以下内容:

 $ docker inspect --format='{{.Config.Cmd}} {{.Config.Entrypoint}}' testapp [-jar ${WEBAPP_CONTEXT}.jar -Dspring.profiles.active=french] [/bin/sh -c /opt/jdk1.8.0_102/bin/java] 

所以它仍然试图执行/bin/sh而不是java。 这看起来不像我从文档中预期的那样。

Update2:使用CMD的JSON数组语法触发另一个问题:

 FROM baseImage COPY config/application-*.properties ./config/${WEBAPP_CONTEXT}/ CMD ["java", "-jar", "${WEBAPP_CONTEXT}.jar", "-Dspring.profiles.active=foo"] 

不会扩展${WEBAPP_CONTEXT}的使用,从而导致错误

 Error: Unable to access jarfile ${WEBAPP_CONTEXT}.jar 

你正在寻找的是入口点的覆盖。 如Docker参考中所述 ,

如果你想在没有shell的情况下运行你的程序,那么你必须把这个命令作为一个JSON数组来表示,并给出可执行文件的完整path。 这个数组forms是CMD的首选格式。 任何附加参数都必须在数组中分别表示为string:

Ubuntu的

CMD [“/ usr / bin / wc”,“ – help”]

如果您希望您的容器每次都运行相同的可执行文件,则应考虑将入口点与CMD结合使用。 见进入点。

而使用Composer,你可以重写CMD参数,如下所述 :

 db: command: '-d' ports: - 5432:5432 

你应该定义一个入口点,这是你的情况:

 ENTRYPOINT java CMD ["-jar", "${WEBAPP_CONTEXT}.jar"] 

在你的具体情况下,我会主张将shell作为入口点,并用脚本覆盖CMD,如:

 ENTRYPOINT /bin/sh CMD ["./script.sh"] 

并在您撰写的YML:

 command: './script2.sh' 

更新(根据更改的问题):

它缺less的是variables的定义。 在这种情况下,我build议使用ARG而不是ENV来构build传入永久值的容器:

 docker build -t your_image:your_version --build-arg WEBAPP_CONTEXT=your_context . 

在构build时获得价值替代。 ARG的优点是可以inheritance您的孩子的形象

不要复制和粘贴错误的Java命令。 如果它位于.jar文件之后,则不会识别-Dspring.profile.active参数。

修复CMD线

 CMD java -jar -Dspring.profiles.active=${PROFILE} ${WEBAPP_CONTEXT}.jar 

一切都很好。

另请参见“ 在spring引导中从命令行设置活动configuration文件和configuration位置 ”