本次实战的环境以下:java
上一篇的例子中,咱们用到了eureka和service两个容器,eureka是注册中心,service是普通业务应用,service容器向eureka容器注册时,eureka尚未初始化完成,所以service注册失败,在稍后的自动重试时因为eureka进入ready状态,于是service注册成功。 今天咱们来改造上一篇的例子,让service用上docker官方推荐的<font color="blue">wait-for-it.sh</font>脚本,等待eureka服务就绪再启动java进程,确保service能够一次性注册eureka成功; 为了达到上述目标,总共须要作如下几步:python
接下来进入实战环节;linux
若是您不想编码,也能够在GitHub上获取文中全部源码和脚本,地址和连接信息以下表所示: | 名称 | 连接 | 备注| | :-------- | :----| :----| | 项目主页| https://github.com/zq2599/blog_demos | 该项目在GitHub上的主页 | | git仓库地址(https)| https://github.com/zq2599/blog_demos.git | 该项目源码的仓库地址,https协议 | | git仓库地址(ssh)| git@github.com:zq2599/blog_demos.git | 该项目源码的仓库地址,ssh协议 | </br>git
这个git项目中有多个文件夹,本章的应用在<font color="blue">wait-for-it-demo</font>文件夹下,以下图红框所示: 源码的结构以下图所示:
接下来开始编码了;程序员
上一篇和本篇,咱们都在用eureka和service这两个容器作实验,如今就来看看他们是怎么作出来的:github
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.bolingcavalry</groupId> <artifactId>eureka</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>eureka</name> <description>eureka</description> <parent> <groupId>com.bolingcavalry</groupId> <artifactId>wait-for-it-demo</artifactId> <version>0.0.1-SNAPSHOT</version> <relativePath>../pom.xml</relativePath> <!-- lookup parent from repository --> </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> <!--使用jib插件--> <plugin> <groupId>com.google.cloud.tools</groupId> <artifactId>jib-maven-plugin</artifactId> <version>1.7.0</version> <configuration> <!--from节点用来设置镜像的基础镜像,至关于Docerkfile中的FROM关键字--> <from> <!--使用openjdk官方镜像,tag是8-jdk-stretch,表示镜像的操做系统是debian9,装好了jdk8--> <image>openjdk:8-jdk-stretch</image> </from> <to> <!--镜像名称和tag,使用了mvn内置变量${project.version},表示当前工程的version--> <image>bolingcavalry/${project.artifactId}:${project.version}</image> </to> <!--容器相关的属性--> <container> <!--jvm内存参数--> <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插件,这样在执行<font color="blue">mvn compile</font>的时候,插件就会用构建结果制做好docker镜像并放入本地仓库; 2. service是个普通的SpringCloud应用,除了在pom.xml中也用到了jib插件来构建镜像,它的配置文件中,访问eureka的地址要写成eureka容器的名称:spring
spring: application: name: service eureka: client: serviceUrl: defaultZone: http://eureka:8080/eureka/
从上面的pom.xml可见,咱们将Java应用制做成docker镜像时,使用的基础镜像是<font color="blue">openjdk:8-jdk-stretch</font>,这样作出的应用镜像是不含wait-for-it.sh脚本的,天然就没法实现启动顺序控制了,所以咱们要作一个带有wait-for-it.sh的基础镜像给业务镜像用:docker
FROM openjdk:8-jdk-stretch ADD wait-for-it.sh /wait-for-it.sh RUN sh -c 'chmod 777 /wait-for-it.sh'
<font color="red">注意:</font>我这里用的是openjdk:8-jdk-stretch,您能够根据本身的实际须要选择不一样的openjdk版本,能够参考:《openjdk镜像的tag说明》 3. 执行命令<font color="blue">docker build -t bolingcavalry/jkd8-wait-for-it:0.0.2 .</font>就能构建出名为<font color="red">bolingcavalry/jkd8-wait-for-it:0.0.2</font>的镜像了,请您根据本身的状况设置镜像名称和tag,注意命令的末尾有个小数点,不要漏了; 4. 若是您有hub.docker.com帐号,建请使用<font color="blue">docker push</font>命令将新建的镜像推送到镜像仓库上去,或者推送到私有仓库,由于后面使用jib插件构建镜像是,jib插件要去仓库获取基础镜像的元数据信息,取不到会致使构建失败;shell
咱们的目标是让service服务等待eureka服务就绪,因此应该改造service服务,让它用docker官方推荐的<font color="blue">wait-for-it.sh</font>方案来实现等待:apache
<plugin> <groupId>com.google.cloud.tools</groupId> <artifactId>jib-maven-plugin</artifactId> <version>1.7.0</version> <configuration> <!--from节点用来设置镜像的基础镜像,至关于Docerkfile中的FROM关键字--> <from> <!--使用自制的基础镜像,里面有wait-for-it.sh脚本--> <image>bolingcavalry/jkd8-wait-for-it:0.0.2</image> </from> <to> <!--镜像名称和tag,使用了mvn内置变量${project.version},表示当前工程的version--> <image>bolingcavalry/${project.artifactId}:${project.version}</image> </to> <!--容器相关的属性--> <container> <!--entrypoint的值等于INHERIT表示jib插件不构建启动命令了,此时要使用者本身控制,能够在启动时输入,或者写在基础镜像中--> <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. 基础镜像改成刚刚构建好的<font color="blue">bolingcavalry/jkd8-wait-for-it:0.0.2</font> b. 增长<font color="blue">entrypoint</font>节点,内容是<font color="red">INHERIT</font>,按照官方的说法,entrypoint的值等于INHERIT表示jib插件不构建启动命令了,此时要使用者本身控制,能够在启动时输入,或者写在基础镜像中,这样咱们在docker-compose.yml中用command参数来设置service容器的启动命令,就能够把<font color="blue">wait-for-it.sh</font>脚本用上了 c. 去掉<font color="blue">jvmFlags</font>节点,按照官方文档的说法,entrypoint节点的值等于INHERIT时,jvmFlags和mainClass参数会被忽略,以下图,地址是:https://github.com/GoogleContainerTools/jib/tree/master/jib-maven-plugin 至此,service工程改造完毕,接下来修改docker-compose.yml,让service容器能用上wait-for-it.sh
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
sh -c './wait-for-it.sh eureka:8080 -t 0 -- java -Xms1g -Xmx1g -cp /app/resources:/app/classes:/app/libs/* com.bolingcavalry.waitforitdemo.ServiceApplication'
全部的改造工做都完成了,能够开始验证了;
使用docker官方推荐的<font color="blue">wait-for-it.sh</font>来控制容器启动顺序,虽然已知足了咱们的需求,但依旧留不是完美方案,留下的缺陷仍是请您先知晓吧,也许这个缺陷会对您的系统产生严重的负面影响:
[root@maven ~]# docker exec eureka ps -ef UID PID PPID C STIME TTY TIME CMD root 1 0 2 07:04 ? 00:00:48 java -Xms1g -Xmx1g -cp /app/resources:/app/classes:/app/libs/* com.bolingcavalry.waitforitdemo.EurekaApplication root 56 0 0 07:25 ? 00:00:00 /bin/bash root 63 0 0 07:31 ? 00:00:00 ps -ef
[root@maven ~]# docker exec service ps -ef UID PID PPID C STIME TTY TIME CMD root 1 0 0 07:04 ? 00:00:00 sh -c ./wait-for-it.sh eureka:8080 -t 0 -- java -Xms1g -Xmx1g -cp /app/resources:/app/classes:/app/libs/* com.bolingcavalry.waitforitdemo.ServiceApplication root 7 1 1 07:04 ? 00:00:32 java -Xms1g -Xmx1g -cp /app/resources:/app/classes:/app/libs/* com.bolingcavalry.waitforitdemo.ServiceApplication root 107 0 0 07:33 ? 00:00:00 ps -ef