云原生架构之Springboot Gateway+K8s 服务注册发现方案(南北流量)

3,155 阅读3分钟

“我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第5篇文章,点击查看活动详情

一 方案概述

springboot gateway 服务利用spring cloud kubernetes进行调用K8s API获取service服务发现,进行路由转发。

二 SpringBoot + K8s service服务注册发现方案

2.1 方案简介

springboot gateway 使用spring cloud kubernetes 与api Servier的http交互,方便项目中对api Server的请求和读取k8s中的 服务注册发现 Services / Endpoints

南北流量访问 http://网关服务IP:网关服务端口/后端服务service名称/请求api路径 , gateway 通过调用API server获取到后端服务endpoints,进行请求路由转发转发。

2.2 服务注册发现实现

2.2.1 服务注册过程

spring cloud 服务配置有serivce的服务,启动后k8s集群针对调用该service,后端会返回具体的pod列表。

2.2.2 服务发现过程

通过 spring cloud kubernetes的服务发现,调用k8s api获取pod实例的ip和端口,gateway 进行流量转发。

2.3 方案特点

  • 优点:
    • 服务直接通过k8s服务发现,获取service后的实例POD IP和端口,gateway 流量转发,直接对POD发起,不经过service转发,性能好。
  • 不足:
    • 负载均衡算法在服务调用端(客户端)实现,例如ribbon实现,如果后期使用服务治理框架例如istio/linkerd不适用。

三 实战

3.1 后端API服务

对外暴露的API服务,服务注册为编写服务对应的service yaml资源对象。 源码位置:github.com/redhatxl/cl…

3.2 gateway

3.2.1 服务逻辑

springboot-init 为服务提供者,对外提供 /services 用于获取 K8s 名称空间的名称,及返回相应 POD 的hostname。服务注册,仅需为服务编写 service yaml 资源清单即可。

3.2.2 服务发现

通过引入 spring-cloud-starter-kubernetes-client-all 进行服务发现

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-kubernetes-client-all</artifactId>
<version>2.1.3</version>
</dependency>

3.2.3 项目目录结构

.
├── Dockerfile
├── HELP.md
├── README.md
├── deploy
│   ├── deploy.yaml
│   └── deploy.yamle
├── mvnw
├── mvnw.cmd
├── pom.xml
├── springboot-gateway.iml
├── src
│   ├── main
│   │   ├── java
│   │   │   └── com
│   │   │       └── xuel
│   │   │           └── springbootgateway
│   │   │               └── SpringbootGatewayApplication.java
│   │   └── resources
│   │       ├── application.properties
│   │       └── application.yaml

3.2.4 K8s部署文件

apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: springgateway
  name: springboot-gateway
  labels:
    app: springboot-gateway
spec:
  replicas: 1
  selector:
    matchLabels:
      app: springboot-gateway
  template:
    metadata:
      labels:
        app: springboot-gateway
    spec:
      containers:
        - name: springboot-gateway
          image: ccr.ccs.tencentyun.com/xxxxxxxxxx-dev/springbootgateway:img_v5
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 8080
              protocol: TCP
          livenessProbe:
            httpGet:
              port: 8080
              path: /actuator/health
            periodSeconds: 10
            initialDelaySeconds: 3
            terminationGracePeriodSeconds: 10
            failureThreshold: 5
            timeoutSeconds: 10
          readinessProbe:
            httpGet:
              port: 8080
              path: /actuator/health
            initialDelaySeconds: 5
            periodSeconds: 10
            failureThreshold: 5
            timeoutSeconds: 10

---
apiVersion: v1
kind: Service
metadata:
  name: springbootgateway
  namespace: springgateway
  labels:
    app: springboot-gateway
spec:
  ports:
    - port: 8080
      protocol: TCP
      targetPort: 8080
  type: ClusterIP
  selector:
    app: springboot-gateway

3.2.5 项目源码

项目位置:github.com/redhatxl/cl…

四 测试

4.1 单独测试服务API

k port-forward -n springgateway --address 0.0.0.0 svc/springbootgatewayserviceprovider 8888:8080

4.2 通过gateway 进行测试

k port-forward -n springgateway --address 0.0.0.0 svc/springbootgateway 9999:8080

4.3 查看资源

五 其他

配置 url-expression 目的是为了在转发的时候直接转发到 Kubernetes 中相应的 Service 上去,默认的表达式为 "'lb://'+serviceId" ,这种适用于通过 Consul 或者 Eureka,最终是根据服务的IP和端口访问, spring-cloud-kubernetes 没有实现 com.netflix.loadbalancer.AbstractServerList ,所以不会进行IP转换,最终是通过服务名称查找Service 实现调用,所以不需要负载均衡

  • 如果是客户端实现负载均衡,则不需要指定 "'http://'+serviceId+':'+port"