本文是《spring-cloud-kubernetes實戰系列》的第四篇,主要內容是在kubernetes上部署兩個應用:Web-Service和Account-Service,經過spring-cloud-kubernetes提供的註冊發現能力,實現Web-Service調用Account-Service提供的http服務;java
本文由如下段落組成:linux
本次實戰的環境和版本信息以下:git
上面的linux、minikube、java、maven,請確保已準備好,linux環境下minikube的安裝和啓動請參考《Linux安裝minikube指南 》。程序員
SpringCloud環境最重要的功能是註冊發現服務,所以將SpringCloud應用遷移到kubernetes環境時,開發者最關心的問題是在kubernetes上如何將自身服務暴露出去,以及如何調用其餘微服務。github
先看看普通SpringCloud環境下的註冊發現,下圖來自spring官方博客,地址是:https://spring.io/blog/2015/07/14/microservices-with-spring,
web
由上圖可見,應用Account-Service將本身註冊到Eureka,這樣Web-Service用"account-service"就能在Eureka找到Account-Service服務的地址,而後順利發送RestFul請求到Account-Service,用上其提供的服務。spring
若是將上面的Web-Service和Account-Service兩個應用遷移到kubernetes上以後,註冊發現機制變成了啥樣呢?
第一種:沿用上圖的方式,將Eureka也部署在kubernetes上,這樣的架構和不用kubernetes時沒有啥區別;
第二種,就是今天要實戰的內容,使用spring-cloud-kubernetes框架,該框架能夠調用kubernetes的原生能力來爲現有SpringCloud應用提供服務,架構以下圖所示:
上圖代表,Web-Service應用在調用Account-Service應用的服務時,會用okhttp向API Server請求服務列表,API Server收到請求後會去etcd取數據返回給Web-Service應用,這樣Web-Service就有了Account-Service的信息,能夠向Account-Service的多個Pod輪詢發起請求;shell
上圖有個細節請注意:WebService應用並非直接將請求發送給Account-Service在kubernetes建立的service,而是直接發送到具體的Pod上了,之因此具備這個能力,是由於spring-cloud-kubernetes框架經過service拿到了Account-Service對應的全部Pod信息(endpoint),此邏輯能夠參考源碼KubernetesServerList.java,以下所示:apache
public List<Server> getUpdatedListOfServers() { //用namespace和serviceId作條件,獲得該服務對應的全部節點(endpoints)信息 Endpoints endpoints = this.namespace != null ? this.client.endpoints().inNamespace(this.namespace) .withName(this.serviceId).get() : this.client.endpoints().withName(this.serviceId).get(); List<Server> result = new ArrayList<Server>(); if (endpoints != null) { if (LOG.isDebugEnabled()) { LOG.debug("Found [" + endpoints.getSubsets().size() + "] endpoints in namespace [" + this.namespace + "] for name [" + this.serviceId + "] and portName [" + this.portName + "]"); } //遍歷全部的endpoint,取出IP地址和端口,構建成Server實例,放入result集合中 for (EndpointSubset subset : endpoints.getSubsets()) { if (subset.getPorts().size() == 1) { EndpointPort port = subset.getPorts().get(FIRST); for (EndpointAddress address : subset.getAddresses()) { result.add(new Server(address.getIp(), port.getPort())); } } else { for (EndpointPort port : subset.getPorts()) { if (Utils.isNullOrEmpty(this.portName) || this.portName.endsWith(port.getName())) { for (EndpointAddress address : subset.getAddresses()) { result.add(new Server(address.getIp(), port.getPort())); } } } } } } else { LOG.warn("Did not find any endpoints in ribbon in namespace [" + this.namespace + "] for name [" + this.serviceId + "] and portName [" + this.portName + "]"); } return result; }
理論分析已經完成,接下來就開始實戰吧json
若是您不打算寫代碼,也能夠從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協議 |
這個git項目中有多個文件夾,本章的Account-Service源碼在spring-cloud-k8s-account-service文件夾下,Web-Service源碼在spring-cloud-k8s-web-service文件夾下,以下圖紅框所示:
下面是詳細的編碼過程;
Account-Service服務是個很普通的springboot應用,和spring-cloud-kubernetes沒有任何關係:
<?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> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.1.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.bolingcavalry</groupId> <artifactId>account-service</artifactId> <version>0.0.1-SNAPSHOT</version> <name>account-service</name> <description>Demo project for Spring Cloud service provider run in kubernetes</description> <properties> <java.version>1.8</java.version> <spring-boot.version>2.1.1.RELEASE</spring-boot.version> <maven-checkstyle-plugin.failsOnError>false</maven-checkstyle-plugin.failsOnError> <maven-checkstyle-plugin.failsOnViolation>false</maven-checkstyle-plugin.failsOnViolation> <maven-checkstyle-plugin.includeTestSourceDirectory>false</maven-checkstyle-plugin.includeTestSourceDirectory> <maven-compiler-plugin.version>3.5</maven-compiler-plugin.version> <maven-deploy-plugin.version>2.8.2</maven-deploy-plugin.version> <maven-failsafe-plugin.version>2.18.1</maven-failsafe-plugin.version> <maven-surefire-plugin.version>2.21.0</maven-surefire-plugin.version> <fabric8.maven.plugin.version>3.5.37</fabric8.maven.plugin.version> <springcloud.version>2.1.1.RELEASE</springcloud.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <type>pom</type> <scope>import</scope> <version>${spring-boot.version}</version> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <version>${springcloud.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>${springcloud.version}</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>${spring-boot.version}</version> <executions> <execution> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin> <plugin> <!--skip deploy --> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-deploy-plugin</artifactId> <version>${maven-deploy-plugin.version}</version> <configuration> <skip>true</skip> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>${maven-surefire-plugin.version}</version> <configuration> <skipTests>true</skipTests> <!-- Workaround for https://issues.apache.org/jira/browse/SUREFIRE-1588 --> <useSystemClassLoader>false</useSystemClassLoader> </configuration> </plugin> <plugin> <groupId>io.fabric8</groupId> <artifactId>fabric8-maven-plugin</artifactId> <version>${fabric8.maven.plugin.version}</version> <executions> <execution> <id>fmp</id> <goals> <goal>resource</goal> </goals> </execution> </executions> </plugin> </plugins> </build> <profiles> <profile> <id>kubernetes</id> <build> <plugins> <plugin> <groupId>io.fabric8</groupId> <artifactId>fabric8-maven-plugin</artifactId> <version>${fabric8.maven.plugin.version}</version> <executions> <execution> <id>fmp</id> <goals> <goal>resource</goal> <goal>build</goal> </goals> </execution> </executions> <configuration> <enricher> <config> <fmp-service> <type>NodePort</type> </fmp-service> </config> </enricher> </configuration> </plugin> </plugins> </build> </profile> </profiles> </project>
由上面的pom.xml內容可見,account-service應用是個簡單的web應用,和SpringCloud、spring-cloud-kubernetes都沒有任何關係,和其餘springboot惟一的不一樣就是用到了fabric8-maven-plugin插件,能夠方便的將應用部署到kubernetes環境;
spring: application: name: account-service server: port: 8080
@RestController public class AccountController { private static final Logger LOG = LoggerFactory.getLogger(AccountController.class); private final String hostName = System.getenv("HOSTNAME"); /** * 探針檢查響應類 * @return */ @RequestMapping("/health") public String health() { return "OK"; } @RequestMapping("/") public String ribbonPing(){ LOG.info("ribbonPing of {}", hostName); return hostName; } /** * 返回hostname * @return 當前應用所在容器的hostname. */ @RequestMapping("/name") public String getName() { return this.hostName + ", " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()); } }
mvn clean install fabric8:deploy -Dfabric8.generator.from=fabric8/java-jboss-openjdk8-jdk -Pkubernetes
執行成功後控制檯輸出以下:
... [INFO] Installing /usr/local/work/k8s/ribbon/spring-cloud-k8s-account-service/target/classes/META-INF/fabric8/kubernetes.json to /root/.m2/repository/com/bolingcavalry/account-service/0.0.1-SNAPSHOT/account-service-0.0.1-SNAPSHOT-kubernetes.json [INFO] [INFO] <<< fabric8-maven-plugin:3.5.37:deploy (default-cli) < install @ account-service <<< [INFO] [INFO] [INFO] --- fabric8-maven-plugin:3.5.37:deploy (default-cli) @ account-service --- [INFO] F8: Using Kubernetes at https://192.168.121.133:8443/ in namespace default with manifest /usr/local/work/k8s/ribbon/spring-cloud-k8s-account-service/target/classes/META-INF/fabric8/kubernetes.yml [INFO] Using namespace: default [INFO] Updating a Service from kubernetes.yml [INFO] Updated Service: target/fabric8/applyJson/default/service-account-service.json [INFO] Using namespace: default [INFO] Updating Deployment from kubernetes.yml [INFO] Updated Deployment: target/fabric8/applyJson/default/deployment-account-service.json [INFO] F8: HINT: Use the command `kubectl get pods -w` to watch your pods start up [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 11.941 s [INFO] Finished at: 2019-06-16T19:00:51+08:00 [INFO] ------------------------------------------------------------------------
[root@minikube spring-cloud-k8s-account-service]# kubectl get deployments NAME READY UP-TO-DATE AVAILABLE AGE account-service 1/1 1 1 69m [root@minikube spring-cloud-k8s-account-service]# kubectl get services NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE account-service NodePort 10.105.157.201 <none> 8080:32596/TCP 69m kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 8d
[root@minikube spring-cloud-k8s-account-service]# minikube service account-service --url http://192.168.121.133:32596
可見account-service的服務能夠經過這個url訪問:http://192.168.121.133:32596
用瀏覽器訪問地址:http://192.168.121.133:32596/name ,以下圖所示,能夠正常訪問account-service提供的服務:
如今account-service服務已經就緒,接下來是開發和部署web-service應用。
<?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> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.1.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.bolingcavalry</groupId> <artifactId>web-service</artifactId> <version>0.0.1-SNAPSHOT</version> <name>web-service</name> <description>Demo project for Spring Cloud service consumer run in kubernetes</description> <properties> <java.version>1.8</java.version> <spring-boot.version>2.1.1.RELEASE</spring-boot.version> <maven-checkstyle-plugin.failsOnError>false</maven-checkstyle-plugin.failsOnError> <maven-checkstyle-plugin.failsOnViolation>false</maven-checkstyle-plugin.failsOnViolation> <maven-checkstyle-plugin.includeTestSourceDirectory>false</maven-checkstyle-plugin.includeTestSourceDirectory> <maven-compiler-plugin.version>3.5</maven-compiler-plugin.version> <maven-deploy-plugin.version>2.8.2</maven-deploy-plugin.version> <maven-failsafe-plugin.version>2.18.1</maven-failsafe-plugin.version> <maven-surefire-plugin.version>2.21.0</maven-surefire-plugin.version> <fabric8.maven.plugin.version>3.5.37</fabric8.maven.plugin.version> <springcloud.kubernetes.version>1.0.1.RELEASE</springcloud.kubernetes.version> <springcloud.version>2.1.1.RELEASE</springcloud.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <type>pom</type> <scope>import</scope> <version>${spring-boot.version}</version> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-kubernetes-core</artifactId> <version>${springcloud.kubernetes.version}</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-kubernetes-discovery</artifactId> <version>${springcloud.kubernetes.version}</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-kubernetes-ribbon</artifactId> <version>${springcloud.kubernetes.version}</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-commons</artifactId> <version>${springcloud.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <version>${springcloud.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>${springcloud.version}</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> <version>${springcloud.version}</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> <version>${springcloud.version}</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>${spring-boot.version}</version> <executions> <execution> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin> <plugin> <!--skip deploy --> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-deploy-plugin</artifactId> <version>${maven-deploy-plugin.version}</version> <configuration> <skip>true</skip> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>${maven-surefire-plugin.version}</version> <configuration> <skipTests>true</skipTests> <!-- Workaround for https://issues.apache.org/jira/browse/SUREFIRE-1588 --> <useSystemClassLoader>false</useSystemClassLoader> </configuration> </plugin> <plugin> <groupId>io.fabric8</groupId> <artifactId>fabric8-maven-plugin</artifactId> <version>${fabric8.maven.plugin.version}</version> <executions> <execution> <id>fmp</id> <goals> <goal>resource</goal> </goals> </execution> </executions> </plugin> </plugins> </build> <profiles> <profile> <id>kubernetes</id> <build> <plugins> <plugin> <groupId>io.fabric8</groupId> <artifactId>fabric8-maven-plugin</artifactId> <version>${fabric8.maven.plugin.version}</version> <executions> <execution> <id>fmp</id> <goals> <goal>resource</goal> <goal>build</goal> </goals> </execution> </executions> <configuration> <enricher> <config> <fmp-service> <type>NodePort</type> </fmp-service> </config> </enricher> </configuration> </plugin> </plugins> </build> </profile> </profiles> </project>
spring: application: name: web-service server: port: 8080 backend: ribbon: eureka: enabled: false client: enabled: true ServerListRefreshInterval: 5000 hystrix.command.BackendCall.execution.isolation.thread.timeoutInMilliseconds: 5000 hystrix.threadpool.BackendCallThread.coreSize: 5
package com.bolingcavalry.webservice; import com.netflix.client.config.IClientConfig; import com.netflix.loadbalancer.AvailabilityFilteringRule; import com.netflix.loadbalancer.IPing; import com.netflix.loadbalancer.IRule; import com.netflix.loadbalancer.PingUrl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; /** * @Description: ribbon配置類 * @author: willzhao E-mail: zq2599@gmail.com * @date: 2019/6/16 11:52 */ public class RibbonConfiguration { @Autowired IClientConfig ribbonClientConfig; /** * 檢查服務是否可用的實例, * 此地址返回的響應的返回碼若是是200表示服務可用 * @param config * @return */ @Bean public IPing ribbonPing(IClientConfig config){ return new PingUrl(); } /** * 輪詢規則 * @param config * @return */ @Bean public IRule ribbonRule(IClientConfig config){ return new AvailabilityFilteringRule(); } }
package com.bolingcavalry.webservice; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.cloud.netflix.ribbon.RibbonClient; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; @SpringBootApplication @EnableDiscoveryClient @EnableCircuitBreaker @RibbonClient(name="account-service", configuration = RibbonConfiguration.class) public class WebServiceApplication { public static void main(String[] args) { SpringApplication.run(WebServiceApplication.class, args); } @LoadBalanced @Bean RestTemplate restTemplate(){ return new RestTemplate(); } }
package com.bolingcavalry.webservice; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; import java.text.SimpleDateFormat; import java.util.Date; /** * @Description: 這裏面封裝了遠程調用account-service提供服務的邏輯 * @author: willzhao E-mail: zq2599@gmail.com * @date: 2019/6/16 12:21 */ @Service public class AccountService { @Autowired private RestTemplate restTemplate; @HystrixCommand(fallbackMethod = "getFallbackName" ,commandProperties = { @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1000") }) public String getDataFromSpringCloudK8SProvider(){ return this.restTemplate.getForObject("http://account-service/name", String.class); } /** * 熔斷時調用的方法 * @return */ private String getFallbackName() { return "Fallback" + ", " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()); } }
package com.bolingcavalry.webservice; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; /** * @Description: 測試用的controller,會遠程調用account-service的服務 * @author: willzhao E-mail: zq2599@gmail.com * @date: 2019/6/16 11:46 */ @RestController public class WebServiceController { @Autowired private AccountService accountService; /** * 探針檢查響應類 * @return */ @RequestMapping("/health") public String health() { return "OK"; } /** * 遠程調用account-service提供的服務 * @return 屢次遠程調返回的全部結果. */ @RequestMapping("/account") public String account() { StringBuilder sbud = new StringBuilder(); for(int i=0;i<10;i++){ sbud.append(accountService.getDataFromSpringCloudK8SProvider()) .append("<br>"); } return sbud.toString(); } }
mvn clean install fabric8:deploy -Dfabric8.generator.from=fabric8/java-jboss-openjdk8-jdk -Pkubernetes
執行成功後控制檯輸出以下:
... [INFO] Installing /usr/local/work/k8s/ribbon/spring-cloud-k8s-web-service/target/classes/META-INF/fabric8/kubernetes.json to /root/.m2/repository/com/bolingcavalry/web-service/0.0.1-SNAPSHOT/web-service-0.0.1-SNAPSHOT-kubernetes.json [INFO] [INFO] <<< fabric8-maven-plugin:3.5.37:deploy (default-cli) < install @ web-service <<< [INFO] [INFO] [INFO] --- fabric8-maven-plugin:3.5.37:deploy (default-cli) @ web-service --- [INFO] F8: Using Kubernetes at https://192.168.121.133:8443/ in namespace default with manifest /usr/local/work/k8s/ribbon/spring-cloud-k8s-web-service/target/classes/META-INF/fabric8/kubernetes.yml [INFO] Using namespace: default [INFO] Creating a Service from kubernetes.yml namespace default name web-service [INFO] Created Service: target/fabric8/applyJson/default/service-web-service.json [INFO] Using namespace: default [INFO] Creating a Deployment from kubernetes.yml namespace default name web-service [INFO] Created Deployment: target/fabric8/applyJson/default/deployment-web-service.json [INFO] F8: HINT: Use the command `kubectl get pods -w` to watch your pods start up [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 12.792 s [INFO] Finished at: 2019-06-16T19:24:21+08:00 [INFO] ------------------------------------------------------------------------
[root@minikube spring-cloud-k8s-web-service]# kubectl get deployments NAME READY UP-TO-DATE AVAILABLE AGE account-service 1/1 1 1 109m web-service 1/1 1 1 18m [root@minikube spring-cloud-k8s-web-service]# kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE account-service NodePort 10.105.157.201 <none> 8080:32596/TCP 109m kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 8d web-service NodePort 10.99.211.179 <none> 8080:30519/TCP 18m
[root@minikube spring-cloud-k8s-web-service]# minikube service web-service --url http://192.168.121.133:30519
可見web-service的服務能夠經過這個url訪問:http://192.168.121.133:30519
用瀏覽器訪問地址:http://192.168.121.133:30519/account ,以下圖所示,頁面上展現的內容都是web-service調用了account-service的接口返回的,證實kubernetes上的註冊發現能力正常:
kubectl scale --replicas=2 deployment account-service
[root@minikube spring-cloud-k8s-web-service]# kubectl get pods NAME READY STATUS RESTARTS AGE account-service-5554576647-m29xr 1/1 Running 0 53m account-service-5554576647-zwwml 1/1 Running 0 20s web-service-6d775855c7-7lkvr 1/1 Running 0 29m
用瀏覽器訪問地址:http://192.168.121.133:30519/account ,以下圖所示,account-sercice返回的hostname已經變成了兩種,和前面查到的pod的name一致,可見web-service的確是經過ribbon輪詢訪問了多個account-service的pod:
kubectl delete deployment account-service
mvn clean install fabric8:deploy -Dfabric8.generator.from=fabric8/java-jboss-openjdk8-jdk -Pkubernetes
至此,spring-cloud-kubernetes的服務發現和輪詢實戰(含熔斷)就所有完成了,利用API Server提供的信息,spring-cloud-kubernetes將原生的kubernetes服務帶給了SpringCloud應用,幫助傳統微服務更好的融合在kubernetes環境中,若是您也在考慮將應用遷移到kubernetes上,但願本文能給您一些參考。