k8s中pod优雅关闭进程

前言:

在 Kubernetes 中,Pod 停止时 kubelet 会先给容器中的主进程发 SIGTERM 信号来通知进程进行 shutdown 以实现优雅停止,如果超时进程还未完全停止则会使用 SIGKILL 来强行终止。

容器终止流程:

1、Pod 被删除,状态置为 Terminating。
2、kube-proxy 更新转发规则,将 Pod 从 service 的 endpoint 列表中摘除掉,新的流量不再转发到该 Pod。
3、如果 Pod 配置了 preStop Hook ,将会执行。
4、kubelet 对 Pod 中各个 container 发送 SIGTERM 信号以通知容器进程开始优雅停止。
5、等待容器进程完全停止,如果在 terminationGracePeriodSeconds 内 (默认 30s) 还未完全停止,就发送 SIGKILL 信号强制杀死进程。
6、所有容器进程终止,清理 Pod 资源。

优雅退出,业务侧需要做的任务是处理SIGTERM信号:

要实现优雅终止,务必在业务代码里面处理下 SIGTERM 信号

 

注意事项:

要实现优雅退出,还需要注意的是如果业务容器的进程,是使用shell脚本启动的,需要进行特殊处理,业务容器才能接收到SIGTERM信号。建议尽量不使用shell脚本启动,如果确实需要,则需要特殊处理。

 

shell启动为什么接收不到SIGTERM信号呢?

1、容器主进程是 shell,业务进程是在 shell 中启动的,成为了 shell 进程的子进程。
2、shell 进程默认不会处理 SIGTERM 信号,自己不会退出,也不会将信号传递给子进程,导致业务进程不会触发停止逻辑。
3、当等到 K8S 优雅停止超时时间 (terminationGracePeriodSeconds,默认 30s),发送 SIGKILL 强制杀死 shell 及其子进程。

 

解决方案:

1、如果shell启动的是单进程,可以在shell 中启动二进制的命令前面加一个exec,这个命令可以让二进制启动的进程代替shell成为主进程,从而业务进程可以接收到SIGTERM

#! /bin/bash

exec /bin/myapp # 脚本中执行二进制

 

2、shell启动的是多个进程,则不能用exec来解决了,因为exec只能让一个进程成为主进程。可以使用trap或init系统实现多进程启动传递SIGTERM信号。

trap:

#! /bin/bash

/bin/myapp & pid1="$!" # 启动第一个业务进程并记录 pid
echo "app started with pid $pid1"

/bin/myclient & pid2="$!" # 启动第二个业务进程并记录 pid
echo "myclient started with pid $pid2"

handle_sigterm() {
  echo "[INFO] Received SIGTERM"
  kill -SIGTERM $pid1 $pid2 # 传递 SIGTERM 给业务进程
  wait $pid1 $pid2 # 等待所有业务进程完全终止
}
trap handle_sigterm SIGTERM # 捕获 SIGTERM 信号并回调 handle_sigterm 函数

wait # 等待回调执行完,主进程再退出

 

init:

dumb-init 和 tini 都可以作为 init 进程,作为主进程 (PID 1) 在容器中启动,然后它再运行 shell 来执行我们指定的脚本 (shell 作为子进程),shell 中启动的业务进程也成为它的子进程,当它收到信号时会将其传递给所有的子进程,从而也能完美解决 SHELL 无法传递信号问题,并且还有回收僵尸进程的能力

制作包含init系统的业务镜像:

FROM ubuntu:latest
RUN apt-get update && apt-get install -y dumb-init
ADD start.sh /
ADD myapp /bin/myapp
ADD myclient /bin/myclient
ENTRYPOINT ["dumb-init", "--"]
CMD ["/start.sh"]

start.sh:

#! /bin/bash
/bin/app1 &
/bin/app2 &
wait

 

 

业务代码不方便处理或没有办法处理SIGTERM信号时,进程优雅退出的方法:

1、preStop-webhook

        lifecycle:
          preStop:
            exec:
              command:
              - sleep
              - 5s

 

2、调整优雅终止时间,terminationGracePeriodSeconds 默认是30s。自己视情况而定

 

posted @ 2021-06-07 16:00  诗码者  阅读(6278)  评论(0编辑  收藏  举报