在《極速體驗docker容器健康》一文已體驗了docker容器健康檢查功能,今天就來給java應用的容器加入健康檢查,使應用的狀態隨時均可以被監控和查看。java
今天實戰的java應用,是用來模擬生產環境應用的,特色以下:git
若是您不想寫代碼,上述springboot應用的源碼可在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項目中有多個文件夾,本章的應用在<font color="blue">springboot-app-docker-health-check</font>文件夾下,以下圖紅框所示: github
應用接入容器健康檢查的步驟以下:web
# Docker file from bolingcavalry # VERSION 0.0.1 # Author: bolingcavalry #基礎鏡像 FROM openjdk:8-jdk-stretch #做者 MAINTAINER BolingCavalry <zq2599@gmail.com> #健康檢查參數設置,每5秒檢查一次,接口超時時間2秒,連續10次返回1就斷定該容器不健康 HEALTHCHECK --interval=5s --timeout=2s --retries=10 \ CMD curl --silent --fail localhost:8080/getstate || exit 1
由上述可見Dockerfile的內容很是簡單,選定自身的基礎鏡像爲<font color="blue">openjdk:8-jdk-stretch</font>,再配置好健康檢查參數: | 參數名 | 做用 | |--|--| | health-cmd | 指定命令在容器內執行,用於檢查容器健康狀態 | | health-interval | 每次健康檢查的間隔時間,默認30秒 | | health-retries | 假設該值爲3,表示若連續三次檢測的返回結果都是不健康,就斷定該容器不健康,默認值爲3 | | health-timeout | 超時時間,默認30秒 | 2. 在Dockerfile文件所在目錄執行命令<font color="blue">docker build -t bolingcavalry/jdk8-healthcheck:0.0.1 .</font>(最後那個點號不要漏掉),控制檯輸出以下,提示鏡像構建成功:spring
(base) zhaoqindeMacBook-Pro:springboot-app-docker-health-check zhaoqin$ docker build -t bolingcavalry/jdk8-healthcheck:0.0.1 . Sending build context to Docker daemon 217.6kB Step 1/3 : FROM openjdk:8-jdk-stretch 8-jdk-stretch: Pulling from library/openjdk 9a0b0ce99936: Already exists db3b6004c61a: Already exists f8f075920295: Already exists 6ef14aff1139: Already exists 962785d3b7f9: Already exists 631589572f9b: Already exists c55a0c6f4c7b: Already exists Digest: sha256:8bce852e5ccd41b17bf9704c0047f962f891bdde3e401678a52d14a628defa49 Status: Downloaded newer image for openjdk:8-jdk-stretch ---> 57c2c2d2643d Step 2/3 : MAINTAINER BolingCavalry <zq2599@gmail.com> ---> Running in 270f78efa617 Removing intermediate container 270f78efa617 ---> 01b5df83611d Step 3/3 : HEALTHCHECK --interval=5s --timeout=2s --retries=10 CMD curl --silent --fail localhost:8080/getstate || exit 1 ---> Running in 7cdd08b9ca22 Removing intermediate container 7cdd08b9ca22 ---> 9dd7ffb22df4 Successfully built 9dd7ffb22df4 Successfully tagged bolingcavalry/jdk8-healthcheck:0.0.1
docker push bolingcavalry/jdk8-healthcheck:0.0.1
本次實戰的目標是讓Java應用支持docker的容器健康檢查功能,接下來一塊兒建立這個Java應用:docker
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.0.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.bolingcavalry</groupId> <artifactId>springboot-app-docker-health-check</artifactId> <version>0.0.1-SNAPSHOT</version> <name>springboot-app-docker-health-check</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.5</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </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> <!--基礎鏡像是bolingcavalry/jdk8-healthcheck:0.0.1,該鏡像已配置了健康檢查參數--> <image>bolingcavalry/jdk8-healthcheck:0.0.1</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> </plugin> </plugins> </build> </project>
上述pom.xml有如下幾處須要注意: a. 使用jib插件來將當前工程構建成docker鏡像; b. 基礎鏡像是前面構建的<font color="blue">bolingcavalry/jdk8-healthcheck:0.0.1</font>,以此爲基礎鏡像的鏡像都帶有健康檢查功能;shell
package com.bolingcavalry.springbootappdockerhealthcheck; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.http.ResponseEntity; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import java.io.*; import java.util.List; @SpringBootApplication @RestController @Slf4j public class SpringbootAppDockerHealthCheckApplication { public static void main(String[] args) { SpringApplication.run(SpringbootAppDockerHealthCheckApplication.class, args); } /** * 讀取本地文本文件的內容並返回 * @return */ private String getLocalFileContent() { String content = null; try{ InputStream is = new FileInputStream("/app/depend/abc.txt"); List<String> lines = IOUtils.readLines(is, "UTF-8"); if(null!=lines && lines.size()>0){ content = lines.get(0); } } catch (FileNotFoundException e) { log.error("local file not found", e); } catch (IOException e) { log.error("io exception", e); } return content; } /** * 對外提供的http服務,讀取本地的txt文件將內容返回, * 若是讀取不到內容返回碼爲403 * @return */ @RequestMapping(value = "/hello", method = RequestMethod.GET) public ResponseEntity<String> hello(){ String localFileContent = getLocalFileContent(); if(StringUtils.isEmpty(localFileContent)) { log.error("hello service error"); return ResponseEntity.status(403).build(); } else { log.info("hello service success"); return ResponseEntity.status(200).body(localFileContent); } } /** * 該http服務返回當前應用是否正常, * 若是能從本地txt文件成功讀取內容,當前應用就算正常,返回碼爲200, * 若是沒法從本地txt文件成功讀取內容,當前應用就算異常,返回碼爲403 * @return */ @RequestMapping(value = "/getstate", method = RequestMethod.GET) public ResponseEntity<String> getstate(){ String localFileContent = getLocalFileContent(); if(StringUtils.isEmpty(localFileContent)) { log.error("service is unhealthy"); return ResponseEntity.status(403).build(); } else { log.info("service is healthy"); return ResponseEntity.status(200).build(); } } }
上述代碼有如下幾處須要注意: a. <font color="blue">hello</font>方法是此應用對外提供的服務,若是本地文件abc.txt存在且內容不爲空,hello方法的返回碼就是200,不然返回碼爲403,表示當前服務出現異常; b. <font color="blue">getstate</font>方法是新增的服務,該接口會被docke-daemon調用,若是返回碼是200,就表示容器健康,若是返回碼是403,表示容器不健康; 3. 在pom.xml文件所在目錄執行<font color="blue">mvn clean compile -U -DskipTests jib:dockerBuild</font>,便可將當前工程構建爲鏡像,名爲<font color="blue">bolingcavalry/springboot-app-docker-health-check:0.0.1-SNAPSHOT</font> 4. 至此,支持容器健康檢查的Java應用鏡像構建成功,接下來驗證容器的健康檢查功能是否正常;apache
驗證的步驟以下: a. 讓應用容器正常工做,確保文件<font color="blue">/app/depend/abc.txt</font>是正常的,此時容器狀態應該是<font color="red">healthy</font> b. 將文件<font color="blue">/app/depend/abc.txt</font>刪除,此時應用hello接口返回碼爲403,而且容器狀態變爲<font color="red">unhealthy</font>springboot
docker run --rm \ --name=java-health-check \ -p 8080:8080 \ -v /Users/zhaoqin/temp/201910/20:/app/depend \ bolingcavalry/springboot-app-docker-health-check:0.0.1-SNAPSHOT
2019-10-20 14:16:34.875 INFO 1 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet' 2019-10-20 14:16:34.876 INFO 1 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet' 2019-10-20 14:16:34.892 INFO 1 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 16 ms 2019-10-20 14:16:34.959 INFO 1 --- [nio-8080-exec-1] pringbootAppDockerHealthCheckApplication : service is healthy 2019-10-20 14:16:40.159 INFO 1 --- [nio-8080-exec-2] pringbootAppDockerHealthCheckApplication : service is healthy 2019-10-20 14:16:45.356 INFO 1 --- [nio-8080-exec-4] pringbootAppDockerHealthCheckApplication : service is healthy 2019-10-20 14:16:50.580 INFO 1 --- [nio-8080-exec-6] pringbootAppDockerHealthCheckApplication : service is healthy
(base) zhaoqindeMBP:20 zhaoqin$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 51572d2488fb bolingcavalry/springboot-app-docker-health-check:0.0.1-SNAPSHOT "java -Xms1g -Xmx1g …" About a minute ago Up About a minute (healthy) 0.0.0.0:8080->8080/tcp java-health-check
019-10-20 14:22:37.490 ERROR 1 --- [nio-8080-exec-7] pringbootAppDockerHealthCheckApplication : service is unhealthy
(base) zhaoqindeMBP:20 zhaoqin$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 51572d2488fb bolingcavalry/springboot-app-docker-health-check:0.0.1-SNAPSHOT "java -Xms1g -Xmx1g …" 7 minutes ago Up 7 minutes (unhealthy) 0.0.0.0:8080->8080/tcp java-health-check
至此,Java應用在docker環境配置容器健康檢查的實戰就完成了,但願您在給本身的應用添加健康檢查時,此文能給您一些參考。