链接Docker图像并按顺序执行

我正在用自己的图像扩展APIMan / Wildfly Docker镜像,这将会做两件事情:

1)将我的.war文件应用程序放到Wildfly standalone / deployments目录中

2)执行一系列将查询Wildfly服务器的cURL命令来configurationAPIMan。

最初,我尝试创build两个Docker镜像(第一个放在.war文件中,第二个放在cURL命令中),但是我错误地认为最内层的CMD指令会先执行,CMD会向外执行。

例如:

ImageA: FROM jboss/apiman-wildfly:1.1.6.Final RUN /opt/jboss/wildfly/bin/add-user.sh admin admin --silent COPY /RatedRestfulServer/target/RatedRestfulServer-1.0-SNAPSHOT.war /opt/jboss/wildfly/standalone/deployments/ CMD ["/opt/jboss/wildfly/bin/standalone.sh", "-b", "0.0.0.0", "-bmanagement", "0.0.0.0", "-c", "standalone-apiman.xml"] 

 ImageB: FROM ImageA COPY /configure.sh /opt/jboss/wildfly/ CMD ["/opt/jboss/wildfly/configure.sh"] 

我最初假设在运行时Wildfly / APIMAN将首先启动(根据ImageA CMD指令),然后运行我的自定义脚本(根据ImageB CMD指令)。 我假设这是不正确的,因为在整个层次结构中,只执行1个CMD指令(链中最外面的Dockerfile中的最后一个)?

于是,我试图将所有东西都合并到一个Dockerfile中(在构build过程中)启动Wildfly / APIMAN,运行cURL命令,closureswildfly服务器,然后CMD命令在运行时启动备份,Wildfly / APIMan进行configuration。 但是,这不起作用,因为当我启动Wildfly(作为构build的一部分)时,它控制着控制台并等待显示日志消息,因此构build从不完成。 如果我在RUN命令的末尾附加一个'&',它不会运行( Dockerfile:RUN会导致一个No op )。

这是我的Dockerfile这个尝试:

 FROM jboss/apiman-wildfly:1.1.6.Final RUN /opt/jboss/wildfly/bin/add-user.sh admin admin --silent COPY /RatedRestfulServer/target/RatedRestfulServer-1.0-SNAPSHOT.war /opt/jboss/wildfly/standalone/deployments/ COPY /configure.sh /opt/jboss/wildfly/ RUN /opt/jboss/wildfly/bin/standalone.sh -b 0.0.0.0 -bmanagement 0.0.0.0 -c standalone-apiman.xml RUN /opt/jboss/wildfly/configure.sh RUN /opt/jboss/wildfly/bin/jboss-cli.sh --connect controller=127.0.0.1 command=:shutdown CMD ["/opt/jboss/wildfly/bin/standalone.sh", "-b", "0.0.0.0", "-bmanagement", "0.0.0.0", "-c", "standalone-apiman.xml"] 

有没有解决办法? 我试图让我的“configure.sh”脚本运行后,Wildfly / APIMan启动。 在构build过程中还是在运行过程中,这并不重要,但是在构build过程中我看不到任何方法,因为Wildfly没有守护进程模式。

只执行1个CMD指令(链中最外面的Dockerfile中的最后一个)?

是的,这是正确的,请记住,CMD不是在构build时运行,而是在实例化时运行。 实质上,你在第二个Dockerfile的CMD所做的是在你从ImageB实例化容器时重写第一个

