本次實戰的環境以下: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