尝试在 kubernetes 中运行的 Spring Boot 2 应用程序中实现优雅关闭

问题描述 投票:0回答:1

我正在尝试在 Spring Boot 2 应用程序中实现优雅关闭,以在 Pod 缩小时消除 5xx 错误

我已经定了

management:
  endpoints:
    jmx: 
      exposure:
        include: "*"
    web:
      exposure:
        include: "*"
  endpoint:
    shutdown:
      enabled: true

server.shutdown: graceful

在我的

application.yaml
文件中,我使用
/actuator/health
端点作为我的
deployment.yaml
文件中的活跃性和就绪性探测器。

我在 preStopHook 中设置了 50 秒的睡眠时间,而我的终止GracePeriod 是 120 秒

我的deployment.yaml文件

lifecycle:
            preStop:
              exec:
                command: ["/bin/sh","-c","sleep 50;","rm -rf /mnt/bixby/log/$HOSTNAME"]
terminationGracePeriod: 120

livenessProbe:
    httpGet:
      port: 8080
      path: /actuator/health
    initialDelaySeconds: 45
    periodSeconds: 5
readinessProbe:
    httpGet:
      port: 8080
      path: /actuator/health
    initialDelaySeconds: 45
    periodSeconds: 5

奇怪的是,这个东西在一个环境(我们称之为 dev1)中工作,但在其他环境(dev2)中却不起作用。

当我删除 pod 并向 /actuator/health 端点发送curl 请求时,它会在 dev1 中返回

{"status":"DOWN","groups":["liveness","readiness"]}
,但不会在 dev2 env 中返回任何响应。 50 秒后我得到以下输出
curl: (52) Empty reply from server
,这也是我的
prestopHook 
睡眠时间。奇怪的是,我们之前使用的自定义健康检查端点在此期间返回了正确的响应

之后,如果我再次执行curl请求,我会得到以下输出

*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> GET /actuator/health HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.64.0
> Accept: */*
> 
< HTTP/1.1 503 Service Unavailable
< Connection: keep-alive
< Content-Length: 0

同样奇怪的是,在 dev1 env 中,优雅关闭似乎可以正常工作,pod 在 50 秒后退出,这很奇怪,因为终止GracePeriod 是 120 秒

我在我的 Spring Boot 应用程序中添加了以下预销毁代码

@PreDestroy
  public void tearDown() {
    logger.log("Application shutting down");
  }

两个环境中的所有配置、Spring Boot 应用程序的 docker 镜像、kubernetes 版本都是相同的。

我还添加了这个 swagger 配置,以便执行器与 swagger 一起工作

 @Bean // This bean is required when you want swagger and actuator to work together
 public static BeanPostProcessor springfoxHandlerProviderBeanPostProcessor() {
    return new BeanPostProcessor() {
      @Override
      public Object postProcessAfterInitialization(Object bean, String beanName) 
          throws BeansException {
        if (bean instanceof WebMvcRequestHandlerProvider 
            || bean instanceof RequestHandlerProvider) {
          customizeSpringfoxHandlerMappings(getHandlerMappings(bean));
        }
        return bean;
      }

      private <T extends RequestMappingInfoHandlerMapping> void customizeSpringfoxHandlerMappings(
          List<T> mappings) {
        List<T> copy = mappings.stream().filter(mapping -> mapping.getPatternParser() == null)
            .collect(Collectors.toList());
        mappings.clear();
        mappings.addAll(copy);
      }

      @SuppressWarnings("unchecked")
      private List<RequestMappingInfoHandlerMapping> getHandlerMappings(Object bean) {
        try {
          Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings");
          field.setAccessible(true);
          return (List<RequestMappingInfoHandlerMapping>) field.get(bean);
        } catch (IllegalArgumentException | IllegalAccessException e) {
          throw new IllegalStateException(e);
        }
      }
    };
  }
java spring kubernetes graceful-shutdown
1个回答
0
投票

一些事情:Springboot 提供了 liveness 和 readiness 探针,所以你不必使用

/actuator/health

在您的 application.yaml 中,执行以下操作:

management:
  health:
    livenessState:
      enabled: true
    readinessState:
      enabled: true

然后在您的部署 yaml 中:

livenessProbe:
    httpGet:
      port: 8080
      path: /actuator/health/liveness
    initialDelaySeconds: 45
    periodSeconds: 5
readinessProbe:
    httpGet:
      port: 8080
      path: /actuator/health/readiness
    initialDelaySeconds: 45
    periodSeconds: 5

此外,pod 在 50 秒后退出是正确的。如果正常关闭只需要 50 秒,那么 pod 就没有理由等待超过这个时间。如果它总是等待 120 秒,则说明正常关闭没有正常进行。您应该在日志末尾看到“正常关闭已完成”,因此请像这样验证它。

至于在 1 个环境中正常关闭但在另一个环境中不起作用,这确实很奇怪。使用的部署文件是否完全相同?您如何开始申请?如果您想真正验证关闭是否有效,最好的选择是查看应用程序日志。

© www.soinside.com 2019 - 2024. All rights reserved.