zoukankan      html  css  js  c++  java
  • 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。自己视情况而定

    --------崔帅的拾荒
  • 相关阅读:
    [Java]如何把当前时间插入到数据库
    [Java]Get与Post,客户端跳转与服务器端跳转
    [Java]MyBatis框架
    [Java]Java分层概念(转)
    [Java]Spring框架
    [Java]JavaScript在这里学习
    [Java]Servlet&JSP
    [Java]jdbc[转]
    [工具]GitHub上整理的一些工具[转]
    [Java] 集合框架
  • 原文地址:https://www.cnblogs.com/cuishuai/p/14859182.html
Copyright © 2011-2022 走看看