美文网首页技术中台k8s
K8S 服务发现与 Sping-cloud-kubernetes

K8S 服务发现与 Sping-cloud-kubernetes

作者: c80bbe47f715 | 来源:发表于2020-06-29 16:03 被阅读0次

    1、项目介绍

    本文章,旨在使用K8S中自身的服务发现功能,不使用其他的服务发现组件,通过 Spring 的 spring-cloud-kubernetes 来搭建SpringCloud项目。


    2、k8s service概述

    在介绍Svc之前,首先简单说明下Kubernetes中Pod概念。
    Pod是Kubernetes非常重要的基本概念,代表着集群中运行的进程,Pod中封装着应用的容器(有情况下是多个容器)。

    Kubernetes为每个Pod都分配了唯一的Ip地址,称为Pod Ip,一个Pod里的多个容器共享Pod Ip地址,这样客户端可以通过Pod Ip+ 容器端口来访问Pod(Pod Ip+ 容器端口,又被称为Endpoint,也是Kubernetes一种资源)。

    我们知道Kubernetes在自动资源调度时,会频繁的销毁与创建,这样就会导致Pod Ip会频繁的变动,客户端几乎不可能以Pod Ip+端口直接访问Pod,这时候就需要Kubernetes的另一种资源来实现,这就是SVC。

    SVC服务是Kubernetes里的核心资源对象之一,其实可以理解成我们微服务架构中的一个微服务。SVC一旦被创建,Kubernetes就会自动为它分配一个可用的Cluster IP,在svc的整个生命周期内,Cluster IP不会发生改变。


    3、k8s 服务发现简介

    任何分布式系统都会涉及“服务发现”这个基础问题,大部分分布式 系统都通过提供特定的API接口来实现服务发现功能,但这样做会导致 平台的侵入性比较强,也增加了开发、测试的难度。Kubernetes则采用 了直观朴素的思路去解决这个棘手的问题。

    首先,每个Kubernetes中的Service都有唯一的Cluster IP及唯一的名 称,而名称是由开发者自己定义的,部署时也没必要改变,所以完全可 以被固定在配置中。接下来的问题就是如何通过Service的名称找到对应 的Cluster IP。
    目前, Kubernetes上的大部分应用都已经采用了DNS这种新兴的服务发现机制。


    4、项目搭建

    下面我们就使用k8s中的原生服务发现功能,不使用其他的注册组件,来搭建在spring-cloud微服务架构,从而达到服务调用目的。

    现在对spring-cloud-kubernetes基本原理做简单介绍。通过上述描述,我们知道在K8S其实已经维护了服务实例列表,每个服务对应的Endpoint也保存在K8S集群etc数据库中,所以spring-cloud-kubernetes所做的工作,就是在服务调用时,找到找到服务的Endpoint,从而完成服务调用。我们发现spring-cloud-kubernetes也是通过实现DiscoveryClient接口,实现类KubernetesDiscoveryClient,具体源码这里就不叙述了。

    4.1项目目录:
    • abc-gateway 网关服务者
    • abc-service-provider 服务提供者
    • abc-service-consumer 服务消费者
      这个三个项目都是非常简单的SpringBoot工程,但是都需要引用以下关键jar包,具体的版本跟随SpringCloud版本即可。
    <!-- 核心jar包,具体版本可参考官方网站-->
    <!--服务间调用都是采用feign方式,所以需要加上相关jar包-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-kubernetes-all</artifactId>
    </dependency>
    
    4.2项目调用流程:
    flow
    4.3关键代码

    1、abc-gateway 就是一个简单的springboot工程,pom文件添加相关jar包,然后添加以下配置

    # 配置文件配置
    server:
      port: 30000
    spring:
      application:
        name: abc-gateway
      cloud:
        gateway:
          discovery:
            locator:
              enabled: true
              lower-case-service-id: true
        kubernetes:
          reload:
            enabled: true
            mode: polling
            period: 5000
    
    logging:
      level:
        org.springframework.cloud.gateway: debug
        org.springframework.cloud.loadbalancer: debug
    

    2、abc-service-provider与abc-service-consumer 也是一个简单的SpringBoot工程,与通常的工程没有区别,唯一需要修改的就是在POM文件中,添加上上述jar包。

    /**
     * [abc-service-consumer] 启动类
     * 与通常的SpringBoot工程没有区别
     */
    @Slf4j
    @RestController
    @SpringBootApplication
    @EnableDiscoveryClient
    @EnableFeignClients
    public class AbcServiceConsumerApplication {
        
        @Autowired
        private DiscoveryClient discoveryClient;
    
        @Autowired
        private FeignDemo demo;
    
        /**
         * 通过Feign调用服务提供者[abc-service-provider]的接口
         */
        @GetMapping("/get")
        public String feignDemo(){
            return demo.getMessage();
        }
    
        /**
         * KubernetesDiscoveryClient核心类实现了DiscoveryClient
         * 通过getServices()方法可以获取k8s中的服务实例
         */
        @GetMapping("/abc-service-consumer/index")
        public String indexService() {
            log.info("消费服务:abc-service-consumer");
            List<String> services = discoveryClient.getServices();
            services.forEach(System.out::println);
            return "消费服务:abc-service-consumer";
        }
    
        public static void main(String[] args) {
            SpringApplication.run(AbcServiceConsumerApplication.class, args);
        }
    }
    
    ------------
    
    /**
     *[abc-service-consumer]服务Feign调用类,通过Feign调用服务提供者abc-service-provider
     */
    @FeignClient(value = "abc-service-provider")
    public interface FeignDemo {
    
        @GetMapping("/get")
        String getMessage();
    }
    
    
    /**
     * [abc-service-provider]服务提供者启动类
     */
    @SpringBootApplication
    @RestController
    @EnableDiscoveryClient
    public class AbcServiceProviderApplication {
    
        @GetMapping("/get")
        public String get() {
            return "服务提供者";
        }
    
        public static void main(String[] args) {
            SpringApplication.run(AbcServiceProviderApplication.class, args);
        }
    }
    
    

    3、K8S 中资源创建模板:

    
    # 注意: 由于我是本地已经搭建好K8S环境与gitlab的CICD,所以该文件中包含多个脚本变量。如果使用该文件,只需要替换成自己项目信息即可。
    # PROJECT_NAME:SpringBoot工程的服务名称
    # REPLACE_IMAGE: Docker镜像
    # PROJECT_PORT: SpringBoot工程的服务端口
    
    # 定义Deployment
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: PROJECT_NAME
      labels:
        app: PROJECT_NAME
    spec:
      replicas: 1
      template:
        metadata:
          name: PROJECT_NAME
          labels:
            app: PROJECT_NAME
        spec:
          containers:
            - name: PROJECT_NAME
              image: REPLACE_IMAGE
              ports:
                - containerPort: PROJECT_PORT
              imagePullPolicy: IfNotPresent
    #     我使用的是阿里云的公共镜像仓库。更简单的方式,是将对应的服务镜像COPY到K8S的节点中。
    #     (COPY到从节点,K8S如果没有设置,是不会调度Pod到master节点上)
          imagePullSecrets:
            - name: regcred-aliyun
          restartPolicy: Always
      selector:
        matchLabels:
          app: PROJECT_NAME
    
    ---
    # 定义SVC
    apiVersion: v1
    kind: Service
    metadata:
      name: PROJECT_NAME
    spec:
      selector:
        app: PROJECT_NAME
      ports:
        - port: PROJECT_PORT
          targetPort: PROJECT_PORT
          nodePort: PROJECT_PORT
      type: NodePort
    

    5、项目部署流程

    1、构建镜像。java代码准备好之后,使用DockerFile构建好3个服务镜像,然后Copy到k8s的node节点。使用命令docker images查看镜像

    #如果想Pod能够调度到master节点,在master节点运行
    kubectl taint node k8s-master node-role.kubernetes.io/master-
    
    #如果要恢复Master Only状态,执行如下命令:
    kubectl taint node k8s-master node-role.kubernetes.io/master=""
    

    2、构建K8S服务。使用命令kubectl apply -f deployment文件名启动3个服务,使用命令kubectl get svc查看。我们看到3个服务已经成功启动。

    3、访问服务。因为K8S中的服务是nodeport类型,可以通过nodeIP来进行访问。注意,NodeIP与截图中的Cluster-IP这个两个IP有很大区别。朴素的数,NodeIP是真实存在的IP,是可以Ping通;而Cluster-IP是K8S独有的,是虚拟IP,是Ping不通的。具体的大家可查看相关书籍。通过kubectl get node -o wide 可以查看到具体的NodeIP,然后通过NodeIP来访问网关,从而验证结果。

    4、验证结果。截图中已经打印出,服务提供者[abc-service-provider]中的信息。


    6、项目总结

    我们发现在使用spring-cloud-kubernetes组件后,不依赖于其他的服务注册组件,可以在K8S集群中正常运行。所以,对应那些在K8S集群中部署的SpringCloud服务,可以摆脱服务发现组件的限制。但是对于开发人员来说,在开发过程中本地的测试将是一个问题,因为我们发现,在项目启动过程中是要依赖K8S环境的,所以目前的spring-cloud-kubernetes对开发来说并不是太友好,希望后续版本能解决这个痛点。

    我们知道K8S的服务有自身的负载均衡功能,在使用spring-cloud-kubernetes后,服务间调用的实质是使用的Ribbon,Ribbon也是有负载均衡功能的,那么这两者有没有什么联系呢?待我们下次讨论。

    相关文章

      网友评论

        本文标题:K8S 服务发现与 Sping-cloud-kubernetes

        本文链接:https://www.haomeiwen.com/subject/oaaofktx.html