写点什么

spring-cloud-kubernetes 的服务发现和轮询实战 (含熔断)

  • 2021 年 11 月 10 日
  • 本文字数:7840 字

    阅读完需:约 26 分钟

<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>rep


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


ackage</goal>


</goals>


</execution>


</executions>


</plugin>


<plugin>


<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>


<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 环境;


  1. application.yml 内容如下,依旧很简单:


spring:


application:


name: account-service


server:


port: 8080


  1. 对外提供服务的是 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());


}


}


  1. 将上述工程的源码放在 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] ------------------------------------------------------------------------


  1. 检查 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


  1. 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


  1. 用浏览器访问地址:http://192.168.121.133:32596/name ,如下图所示,可以正常访问 account-service 提供的服务:



现在 account-service 服务已经就绪,接下来是开发和部署 web-service 应用。

开发和部署 Web-Service 服务

Web-Service 服务是个 springboot 应用,用到了 spring-cloud-kubernetes 提供的注册发现能力,以轮询的方式访问指定服务的全部 pod:


  1. 通过 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>


</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>


<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>


<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>


  1. 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


  1. 创建一个 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: 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();


}


}


  1. 应用启动类如下,注意增加了服务发现、熔断、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();


}


}


  1. 远程调用 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: 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());


}


}


  1. 最后是响应 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: 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();


}


}


  1. 将上述工程的源码放在 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

评论

发布
暂无评论
spring-cloud-kubernetes的服务发现和轮询实战(含熔断)