栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

基于 spring-cloud-k8s 跨NS坑续集

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

基于 spring-cloud-k8s 跨NS坑续集

在前面文章 (spring-cloud-k8s 跨 NS 的坑 中,讲述了 spring-cloud-k8s 中,如何利用 k8s 基于 Ribbon 等负载均衡利器来实现 LB,但存在跨命名空间的问题。

今天主要分享的是,基于 K8s 本身的 LB 利器,如何实现跨命名空间的应用服务互相访问,而且不是通过 K8s 原生的负载均衡 url 方式。还是基于 ServiceName。

直击源码

首先,我们新建一个服务提供者:diff-ns-service,该服务提供了一个接口:

@RequestMapping("/getservicedetail")
public String getservicedetail(
        @RequestParam(value = "servicename", defaultValue = "") String servicename) {
    return JSON.toJSonString(discoveryClient.getInstances(servicename));
}

该接口的功能是返回指定 service 的相关信息。比如:这个 Service 对应的有几个 pod,每个 pod 的节点信息,host 等。

image.png

如果想结合 K8s 来实现这个服务的发现,可以基于这个配置:

management:
  endpoint:
    restart:
      enabled: true
    health:
      enabled: true
    info:
      enabled: true

spring:
  application:
    name: diff-ns-service
  cloud:
    loadbalancer:
      ribbon:
        enabled: false
    kubernetes:
      ribbon:
        mode: SERVICE
      discovery:
        all-namespaces: true

另外,如果想利用 k8s configMap 的配置来实现动态刷新应用服务的环境配置,可以这样配置:

spring:
  application:
    name: diff-ns-service
  cloud:
    kubernetes:
      reload:
        enabled: true
        strategy: refresh

        mode: event
      config:
        name: ${spring.application.name}
        namespace: default
        sources:
          - name: ${spring.application.name}
            namespace: ns-app

这里的动态刷新的模式有两个:[polling、event。一个是主动拉取,一个是当 configmap 发生改变时,这种事件会被监听到,会主动刷新。

另外,这个刷新的策略也有几种:

  • refresh,直接刷新

  • restart_context,整个 Spring Context 会优雅重启,里面的所有配置都会重新加载

  • shutdown,重启容器

这样,我们再来配置一下 Service:

apiVersion: v1
kind: Service
metadata:
  name: diff-ns-service-service
  namespace: ns-app
spec:
  type: NodePort
  ports:
  - name: diff-ns-svc
    port: 2008
    targetPort: 2001
  selector:
    app: diff-ns-service

这里我们设置了 Service 的 port,并且这个 Service 以 NodePort 类型创建。在(spring-cloud-k8s 跨 NS 的坑)一文中,我们使用的是默认的类型:ClusterIp。

这样,一个简单的服务提供者就创建成功了。接下来,我们看看服务消费者。

同样,我们先来创建一个服务 rest-service,创建接口:

@GetMapping("/getClientRes")
public Response getClientRes() throws Exception {
        HttpHeaders headers = new HttpHeaders();
        MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
        headers.setContentType(type);
        headers.add("Accept", MediaType.APPLICATION_JSON.toString());
        HttpEntity formEntity = new HttpEntity(null, headers);
        String body = "";
        try {
                ResponseEntity responseEntity = restTemplate.exchange("http://diff-ns-service-service/getservicedetail?servicename=cas-server-service",
                                HttpMethod.GET, formEntity, String.class);
                System.out.println(JSON.toJSonString(responseEntity));
                if (responseEntity.getStatusCodevalue() == 200) {
                        return Response.ok(responseEntity.getBody());
                }
        } catch (Exception e) {
                System.out.println(e.getMessage());
        }
        return Response.error("failed");
}
 

同理地,结合 K8s 来实现这个服务的发现,可以基于这个配置:

management:
  endpoint:
    restart:
      enabled: true
    health:
      enabled: true
    info:
      enabled: true

spring:
  application:
    name: rest-service
  cloud:
    loadbalancer:
      ribbon:
        enabled: false
    kubernetes:
      ribbon:
        mode: SERVICE
      discovery:
        all-namespaces: true

这里,我们不使用 RibbonLoadBalancerClient。

另外,如果想利用 k8s configMap 的配置来实现动态刷新应用服务的环境配置,可以这样配置:

spring:
  cloud:
    kubernetes:
      reload:
        enabled: true
        strategy: refresh

        mode: event
      config:
        name: ${spring.application.name}
        namespace: default
        sources:
          - name: ${spring.application.name}
            namespace: system-server

对于这些,在前面的文章说过,我们需要依赖配置:


    org.springframework.boot
    spring-boot-actuator



        org.springframework.boot
        spring-boot-starter-webflux



    org.springframework.boot
    spring-boot-actuator-autoconfigure



    org.springframework.cloud
    spring-cloud-starter-kubernetes



   org.springframework.cloud
   spring-cloud-starter-kubernetes-config



    org.springframework.cloud
    spring-cloud-kubernetes-discovery



        org.springframework.cloud
        spring-cloud-starter-kubernetes-loadbalancer



        com.squareup.okhttp3
        okhttp

这里没有用 Ribbon 的,直接使用 spring-cloud-starter-kubernetes-loadbalancer,但我们还是利用 RestTemplate:

@LoadBalanced
@Bean
public RestTemplate restTemplate() {
        SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
        requestFactory.setReadTimeout(env.getProperty("client.http.request.readTimeout", Integer.class, 15000));
        requestFactory.setConnectTimeout(env.getProperty("client.http.request.connectTimeout", Integer.class, 3000));
        RestTemplate rt = new RestTemplate(requestFactory);
        return rt;
}

接下来,我们开始部署这两个应用服务了,同时,我们采用服务扩容方式实现多 pod:

kubectl scale --replicas=2 deployment diff-ns-service-deployment

我们苦役看看服务节点信息:

image.png

查看 Service 信息:

接下来,我们访问服务rest-service:http://192.168.8.107:5556/rest-service/getClientRes, 这里我们可以看到日志:

image.png

同时,去哦们可以看到返回结果:这里,我们请求的是获取cas-server 这个服务的 pod 的分布信息。

同样地,我们通过 Service 的 Ip 和端口也可以直接访问:http://192.168.8.107:30916/getservicedetail?servicename=cas-server-service

image.png

PS:如果需要实现负载均衡,还是需要注入:@LoadBalanced,如果我们把这个注解去掉会发生什么呢?

1636538633(1).png

我们发现去掉后,竟然不能访问了。

我们再做一组测试,如果我们利用 spring.cloud.kubernetes.ribbon.mode=POD,我们来看看会有啥结果不?修改配置后,重新编译、部署,我们继续请求 urlhttp://192.168.8.107:5556/rest-service/getClientRes:

image.png
新发现

如果我们引入的是基于 Spring cloud 本身的spring-cloud-starter-kubernetes-loadbalancer,同时,我们没有去掉基于 Ribbon 的 LB 的能力,如:spring.cloud.loadbalancer.ribbon.enabled=false,是有可能会报错的:

1636601324.png
总结
  • Spring cloud 本身:如果是基于 Spring cloud 本身的 LB,需要隐藏 Ribbon 的能力,同时基于RestTemplate 需要注解@LoadBalanced。

  • k8s 本身:如果采用 Spring cloud 的负载,再结合 K8s,可以实现应用服务的 LB。如果设置spring.cloud.kubernetes.ribbon.mode=POD,其禁用了 Ribbon 的 LB 能力,此时不会生效,走的还是 Spring cloud LoadBalancer。另外对于 Service,这里都设置为 NodePort 类型,如果是默认类型是否可以实现 LB,需要待确认,因为目前来看,没有实现,可能是网络问题,并不是说默认类型的 Service 不可实现 LB。

  • Ribbon,基于上面,下次可以尝试基于 NodePort 类型的 Service 来实现 Ribbon 的 LB,看是否是因为 Service 的网络导致的。

实践验证

在前面我们已经针对默认类型的Service进行Ribbon负载均衡测试过,发现无法对跨 NS 进行LB。接下来,我们测试下基于 NodePort 类型的Service,打开spring.cloud.loadbalancer.ribbon.enabled=true,引入依赖:


    
    org.springframework.cloud
    spring-cloud-starter-kubernetes-ribbon

按照以上配置,我们部署服务diff-ns-service,我们发现服务启动后日志:

1636603546(1).png

请求后返回日志:

结论

不管怎样,Ribbon 无法解决跨 NS 的应用服务之间的相互访问。但对于 Service 类型来说,可能是网络设置问题,跟其类型无关。

下面给大家介绍一本好书《深入了解分布式事务》,该书在当当网目前销售火热,有原理加实战,感兴趣可以点击下方链接购买。

开源项目

  实践项目代码开源:https://gitee.com/damon_one/microservice-k8s

欢迎大家star、fork,欢迎联系我,一起学习。

云原生社区合肥站

云原生社区合肥站正式启动啦,欢迎base合肥、关注云原生、长期从事云原生的同志们踊跃加入,云原生社区合肥站会因为你们的加入而变得更加美好~

详情参见Issue:https://github.com/cloudnativeto/community/issues/107

欢迎关注个站

往期回顾

微服务自动化部署CI/CD

如何利用k8s拉取私有仓库镜像

个站建设基础教程

ArrayList、linkedList 你真的了解吗?

大佬整理的mysql规范,分享给大家

如果张东升是个程序员

微服务架构设计之解耦合

浅谈负载均衡

Oauth2的认证实战-HA篇

Oauth2的授权码模式《上》

浅谈开发与研发之差异

浅谈 Java 集合 | 底层源码解析

基于 Sentinel 作熔断 | 文末赠资料

基础设施服务k8s快速部署之HA篇

今天被问微服务,这几点,让面试官刮目相看

Spring cloud 之多种方式限流(实战)

Spring cloud 之熔断机制(实战)

面试被问finally 和 return,到底谁先执行?

Springcloud Oauth2 HA篇

Spring Cloud Kubernetes之实战一配置管理

Spring Cloud Kubernetes之实战二服务注册与发现

Spring Cloud Kubernetes之实战三网关Gateway

关注公众号,回复入群,获取更多惊喜!公众号(程序猿Damon)里回复 ES、Flink、Java、Kafka、MQ、ML、监控、大数据、k8s 等关键字可以查看更多关键字对应的文章。

点击 "damon8.cn" 获取更好的阅读体验!

❤️给个「在看」,是对我最大的支持❤️
转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号