pods 优雅终止


概述

Pod 销毁时,会停止容器内的进程,通常在停止的过程中我们需要执行一些善后逻辑,比如等待存量请求处理完以避免连接中断,或通知相关依赖进行清理等,从而实现优雅终止目的。本文介绍在 Kubernetes 场景下,实现容器优雅终止的最佳实践。

当 Kubernetes 杀死一个 pod 时,会发生以下 5 个步骤:

  1. Pod 切换到终止状态并停止接收任何新流量,容器仍在 pod 内运行。
  2. preStop 钩子是一个特殊的命令或 HTTP 请求被执行,并被发送到 pod 内的容器。
  3. SIGTERM 信号被发送到 pod,容器意识到它将很快关闭。
  4. Kubernetes 等待宽限期 (terminationGracePeriodSeconds)。此等待与 preStop hook 和 SIGTERM 信号执行并行(默认 30 秒)。因此,Kubernetes 不会等待这些完成。如果这段时间结束,则直接进入下一步。正确设置宽限期的值非常重要。
  5. 向 pod 发送 SIGKILL 信号,然后移除 pod。如果容器在宽限期后仍在运行,则 Pod 被 SIGKILL 强行移除,终止完成。

总结下大致分为两步,第一步定义 preStop,一般情况下可以休眠 30s,用于处理残余流量;第二步发送 SIGTERM 信号,服务收到信号后进行服务的收尾工作处理。比如:关闭连接、通知第三方注册中心服务关闭…..

Pods 生命周期的状态

phase表示一个Pod处于其生命周期的哪个阶段,一共有以下5个可能的取值:

  1. Pending:Pod已经被k8s系统接受,但Pod中还有容器没有被创建。Pod被调度前和下载容器镜像的时候都处于这个阶段
  2. Running:Pod已经被调度到Node上,所有的容器都已经被创建,并且至少有一个容器还在运行中(正在启动或重启中的容器也算)
  3. Succeeded:Pod中的所有容器都成功停止,并且不会再次重启
  4. Failed:Pod中的所有容器都已经停止,并且至少有一个容器是以失败停止的(以非0状态退出或被系统强制停止)
  5. Unknown:由于某种原因无法获得Pod的状态,一般是和Pod所在的Host出现通信问题导致

Pod phase的查看方式:

kubectl get pods whoami-78c854646d-nhgl9 -o yaml |grep 'phase:'

输出:

 phase: Running

k8s lifecycle 用法

lifecycle 周期有两个hook钩子 postStart 与 preStop

  1. PostStart hook是在容器创建(created)之后立马被调用,并且PostStart跟容器的ENTRYPOINT是异步执行的,无法保证它们之间的顺序.
  2. PreStop hook是容器处于Terminated状态时立马被调用(也就是说要是Job任务的话,执行完之后其状态为completed,所以不会触发PreStop的钩子),同时PreStop是同步阻塞的,PreStop执行完才会执行删除Pod的操作

注意:
PostStart 会阻塞容器成为Running状态,PreStop 会阻塞容器的删除,但是过了 terminationGracePeriodSeconds时间后,容器会被强制删除,
如果PreStop或者PostStart失败的话, 容器会被杀死;

钩子的回调函数支持三种方式定义动作:

  1. exec:在容器内执行命令,如果命令的退出状态码是 0 表示执行成功,否则表示失败
  lifecycle:
    postStart:
      exec:
        command:
        - cat
        - /tmp/healthy
  1. httpGet:向指定 URL 发起 GET 请求,如果返回的 HTTP 状态码在 [200, 400) 之间表示请求成功,否则表示失败
lifecycle:
    postStart:
      httpGet:
        path: /login   # URI地址
        port: 80  # 端口号
        host: 192.168.126.100 # 主机地址
        scheme: HTTP   # 支持的协议,http或https

# http://192.168.126.100:80/login
  1. TCPSocket:在容器尝试访问指定的socket
  lifecycle:
    postStart:
      tcpSocket:
        port: 8080

Example:

apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: nginx
  name: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: nginx
    spec:
      containers:
        - image: nginx
          name: nginx
          resources: {}
          lifecycle:
            postStart:
              exec:
                command: ["/bin/sh","-c","echo 11 >> /usr/share/nginx/html/index.html"]  # 启动容器应用之后执行
            preStop:
              exec:
                command: ["/bin/sh","-c","echo 'Hello from the preStop handler' >> /var/log/nginx/message"] ## 删除pod 完成之前执行
status: {}

文章作者: costalong
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 costalong !
评论
  目录
国庆
快乐