技术栈是这样的:spring boot,openfeign,nacos,k8s

k8s部署 spring boot 两个项目(client和server,并且两个服务都注册到nacos上,client通过openfegin调用server)。
client 有2个deployment,一个service。server有10个deployment。

如果 滚动更新 server(10个deployment),虽然k8s能做到优雅终止。但是 nacos上注册的旧的server,好像没法确保已经被下线了。
要怎么做才能确保 nacos上的server下线。(可能要用到k8s的以下参数配置:terminationGracePeriodSeconds,Readiness , Liveness Probes,preStop)

在使用 Spring Boot、OpenFeign、Nacos 和 Kubernetes 的架构中,确保服务实例在滚动更新期间能够优雅地下线非常重要。以下是确保 Nacos 上的服务实例在滚动更新期间能够正确下线的步骤:

步骤 1: Spring Boot 应用程序配置

  1. Spring Boot 应用程序:确保 Spring Boot 应用程序支持优雅关闭,并在关闭时从 Nacos 注册表中移除服务实例。

    @Component
    public class GracefulShutdownHook implements ApplicationListener<ApplicationEvent> {
    
        private final NamingService namingService;
        private final String serviceName;
    
        public GracefulShutdownHook(NamingService namingService, String serviceName) {
            this.namingService = namingService;
            this.serviceName = serviceName;
        }
    
        @Override
        public void onApplicationEvent(ApplicationEvent event) {
            if (event instanceof ContextClosedEvent) {
                // 在关闭时从 Nacos 注册表中移除服务实例
                namingService.deregisterInstance(serviceName, "default", "127.0.0.1", 8080);
            }
        }
    }
    
  2. Actuator 配置:确保 Spring Boot 应用程序启用了 Actuator,并且配置了安全相关的设置(如果需要的话)。

    management.endpoints.web.exposure.include: shutdown
    management.security.enabled: false  # 如果不需要安全设置
    

    如果需要安全设置,可以配置基本认证:

    management.security.enabled: true
    management.security.user.name: admin
    management.security.user.password: password
    
  3. Nacos 配置:确保 Nacos 的客户端配置中包含了自动注销的配置,这样当服务实例关闭时,Nacos 会自动从服务注册表中移除该实例。

    NacosProperties nacosProperties = new NacosProperties();
    nacosProperties.setServerAddr("nacos-server-address");
    nacosProperties.setNamespace("namespace-id");
    nacosProperties.setEndpoint("endpoint");
    nacosProperties.setPort(8848);
    nacosProperties.setUsername("username");
    nacosProperties.setPassword("password");
    
    // 设置客户端配置
    ClientConfig clientConfig = new ClientConfig();
    clientConfig.setServerAddr(nacosProperties.getServerAddr());
    clientConfig.setNamespace(nacosProperties.getNamespace());
    
    // 设置自动注销配置
    clientConfig.setClientWorkerThreads(1);  // 设置客户端线程池大小
    clientConfig.setBeatInterval(5000);  // 心跳间隔
    clientConfig.setBeatTimeout(5000);  // 心跳超时时间
    clientConfig.setEndpoint(nacosProperties.getEndpoint());
    clientConfig.setPort(nacosProperties.getPort());
    
    // 创建 Nacos 客户端
    NamingService naming = NacosFactory.createNamingService(clientConfig);
    
    // 注册服务
    Instance instance = new Instance();
    instance.setIp("your-ip");
    instance.setPort(8080);
    naming.registerInstance("your-service-name", "your-group-name", instance);
    

步骤 2: Kubernetes 配置

  1. 设置 TerminationGracePeriodSeconds:在 Kubernetes 的 Deployment 配置中,为 Pod 设置 terminationGracePeriodSeconds,这样 Kubernetes 会在销毁 Pod 前等待指定的时间,以便应用程序能够完成必要的清理工作。

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: my-server
    spec:
      replicas: 10
      selector:
        matchLabels:
          app: my-server
      template:
        metadata:
          labels:
            app: my-server
        spec:
          terminationGracePeriodSeconds: 30
          containers:
          - name: my-server
            image: my-server:latest
            ports:
            - containerPort: 8080
            readinessProbe:
              httpGet:
                path: /actuator/health
                port: 8080
              initialDelaySeconds: 5
              periodSeconds: 5
            livenessProbe:
              httpGet:
                path: /actuator/health
                port: 8080
              initialDelaySeconds: 15
              periodSeconds: 20
            lifecycle:
              preStop:
                exec:
                  command: ["sh", "-c", "curl -X POST http://localhost:8080/actuator/shutdown"]
    
  2. 配置 Health Checks:在 Deployment 中配置健康检查探针(Readiness 和 Liveness Probes),以确保 Pod 在启动后能够正确地响应请求,并在出现问题时能够及时重启 Pod。

    readinessProbe:
      httpGet:
        path: /actuator/health
        port: 8080
      initialDelaySeconds: 5
      periodSeconds: 5
    livenessProbe:
      httpGet:
        path: /actuator/health
        port: 8080
      initialDelaySeconds: 15
      periodSeconds: 20
    
  3. 使用 preStop 钩子:在 Deployment 的容器配置中,可以为容器配置 preStop 钩子。这可以通过在 lifecycle 字段中定义 preStop 来实现。

    lifecycle:
      preStop:
        exec:
          command: ["sh", "-c", "curl -X POST http://localhost:8080/actuator/shutdown"]
    

    这个示例中,preStop 钩子会在 Pod 终止之前发送一个 HTTP POST 请求到 /actuator/shutdown 端点,以触发 Spring Boot 应用程序的优雅关闭。

总结

通过上述配置,你可以确保在 Kubernetes 环境下 Spring Boot 应用程序能够优雅地关闭,并在关闭前完成必要的清理工作。当 Kubernetes 执行滚动更新时,旧的 Pod 会在新的 Pod 启动之前优雅地下线,并从 Nacos 注册表中移除服务实例。这确保了服务的连续性和一致性。

需要注意的是,确保 Nacos 客户端配置正确,以便在 Pod 终止时能够从注册表中正确移除服务实例。同时,确保 Spring Boot 应用程序支持优雅关闭,并且在关闭时能够从 Nacos 注册表中移除服务实例。