SpringCloudKubernetes服务发现

wen java案例 2

本文目录导读:

SpringCloudKubernetes服务发现

  1. 核心思想:用 K8s Service 取代 Eureka
  2. 工作机制与流程
  3. 主要组件与配置
  4. 与 K8s 原生 Service 的区别
  5. 常见问题与最佳实践
  6. 完整示例

Spring Cloud Kubernetes 是一个开源项目,旨在让基于 Spring Cloud 的微服务能够无缝地在 Kubernetes(K8s)环境中运行,尤其是利用 Kubernetes 原生的服务发现与配置管理能力,替代传统的 Eureka 或 Consul。

下面详细介绍 Spring Cloud Kubernetes 的服务发现机制。

核心思想:用 K8s Service 取代 Eureka

在传统的 Spring Cloud 架构中,服务通过 Eureka 注册中心相互发现,在 Kubernetes 中,Kubernetes 本身就是一个强大的服务发现系统,通过 Service 资源和 kube-dns / CoreDNS 实现。

Spring Cloud Kubernetes 的服务发现模块 (spring-cloud-starter-kubernetes-discovery) 的作用就是:

  1. 对接 Kubernetes API Server,实时获取当前 Namespace 下的所有 Service 和 Pod 信息。
  2. 实现 Spring Cloud 标准的 DiscoveryClient 接口(即 org.springframework.cloud.client.discovery.DiscoveryClient)。
  3. 使得 @LoadBalancedRestTemplateWebClient 可以直接使用 http://service-name 这样的 Kubernetes 内部域名进行服务调用。

工作机制与流程

sequenceDiagram
    participant ServiceA as ServiceA Pod
    participant K8sAPI as K8s API Server
    participant K8sDNS as K8s DNS (CoreDNS)
    participant ServiceB as ServiceB Pod
    Note over ServiceA: 启动时,Spring Cloud K8s<br/>通过 API Server 获取所有 Service
    ServiceA->>K8sAPI: GET /api/v1/namespaces/default/services/
    K8sAPI-->>ServiceA: 返回 Service 列表 (endpoints)
    Note over ServiceA: 更新本地 Service 缓存<br/>(service-b: 10.1.0.5:8080)
    ServiceA->>ServiceA: 调用 http://service-b/api/data
    Note over ServiceA: 拦截请求,解析 service-b<br/>不直接走 DNS,而是走本地缓存(LB)
    ServiceA->>ServiceB: HTTP Request (10.1.0.5:8080)
    ServiceB-->>ServiceA: HTTP Response

主要组件与配置

添加依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-kubernetes-discovery</artifactId>
</dependency>

核心配置类

application.propertiesapplication.yml 中:

spring:
  application:
    name: service-a
  cloud:
    kubernetes:
      discovery:
        # 是否启用 K8s 服务发现,默认 true
        enabled: true
        # 要发现的服务所在的 Namespace,默认当前 Pod 所在 Namespace
        # 如果所有服务都在同一个 Namespace,通常不需要设置
        # namespaces: [default, production]
        all-namespaces: false
        # 服务发现的轮询间隔(毫秒),默认 30000 (30秒)
        cache-refresh-interval: 10000
      # Pod 启动在 K8s 外部(例如本地开发),需要指定 API Server 地址
      # master-url: https://kubernetes.default.svc
      # config-map 和 secret 相关配置...

使用方式

服务调用代码与传统 Spring Cloud 完全一致:

@RestController
public class ConsumerController {
    @Autowired
    @LoadBalanced
    private RestTemplate restTemplate;
    @GetMapping("/call")
    public String callServiceB() {
        // 这里的 service-b K8s Service 的名称
        String response = restTemplate.getForObject("http://service-b/api/data", String.class);
        return "Response from service-b: " + response;
    }
}

关键点

  • 结合了 @LoadBalanced 注解后,RestTemplate 会使用 Spring Cloud LoadBalancer(默认实现)进行客户端负载均衡。
  • 它并不直接使用 Kubernetes 的 Service 进行负载均衡(这是 kube-proxy 的工作),而是客户端侧负载均衡,直接从 Pod 的 IP:Port 直接调用,跳过了一次 kube-proxy 的转发,延迟更低。

与 K8s 原生 Service 的区别

特性 Kubernetes 原生 Service (通过 kube-proxy) Spring Cloud Kubernetes 服务发现
负载均衡位置 节点内核 (iptables/IPVS) 客户端进程内 (Spring Cloud LoadBalancer)
请求路径 → Pod → Service IP → kube-proxy → Pod → Pod → Pod (直接调用)
网络开销 多一次 DNAT 转发 (非常小) 无转发,直连 Pod
控制粒度 粗粒度(只能 round-robin) 细粒度(自定义负载均衡策略、权重、熔断等)
服务列表来源 iptables/IPVS 规则(静态) API Server(动态拉取 + 本地缓存)
适用场景 简单微服务,不关心客户端负载均衡 需要高级负载均衡、断路器、灰度发布的场景

常见问题与最佳实践

权限问题

Spring Cloud Kubernetes 需要读取 API Server 的资源,在 K8s 1.24+ 中,默认的 service account 权限很低,你需要创建 RBAC:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: spring-cloud-k8s-discover
rules:
- apiGroups: [""]
  resources: ["services", "endpoints", "pods"]
  verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: spring-cloud-k8s-discover-binding
subjects:
- kind: ServiceAccount
  name: default
  namespace: default
roleRef:
  kind: ClusterRole
  name: spring-cloud-k8s-discover
  apiGroup: rbac.authorization.k8s.io

本地调试

在 K8s 集群外启动 Spring Boot 应用进行调试时,需要配置 K8s 连接信息:

spring:
  cloud:
    kubernetes:
      client:
        master-url: https://your-k8s-master:6443
      # 或者使用 kubeconfig 文件
      # kube-config-path: ~/.kube/config
      discovery:
        namespaces: [default]

与 ConfigMap/Secret 的配合

服务发现常与配置管理一起使用,Spring Cloud Kubernetes 还提供 spring-cloud-starter-kubernetes-config 支持从 ConfigMap 和 Secret 加载配置。

完整示例

假设有一个 order-service 和一个 user-service

order-service 的 application.yml:

spring:
  application:
    name: order-service
  cloud:
    kubernetes:
      discovery:
        all-namespaces: false
        cache-refresh-interval: 5000

OrderController.java:

@RestController
@RequestMapping("/orders")
public class OrderController {
    @Autowired
    private DiscoveryClient discoveryClient;
    @GetMapping("/services")
    public List<String> getAllServices() {
        // 获取所有注册的服务名
        return discoveryClient.getServices();
    }
    @GetMapping("/users/{id}")
    public String getUserById(@PathVariable Long id) {
        // 调用 user-service
        String response = restTemplate.getForObject(
            "http://user-service/users/" + id, String.class);
        return "User: " + response;
    }
}

部署到 K8s 后,order-service 就会自动发现 user-service 的 Pod 列表,并进行负载均衡调用。

  • Spring Cloud Kubernetes 服务发现 是 Spring Cloud 与 K8s 的桥梁,让传统微服务开发体验迁移到容器环境。
  • 不替代 K8s Service,而是基于 K8s Service 提供更高级的客户端负载均衡能力。
  • 核心优势:Spring Cloud 生态的无缝集成,支持 Ribbon/LoadBalancer、Sentinel 熔断、OpenFeign 等。
  • 注意事项:需要配置 RBAC 权限,并在本地开发时指定 K8s 连接信息。

抱歉,评论功能暂时关闭!