您现在的位置是:网站首页> 编程开发> devops 编程开发

解决k8s里平滑下线nacos的问题

2023-06-30devops 261人已围观

简介今天上线,突然间齐刷刷报出来一堆错误,本以为有平滑下线就不用去操作下线nacos的动作。后来排查发现,居然平滑下线没起作用。问了一下chatgpt:k8s里优雅退出怎么做?在Kubernetes(简称K8s)中,优雅退出是指在停止或重启一个容器时,容器能够平稳地完成正在处理的工作,并允许正在进行的请求正常完成,不中断用户的服务。以下是在Kubernetes中实现优雅退出的几种方法: 1.&n

解决k8s里平滑下线nacos的问题

最后更新:2023-06-30 16:25:54

推荐指数


今天上线,突然间齐刷刷报出来一堆错误,本以为有平滑下线就不用去操作下线nacos的动作。后来排查发现,居然平滑下线没起作用。


问了一下chatgpt:k8s里优雅退出怎么做?

在Kubernetes(简称K8s)中,优雅退出是指在停止或重启一个容器时,容器能够平稳地完成正在处理的工作,并允许正在进行的请求正常完成,不中断用户的服务。以下是在Kubernetes中实现优雅退出的几种方法:

1. 使用Kubernetes的TerminationGracePeriodSeconds参数:在Pod的配置文件中,可以设置TerminationGracePeriodSeconds参数来控制容器终止前的等待时间。Kubernetes会等待该时间段后再强制关闭容器。可以提供一个合适的时间让容器完成正在处理的任务。

   ```yaml
   apiVersion: v1
   kind: Pod
   metadata:
     name: my-pod
   spec:
     terminationGracePeriodSeconds: 30
     containers:
     - name: my-container
       image: my-image
   ```

2. 在容器内部处理信号:在容器内部编写代码来处理接收到的信号,例如SIGTERM。在接收到信号后,容器可以执行清理工作(例如保存数据、释放资源等)然后正常退出。

   以Python为例,可以使用`signal`库来捕获信号并实现优雅退出的逻辑:

   ```python
   import signal
   import sys

   def graceful_exit(signum, frame):
       # 执行清理工作
       # ...

       sys.exit(0)

   signal.signal(signal.SIGTERM, graceful_exit)

   # 业务逻辑
   # ...
   ```

3. 使用Kubernetes的PreStop钩子:PreStop钩子是一种在Pod终止之前执行的容器命令或脚本。可以在PreStop钩子中编写容器终止前的清理逻辑,例如发送停止信号给应用程序,等待正在处理的任务完成后再退出。

   ```yaml
   apiVersion: v1
   kind: Pod
   metadata:
     name: my-pod
   spec:
     containers:
     - name: my-container
       image: my-image
       lifecycle:
         preStop:
           exec:
             command: ["./cleanscript.sh"]
   ```

以上是一些常见的方法,可以根据具体场景选择适合的方式来实现优雅退出。在Kubernetes中,优雅退出对于确保高可用性和稳定性非常重要。

看了以上内容,发现还是有思路的,至少证明我的k8s里的prestop配置是没错的。

我的k8s配置如下图:

image.png


那问题就应该是出现在了我的pre-stop.sh脚本里了。

我的脚本里是写了一个curl脚本停止调用我的nacos,我尝试进入容器,手动调用pre-stop.sh试一试?


果然,我只调用了pre-stop.sh一个shell居然就直接把我的微服务从nacos里下线了,这根本不是我要的效果啊。现在微服务直接下线,如果有上游服务调用我,那肯定会报错的。所以问题出现在了下线nacos的问题。

后分析源码,果然 出现在了

serviceRegistry.deregister(registration);
这里是直接把服务从nacos里删除,我要的目录只需要标记下线就好。所以换个方法吧。
serviceRegistry.setStatus(registration,"DOWN");

使用以上方法。完美解决问题,具体源码如下:
public void offline(){
   new Thread(() -> {
       log.info("Ready to stop service");
       //serviceRegistry.deregister(registration);
       serviceRegistry.setStatus(registration,"DOWN");
       int waitTime = offlineProperties.getWaitTime();
       log.info("instance has been de-registered: {}" , registration.getServiceId());
       log.info("Waiting {} milliseconds...", waitTime);
       try {
           Thread.sleep(waitTime);
       } catch (InterruptedException e) {
           log.info("interrupted!", e);
       }
       log.info("Closing application...");
       final int exitCode = SpringApplication.exit(context);
       log.info("Closing application code: {} ",exitCode);
       System.exit(exitCode);
   }).start();
}

完美解决问题!

很赞哦! (0)

文章评论

来说两句吧...

验证码: