spring-cloud-kubernetes的服務發現和輪詢實戰(含熔斷)
本文是《spring-cloud-kubernetes實戰系列》的第四篇,主要內容是在kubernetes上部署兩個應用:Web-Service和Account-Service,通過spring-cloud-kubernetes提供的註冊發現能力,實現Web-Service呼叫Account-Service提供的http服務;
系列文章列表
- 《spring-cloud-kubernetes官方demo執行實戰》
- 《你好spring-cloud-kubernetes》
- 《spring-cloud-kubernetes背後的三個關鍵知識點》
- 《spring-cloud-kubernetes的服務發現和輪詢實戰(含熔斷)》
- 《spring-cloud-kubernetes與SpringCloud Gateway》
- 《spring-cloud-kubernetes與k8s的configmap》
全文概覽
本文由以下段落組成:
- 環境資訊
- 常見的SpringCloud註冊發現服務一覽
- 分析kubernetes上如何實現服務註冊發現
- 本章實戰原始碼下載連結
- 實戰開發Account-Service服務(服務提供方)
- 實戰開發Web-Service服務(服務消費方)
- 擴容驗證ribbon輪詢能力
- 驗證熔斷能力
環境資訊
本次實戰的環境和版本資訊如下:
- 作業系統:CentOS Linux release 7.6.1810
- minikube:1.1.1
- Java:1.8.0_191
- Maven:3.6.0
- fabric8-maven-plugin外掛:3.5.37
- spring-cloud-kubernetes:1.0.1.RELEASE
上面的linux、minikube、java、maven,請確保已準備好,linux環境下minikube的安裝和啟動請參考《Linux安裝minikube指南 》。
常見的SpringCloud註冊發現服務一覽
SpringCloud環境最重要的功能是註冊發現服務,因此將SpringCloud應用遷移到kubernetes環境時,開發者最關心的問題是在kubernetes上如何將自身服務暴露出去,以及如何呼叫其他微服務。
先看看普通SpringCloud環境下的註冊發現,下圖來自spring官方部落格,地址是:https://spring.io/blog/2015/07/14/microservices-with-spring,
由上圖可見,應用Account-Service將自己註冊到Eureka,這樣Web-Service用"account-service"就能在Eureka找到Account-Service服務的地址,然後順利傳送RestFul請求到Account-Service,用上其提供的服務。
分析kubernetes上如何實現服務註冊發現
如果將上面的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輪詢發起請求;
上圖有個細節請注意:WebService應用並不是直接將請求傳送給Account-Service在kubernetes建立的service,而是直接傳送到具體的Pod上了,之所以具有這個能力,是因為spring-cloud-kubernetes框架通過service拿到了Account-Service對應的所有Pod資訊(endpoint),此邏輯可以參考原始碼KubernetesServerList.java,如下所示:
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;
}
理論分析已經完成,接下來就開始實戰吧
原始碼下載
如果您不打算寫程式碼,也可以從GitHub上下載本次實戰的原始碼,地址和連結資訊如下表所示:
名稱 | 連結 | 備註 |
---|---|---|
專案主頁 | https://github.com/zq2599/blog_demos | 該專案在GitHub上的主頁 |
git倉庫地址(https) | https://github.com/zq2599/blog_demos.git | 該專案原始碼的倉庫地址,https協議 |
git倉庫地址(ssh) | [email protected]:zq2599/blog_demos.git | 該專案原始碼的倉庫地址,ssh協議 |
這個git專案中有多個資料夾,本章的Account-Service原始碼在spring-cloud-k8s-account-service資料夾下,Web-Service原始碼在spring-cloud-k8s-web-service資料夾下,如下圖紅框所示:
下面是詳細的編碼過程;
開發和部署Account-Service服務
Account-Service服務是個很普通的springboot應用,和spring-cloud-kubernetes沒有任何關係:
- 通過maven建立一個springboot應用,artifactId是account-service,pom.xml內容如下:
<?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環境;
- application.yml內容如下,依舊很簡單:
spring:
application:
name: account-service
server:
port: 8080
- 對外提供服務的是AccountController ,方法getName返回了當前容器的hostname,方法health用於響應kubernetes的兩個探針,方法ribbonPing用於響應使用了ribbon服務的呼叫方,它們會呼叫這個介面來確定當前服務是否正常:
@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());
}
}
- 將上述工程的原始碼放在minikube機器上,確保maven設定正常,然後在pom.xml檔案所在目錄執行以下命令,即可編譯構建工程並部署到kubernetes上:
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] ------------------------------------------------------------------------
- 檢查kubernetes上的部署和服務是否正常:
[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
- minikube的service命令可以得到指定服務的訪問地址:
[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應用。開發和部署Web-Service服務
Web-Service服務是個springboot應用,用到了spring-cloud-kubernetes提供的註冊發現能力,以輪詢的方式訪問指定服務的全部pod:- 通過maven建立一個springboot應用,artifactId是web-service,pom.xml內容如下,要重點關注的是spring-cloud-starter-kubernetes-ribbon的依賴:
<?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>
- application.yml的內容如下,增加了熔斷的配置:
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
- 建立一個ribbon的配置類RibbonConfiguration:
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: [email protected]
* @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();
}
}
- 應用啟動類如下,注意增加了服務發現、熔斷、ribbon的配置,還定義了restTemplte例項,注意@LoadBalanced註解:
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();
}
}
- 遠端呼叫account-service的http介面的邏輯被放進服務類AccountService中,注意URL中用的是服務名account-service:
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: [email protected]
* @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());
}
}
- 最後是響應web請求的WebServiceController類,這裡面呼叫了AccountService的服務,這樣我們從web發起請求後,web-service就會遠端呼叫account-service的服務:
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: [email protected]
* @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();
}
}
- 將上述工程的原始碼放在minikube機器上,確保maven設定正常,然後在pom.xml檔案所在目錄執行以下命令,即可編譯構建工程並部署到kubernetes上:
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] ------------------------------------------------------------------------
- 檢查kubernetes上的部署和服務是否正常:
[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
- minikube的service命令可以得到指定服務的訪問地址:
[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上的註冊發現能力正常:
擴容驗證ribbon輪詢能力
雖然web-service可以正常呼叫account-service的服務,但始終訪問的是一個pod,接下來我們就對account-service的pod進行擴容,將數量調整為2個,看看web-service是否可以輪詢呼叫每個account-service的pod:- 執行以下命令即可將pod數量調整為2個:
kubectl scale --replicas=2 deployment account-service
- 檢查account-service的pod,發現已經有兩個了(account-service-5554576647-m29xr和account-service-5554576647-zwwml):
[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:
驗證熔斷能力
接下來驗證web-service配置的熔斷服務是否可以生效:- 執行以下命令將account-service的deployment刪除:
kubectl delete deployment account-service
- 再瀏覽器訪問地址:http://192.168.121.133:30519/account ,如下圖所示,頁面上的"Fallback"是配置的熔斷方法返回的內容,可見熔斷配置已經生效:
- 再回到web-service的pom.xml所在位置執行以下命令,這樣會重新構建部署一次web-service服務:
mvn clean install fabric8:deploy -Dfabric8.generator.from=fabric8/java-jboss-openjdk8-jdk -Pkubernetes
- 再瀏覽器訪問地址:http://192.168.121.133:30519/account ,如下圖所示,服務成功恢復:
至此,spring-cloud-kubernetes的服務發現和輪詢實戰(含熔斷)就全部完成了,利用API Server提供的資訊,spring-cloud-kubernetes將原生的kubernetes服務帶給了SpringCloud應用,幫助傳統微服務更好的融合在kubernetes環境中,如果您也在考慮將應用遷移到kubernetes上,希望本文能給您一些參考。
歡迎關注我的公眾號:程式設計師欣宸
相關推薦
spring-cloud-kubernetes的服務發現和輪詢實戰(含熔斷)
本文是《spring-cloud-kubernetes實戰系列》的第四篇,主要內容是在kubernetes上部署兩個應用:Web-Service和Account-Service,通過spring-cloud-kubernetes提供的註冊發現能力,實現Web-Service呼叫Account-Service提
SpringBoot + Spring Cloud Consul 服務註冊和發現
![image.png](https://cdn.nlark.com/yuque/0/2020/png/359374/1595433507631-6d8b936d-72dc-4ec2-8148-15ae46e5ee12.png#align=left&display=inline&height=360&marg
Spring Cloud Consul—服務發現與Consul
列表 當前 host static 實例 cati edi 上下文 ota 服務發現是基於微服務架構的關鍵原則之一。嘗試配置每個客戶端或某種形式的約定可能非常困難,可以非常脆弱。Consul通過HTTP API和DNS提供服務發現服務。Spring Cloud Consul
Spring Cloud-02服務發現與服務註冊Eureka + Eureka Server的搭建
文章目錄 服務發現元件概述 Eureka概述 Eureka原理 Maven父子工程的搭建 Eureka Server的搭建 新建 Maven Module 新增spring-cloud-starter-eureka-s
java面試題框架篇spring cloud之服務發現consul
1.服務發現 spring cloud提供了多個服務發現框架整合,euerka已經停止開發了,目前最流行的是consul Feature euerka Consul zookeeper etcd 服務健康檢查 可配支援 服務狀態,記
SpringCloud實戰二:Spring Cloud Eureka 服務發現與註冊中心
Spring Cloud Eureka 它是通過封裝 Netflix 開源的Eureka,一款基於 Rest 的服務發現與註冊元件,包括 Eureka Server 和 Eureka Client,最新版本為2018年8月釋出的1.9.4版本,最新的2.x版本已經不再開源,但是1.9
Spring Cloud Eureka —— 服務發現與消費
ribbon簡單介紹 1服務發現的任務由Eureka的客戶端完成,服務消費的任務由Ribbon完成。 2Ribbon是一個基於HTTP和TCP的客戶端負載均衡器,它可以在通過客戶端中配置的ribbonServerList服務端列表去輪詢訪問以達到負載均衡的作用。 構建例
Spring Cloud Eureka--服務發現
一、Spring Cloud Spring Cloud 為開發者提供了在分散式系統(如配置管理、服務發現、斷路器、智慧路由、微代理、控制匯流排、一次性 Token、全域性鎖、決策競選、分散式會話和叢集狀態)操作的開發工具。最關鍵的是它足夠簡單,一般的開發人員只需要
Spring系列學習之Spring Cloud Zookeeper服務發現及分散式配置
英文原文:https://spring.io/projects/spring-cloud-zookeeper 目錄 概述 特性 快速開始 學習 文件 示例 概述 Spring Cloud Zookeeper通過自動配置和Spring環境以及其他Spring程式
四:Spring Cloud 之服務發現與呼叫-Ribbon
1. 簡介 Ribbon is a client side load balancer which gives you a lot of control over the behaviour of HTTP and TCP clients. F
四、Spring cloud之服務發現/註冊(Eureka)
一、Spring Cloud Eureka (一)Eureka伺服器 Eureka Server 是 Eureka Client 的註冊服務中心,管理所有註冊服務、以及其例項資訊和狀態。 1、引入Maven依賴 <dependency>
Kubernetes服務發現和kube-dns外掛
大綱 kube-dns的主要變化 kube-dns的實現原理 kubedns容器詳解 dnsmasq容器簡介 exech
spring cloud——eureka服務的註冊和發現
https://blog.csdn.net/forezp/column/info/15197 參考方誌朋的部落格 學到了@LoadBalanced註釋,可以使得ribbon(負載均衡)起作用。還有就是 restTemplate.getForObject("http://provide
spring-cloud微服務之路(三):服務註冊和發現之Eureka、Consul
在上一篇spring-cloud微服務之路(二):Spring Boot 我們介紹瞭如何快速的使用 Spring Boot 搭建一個微服務專案,這一篇我們演示如何分別使用 Spring Cloud Eureka 和 Spring Cloud Consul 完成
Spring Cloud + Kubernetes 微服務框架原理和實踐
早在半年前,公司開始推行容器化部署方案 AppOS,雖然釋出介面過於極客,十分晦澀,不過仔細研究起來真的覺得十分強大,容器化推行後,計算資源(CPU、記憶體)的利用率可以極大提高,降低伺服器數量,從而節約技術成本。恰巧,若干個朋友所在創業公司最近也在嘗試做微服務、容器化。架構
spring cloud微服務架構 服務提供者和服務消費者
服務 lee 名詞 mave into gin tag bigint snap 服務提供者和服務消費者 下面這張表格,簡單描述了服務提供者/消費者是什麽: | 名詞 | 概念 | | ----- | ---------
Spring Cloud微服務架構—服務註冊與發現
開源 查看 zookeeper rest 探討 ken 並且 tin services Spring Cloud簡介 Spring Cloud是一個基於Spring Boot實現的雲應用開發工具,它為基於JVM的雲應用開發中涉及的配置管理、服務發現、斷路器、智能路由、微代理
構建微服務架構Spring Cloud:服務註冊與發現(Eureka、Consul)
comm 簡介 foundry 架構 eas args 包含 什麽 其他 Spring Cloud簡介 Spring Cloud是一個基於Spring Boot實現的雲應用開發工具,它為基於JVM的雲應用開發中涉及的配置管理、服務發現、斷路器、智能路由、微代理、控制總線、全
spring cloud註冊服務與發現(踩著坑往前爬)
lse value 都是 一個 人員 aging 分享圖片 idea put spring cloud簡介 Spring Cloud為開發人員提供了快速構建分布式系統中的一些通用模式(例如配置管理,服務發現,斷路器,智能路由,微代理,控制總線,一次性令牌,全局鎖,領導選舉
你真的了解微服務架構嗎?聽聽八年阿裏架構師怎樣講述Dubbo和Spring Cloud微服務架構
微服務 架構 dubbo Spring Cloud 微服務架構是互聯網很熱門的話題,是互聯網技術發展的必然結果。它提倡將單一應用程序劃分成一組小的服務,服務之間互相協調、互相配合,為用戶提供最終價值。雖然微服務架構沒有公認的技術標準和規範或者草案,但業界已經有一些很有影響力的開源微服務架構框架