如果您正在做某种Rest API或cli或cURL来连接到您的Wildfly服务器,我build议您在容器的实例化之后进行configuration,而不是在容器的构build之后。 这条路:

 CMD ["/opt/jboss/wildfly/bin/standalone.sh", "-b", "0.0.0.0", "-bmanagement", "0.0.0.0", "-c", "standalone-apiman.xml"]` 

永远是你最后的命令。 如果您需要一些额外的文件或对configuration文件的更改,可以将它们放入Dockerfile以便在实例化CMD之前在构build时复制它们。

总之:

1)用这个DockerfileDockerfile build)构build你的Docker容器:

 FROM jboss/apiman-wildfly:1.1.6.Final RUN /opt/jboss/wildfly/bin/add-user.sh admin admin --silent COPY /RatedRestfulServer/target/RatedRestfulServer-1.0-SNAPSHOT.war /opt/jboss/wildfly/standalone/deployments/ COPY /configure.sh /opt/jboss/wildfly/ CMD ["/opt/jboss/wildfly/bin/standalone.sh", "-b", "0.0.0.0", "-bmanagement", "0.0.0.0", "-c", "standalone-apiman.xml"] 

2)运行(从新创build的图像实例化你的容器)

 docker run <image-id> 

3)从一个容器中运行以下代码,或者从拥有Wildfly的主机上以相同的方式configuration。 这假设你正在使用一些Rest API来configuration东西(即使用cURL):

 /opt/jboss/wildfly/configure.sh 

你可以实例化第二个容器来运行这个命令,如下所示:

 docker run -ti <image-id> /bin/bash 

build立一个图像:

 FROM jboss/apiman-wildfly:1.1.6.Final RUN /opt/jboss/wildfly/bin/add-user.sh admin admin --silent COPY /RatedRestfulServer/target/RatedRestfulServer-1.0-SNAPSHOT.war /opt/jboss/wildfly/standalone/deployments/ COPY /configure.sh /opt/jboss/wildfly/ CMD ["/opt/jboss/wildfly/bin/standalone.sh", "-b", "0.0.0.0", "-bmanagement", "0.0.0.0", "-c", "standalone-apiman.xml"] 

启动它。 启动完成后,使用docker exec命令在正在运行的容器中启动您的configuration脚本。

 docker run -d --name wildfly <image name> docker exec wildfly /opt/jboss/wildfly/configure.sh 

我的问题背后的原始前提(尽pipe在原始文章中没有明确说明)是在图像中configurationAPIMan,并且在图像之外没有任何干预。

这是一个黑客,但我能够通过创build3个脚本来解决这个问题。 一个用于启动Wildfly,一个用于运行configuration脚本,另一个用于执行它们。 希望这可以帮助一些其他的可怜的灵魂花费一天的时间来研究这一切。

由于Dockerfile的性质只允许在运行时执行一次调用,所以这个调用需要是一个自定义脚本。

以下是有评论的文件。

Dockerfile

 FROM jboss/apiman-wildfly:1.1.6.Final RUN /opt/jboss/wildfly/bin/add-user.sh admin admin --silent COPY /RatedRestfulServer/target/RatedRestfulServer-1.0-SNAPSHOT.war /opt/jboss/wildfly/standalone/deployments/ COPY /configure.sh /opt/jboss/wildfly/ COPY /execute.sh /opt/jboss/wildfly/ COPY /runWF.sh /opt/jboss/wildfly/ CMD ["/opt/jboss/wildfly/execute.sh"] 

请注意,所有3个脚本都内置在图像中。 execute.sh脚本在运行时(实例化)而不是构build时执行。

execute.sh

 #!/bin/sh /opt/jboss/wildfly/configure.sh & /opt/jboss/wildfly/runWF.sh 

请注意,configure.sh脚本被发送到后台,以便我们可以在configure.sh仍在运行时转到runWF.sh脚本)

configure.sh

 #!/bin/sh done="" while [ "$done" != "200" ] do done=$(curl --write-out %{http_code} --silent --output /dev/null -u username:password -X GET -H "Accept: application/json" http://127.0.0.1:8080/apiman/system/status) sleep 3 done # configuration curl commands curl ... curl ... 

上面的configure.sh脚本运行在循环查询wildfly / apiman服务器每隔3秒curl检查其状态。 一旦获得了200的HTTP状态码(代表“正在运行”状态),它就退出循环并自由移动到configuration中。 注意,通过提供另一种退出循环的方法(例如,在一定数量的查询之后等等),这可能应该变得更“安全”一些。 我想这会给生产开发者带来心悸,我不会build议将其部署在生产环境中,但是它现在还是可行的。

runWF.sh

 #!/bin/sh /opt/jboss/wildfly/bin/standalone.sh -b 0.0.0.0 -bmanagement 0.0.0.0 -c standalone-apiman.xml 

这个脚本只是启动服务器。 这些参数将各种模块绑定到0.0.0.0,并指示wildfly使用apiman独立xml文件进行configuration。

在我的机器上,它需要大约10-15秒(取决于运行在哪台计算机上)的wildfly + apiman(用我的自定义war文件)来完全加载,但是一旦完成,configuration脚本将能够成功查询它然后继续使用configurationcurl命令。 同时,wildfly仍然控制着控制台,因为它最后启动了,你可以监视活动并用ctrl-c终止进程。