docker-compose 下的 java 应用启动顺序两部曲之二:实战
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.RELEASE</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
<version>1.7.0</version>
<configuration>
<from>
<image>openjdk:8-jdk-stretch</image>
</from>
<to>
<image>bolingcavalry/{project.version}</image>
</to>
<container>
<jvmFlags>
<jvmFlag>-Xms1g</jvmFlag>
<jvmFlag>-Xmx1g</jvmFlag>
</jvmFlags>
<ports>
<port>8080</port>
</ports>
<useCurrentTimestamp>true</useCurrentTimestamp>
</container>
</configuration>
<executions>
<execution>
<phase>compile</phase>
<goals>
<goal>dockerBuild</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
上述 pom.xml 中多了个 jib 插件,这样在执行 mvn compile 的时候,插件就会用构建结果制作好 docker 镜像并放入本地仓库;
2. service 是个普通的 SpringCloud 应用,除了在 pom.xml 中也用到了 jib 插件来构建镜像,它的配置文件中,访问 eureka 的地址要写成 eureka 容器的名称:
spring:
application:
name: service
eureka:
client:
serviceUrl:
defaultZone: http://eureka:8080/eureka/
关于如何将 java 应用制作成 docker 镜像,如果您想了解更多请参考以下两篇文章:
制作基础镜像
从上面的 pom.xml 可见,我们将 Java 应用制作成 docker 镜像时,使用的基础镜像是 openjdk:8-jdk-stretch,这样做出的应用镜像是不含 wait-for-it.sh 脚本的,自然就无法实现启动顺序控制了,因此我们要做一个带有 wait-for-it.sh 的基础镜像给业务镜像用:
把 wait-for-it.sh 文件准备好,下载地址:https://raw.githubusercontent.com/zq2599/blog_demos/master/wait-for-it-demo/docker/wait-for-it.sh
在 wait-for-it.sh 文件所在目录新建 Dockerfile 文件,内容如下:
FROM openjdk:8-jdk-stretch
ADD wait-for-it.sh /wait-for-it.sh
RUN sh -c 'chmod 777 /wait-for-it.sh'
注意:我这里用的是 openjdk:8-jdk-stretch,您可以根据自己的实际需要选择不同的 openjdk 版本,可以参考:《openjdk镜像的tag说明》
执行命令 docker build -t bolingcavalry/jkd8-wait-for-it:0.0.2 .就能构建出名为 bolingcavalry/jkd8-wait-for-it:0.0.2 的镜像了,请您根据自己的情况设置镜像名称和 tag,注意命令的末尾有个小数点,不要漏了;
如果您有 hub.docker.com 账号,建请使用 docker push 命令将新建的镜像推送到镜像仓库上去,或者推送到私有仓库,因为后面使用 jib 插件构建镜像是,jib 插件要去仓库获取基础镜像的元数据信息,取不到会导致构建失败;
使用新的基础镜像构建 service 镜像
我们的目标是让 service 服务等待 eureka 服务就绪,所以应该改造 service 服务,让它用 docker 官方推荐的 wait-for-it.sh 方案来实现等待:
修改 service 工程的 pom.xml,有关 jib 插件的配置改为以下内容:
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
<version>1.7.0</version>
<configuration>
<from>
<image>bolingcavalry/jkd8-wait-for-it:0.0.2</image>
</from>
<to>
<image>bolingcavalry/{project.version}</image>
</to>
<container>
<entrypoint>INHERIT</entrypoint>
<ports>
<port>8080</port>
</ports>
<useCurrentTimestamp>true</useCurrentTimestamp>
</container>
</configuration>
<executions>
<execution>
<phase>compile</phase>
<goals>
<goal>dockerBuild</goal>
</goals>
</execution>
</executions>
</plugin>
上述配置有几点需要注意:
a. 基础镜像改为刚刚构建好的 bolingcavalry/jkd8-wait-for-it:0.0.2
b. 增加 entrypoint 节点,内容是 INHERIT,按照官方的说法,entrypoint 的值等于 INHERIT 表示 jib 插件不构建启动命令了,此时要使用者自己控制,可以在启动时输入,或者写在基础镜像中,这样我们在 docker-compose.yml 中用 command 参数来设置 service 容器的启动命令,就可以把 wait-for-it.sh 脚本用上了
c. 去掉 jvmFlags 节点,按照官方文档的说法,entrypoint 节点的值等于 INHERIT 时,jvmFlags 和 mainClass 参数会被忽略,如下图,地址是:https://github.com/GoogleContainerTools/jib/tree/master/jib-maven-plugin
至此,service 工程改造完毕,接下来修改 docker-compose.yml,让 service 容器能用上 wait-for-it.sh
改造 docker-comp
ose.yml
完整的 docker-compose.yml 内容如下所示:
version: '3'
services:
eureka:
image: bolingcavalry/eureka:0.0.1-SNAPSHOT
container_name: eureka
restart: unless-stopped
service:
image: bolingcavalry/service:0.0.1-SNAPSHOT
container_name: service
restart: unless-stopped
command: sh -c './wait-for-it.sh eureka:8080 -t 0 -- java -Xms1g -Xmx1g -cp /app/resources:/app/classes:/app/libs/* com.bolingcavalry.waitforitdemo.ServiceApplication'
depends_on:
eureka
注意 command 参数的内容,如下,service 容器创建后,会一直等待 eureka:8080 的响应,直到该地址有响应后,才会执行命令 java -Xms1g -Xmx1g -cp /app/resources:/app/classes:/app/libs/* com.bolingcavalry.waitforitdemo.ServiceApplication:
sh -c './wait-for-it.sh eureka:8080 -t 0 -- java -Xms1g -Xmx1g -cp /app/resources:/app/classes:/app/libs/* com.bolingcavalry.waitforitdemo.ServiceApplication'
对于命令 java -Xms1g -Xmx1g -cp /app/resources:/app/classes:/app/libs/* com.bolingcavalry.waitforitdemo.ServiceApplication,您可能觉得太长了不好写,这里有个小窍门,就是在不使用 entrypoint 节点的时候,用 jib 插件制作的镜像本身是带有启动命令的,容器运行的时候,您可以通过 docker ps --no-trunc 命令看到该容器的完整启动命令,复制过来直接用就行了;
所有的改造工作都完成了,可以开始验证了;
评论