Kubernetes中Pod终止信号量详解

本文深入解析Kubernetes删除Pod时的信号量机制,详细阐述SIGTERM与SIGKILL的区别、容器优雅终止与强制终止的流程,以及Pod生命周期的管理策略。

这篇文章已发布 726 天,部分内容可能已过时。如有疑问,可在评论区留言。

K8s 删除一个 Pod 生命周期

删除一个容器在 Kubernetes 中涉及到以下几个步骤和概念。具体来说,容器的生命周期管理是由 Pod 和控制器(如 Deployment、ReplicaSet 等)来处理的。我们可以通过 Kubernetes 中的 kubectl delete 命令删除 Pod 或容器,具体行为会根据使用的资源类型有所不同。

删除一个容器的过程

假设你执行了以下命令删除一个 Pod(容器是 Pod 中的一个或多个进程):

1
kubectl delete pod <pod-name>

在执行此命令时,发生的过程如下:

  • Pod 调度管理: Kubernetes 中的控制器(如 Deployment 或 ReplicaSet)会监控与 Pod 相关的副本数,并确保运行的 Pod 数量符合期望。如果你删除了一个 Pod,而副本数设置为大于 1(比如 Deployment 中的副本数为 3),控制器会自动创建一个新的 Pod 来替代被删除的 Pod。

    如果副本数设置为 1,且没有额外的控制器来管理 Pod,那么该 Pod 被删除后不会自动重建,除非你手动调整副本数。

  • 容器终止: 当你删除一个 Pod 时,Kubernetes 会向 Pod 内运行的容器发送终止信号(SIGTERM),这意味着容器会有一段时间来执行清理操作。默认情况下,容器会有 30 秒的时间来处理清理操作和释放资源。

  • 容器的强制终止: 如果容器在 30 秒内没有停止,它会被强制终止(发送 SIGKILL 信号)。

  • Pod 删除: 一旦容器被终止,Pod 本身会被从集群中删除,并且相关的资源(如卷)也会被清理或重新挂载,具体取决于使用的卷类型。

  • 资源清理: 删除的容器会释放它所使用的资源(如 CPU、内存、网络连接等)。如果容器使用了挂载卷(如 Persistent Volumes),这些卷的清理行为也会根据其 ReclaimPolicy 和类型(如 RetainDelete)决定。

容器生命周期的管理

Kubernetes 中的容器生命周期通常由 Pod 控制,而 Pod 的生命周期是一个由创建、运行、终止等状态组成的过程。

Pod 生命周期

  • Pending: Pod 被调度到节点上,但是其中的容器尚未运行。通常是因为容器镜像需要拉取,或者资源调度未完成。
  • Running: 容器正在运行,Pod 正在执行。
  • Succeeded: 所有容器都成功终止,Pod 的生命周期结束。
  • Failed: 某个容器非正常退出(比如通过返回码 1 或其他非零退出状态)并且无法重新启动,Pod 进入 Failed 状态。
  • Unknown: 无法获取 Pod 的状态,通常是节点故障或网络问题引起的。

容器生命周期

容器的生命周期是由 Pod 控制的,但你可以在 Pod 配置中通过 lifecycle 钩子自定义容器的生命周期行为。包括:

  • PreStop: 在容器终止之前调用,可以用于执行清理工作,比如关闭网络连接、保存临时数据等。
  • PostStart: 在容器启动后调用,可以用于执行初始化任务。

具体生命周期示例

  1. Pod 创建:
    • Pod 被创建,容器开始启动。
    • 容器开始拉取镜像并启动。
    • 在启动过程中,容器会执行 PostStart 钩子(如果配置了)。
  2. Pod 运行:
    • 容器运行过程中提供服务。
    • 在运行期间,容器和其他资源保持活跃。
  3. Pod 删除:
    • 当你删除 Pod 时,Kubernetes 向容器发送 SIGTERM 信号,请求容器正常关闭。
    • 如果容器在规定时间内没有退出,则发送 SIGKILL 强制终止容器。
    • 删除后,Pod 资源被清理(包括网络和卷资源),并且容器和 Pod 进入终止状态。
  4. 容器退出:
    • 容器退出时,它的退出状态码会记录。若退出码为 0,则视为成功,否则为失败。
    • 根据 Pod 配置,容器退出后,Kubernetes 可能会重新启动该容器(如果定义了重启策略,如 Always)。

重启策略与副本数

  • Always(默认): 如果容器崩溃或被删除,Kubernetes 会尝试重新启动容器。
  • OnFailure: 容器只有在异常退出时(返回非零退出码)才会被重启。
  • Never: 容器不会自动重启,退出后将永久停止。

总结

当你删除一个容器时,Kubernetes 会尝试按照以下步骤来管理 Pod 和容器的生命周期:

  1. 容器优雅关闭: 发送 SIGTERM,允许容器优雅退出(默认 30 秒)。
  2. 强制终止: 如果容器在指定时间内没有退出,则发送 SIGKILL 强制停止容器。
  3. Pod 删除: 容器停止后,Pod 资源会被清理。
  4. 控制器行为: 如果 Pod 是由 Deployment 或 ReplicaSet 管理的,控制器会确保 Pod 数量符合预期,必要时会创建新的 Pod 来替代已删除的 Pod。

如果副本数为 1,删除 Pod 后不会自动创建新的 Pod,除非手动修改副本数或重新创建资源。

容器正常终止和强制终止

在 Kubernetes 中,容器的终止有两个主要阶段:容器正常终止(Graceful Termination)和容器强制终止(Forced Termination)。这两者的区别主要体现在 Kubernetes 如何处理容器的退出过程,以及容器退出时是否能有机会进行清理操作。

容器正常终止(Graceful Termination)

当你删除一个 Pod 或者容器时,Kubernetes 会首先尝试以一种优雅的方式终止容器,这通常被称容器正常终止**(Graceful Termination)**。

  • 发送 SIGTERM 信号: 当 Kubernetes 请求终止容器时,它会向容器发送一个 SIGTERM(终止信号)。这时,容器可以捕捉到该信号并开始进行正常的关闭操作。

    容器可以在接收到 SIGTERM 后执行一系列操作,比如:

    • 关闭网络连接。
    • 清理占用的资源(例如文件句柄、临时数据等)。
    • 执行自定义的关闭逻辑(例如数据库提交、日志记录等)。
  • Grace Period(宽限期): 在接收到 SIGTERM 信号后,容器会有一个“宽限期”来完成这些清理工作。默认情况下,这个宽限期为 30 秒,但你可以在 Pod 配置文件中通过 terminationGracePeriodSeconds 字段来调整这个时间。

  • 正常退出: 如果容器在宽限期内正常退出(即,执行了清理操作并退出),Kubernetes 会将容器状态标记为 SucceededTerminated,Pod 会根据终止策略进行后续处理(如删除或重新调度)。

容器强制终止(Forced Termination)

如果容器没有在宽限期内正常退出,Kubernetes 会进行强制终止。这意味着容器没有完成清理操作或未响应终止请求时,Kubernetes 会采取更强硬的措施来终止容器。

  • 发送 SIGKILL 信号: 如果容器没有在 terminationGracePeriodSeconds 指定的时间内优雅地终止,Kubernetes 会发送 SIGKILL(强制杀死信号)来立即停止容器。与 SIGTERM 不同,SIGKILL 信号无法被捕获或处理,因此容器无法执行任何清理操作。
  • 立即终止: 当容器收到 SIGKILL 信号后,它会被立即停止,所有正在运行的进程会被杀死。这意味着容器的进程没有机会释放资源(如文件句柄、临时存储等),并且可能会留下未清理的状态。
  • 无法清理资源: 容器在强制终止时没有机会进行任何的清理操作,可能会导致一些资源(例如临时文件、内存、数据库连接等)没有正确释放。

容器正常终止与强制终止的区别

特性 正常终止(Graceful Termination) 强制终止(Forced Termination)
信号 SIGTERM SIGKILL
清理时间 容器有机会进行清理,默认为 30 秒(可配置) 没有清理时间,立即终止
终止操作 容器可以捕获 SIGTERM,执行清理操作 容器无法捕获 SIGKILL,直接强制终止
资源释放 容器能够释放资源(如文件句柄、数据库连接等) 容器无法释放资源,可能会泄漏资源
容器状态 容器可以正常退出,状态为 Succeeded 或 Terminated 容器强制停止,状态为 Terminated
发生场景 容器运行正常,接收到删除请求时的正常处理 容器没有在宽限期内退出或没有响应请求

Pod 配置中如何控制容器终止行为

你可以在 Pod 的配置文件中设置 terminationGracePeriodSeconds 来控制容器的宽限期。默认情况下,这个值是 30 秒,但你可以根据需要进行修改。

1
2
3
4
5
6
7
8
9
apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  terminationGracePeriodSeconds: 60  # 设置容器的优雅终止宽限期为 60 秒
  containers:
    - name: mycontainer
      image: myimage

容器生命周期钩子(Lifecycle Hooks)

Kubernetes 还提供了 lifecycle 钩子,允许你在容器的启动和停止过程中插入自定义行为,特别是在容器终止时执行额外操作:

  • PreStop: 在容器终止之前执行,你可以使用此钩子来执行一些清理操作,或者发送通知等操作。例如,停止某个外部服务的连接或关闭数据库连接。

示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
    - name: mycontainer
      image: myimage
      lifecycle:
        preStop:
          exec:
            command: ["sh", "-c", "echo 'Container is stopping' > /tmp/shutdown.log"]

总结

  • 容器正常终止: Kubernetes 会通过发送 SIGTERM 信号请求容器优雅退出,容器有机会进行清理操作并释放资源,通常会在宽限期内完成。
  • 容器强制终止: 如果容器没有在宽限期内正常退出,Kubernetes 会发送 SIGKILL 信号强制停止容器,容器无法进行任何清理操作,立即停止并释放资源。

通过合理配置 Pod 的宽限期和生命周期钩子,你可以控制容器的终止行为,并确保在容器退出时尽量避免资源泄漏和服务中断。

SIGTERM 和 SIGKILL

SIGTERMSIGKILL 是两种常用的 Unix/Linux 信号,它们都用于向进程发送终止请求,但它们的作用、行为和后果是不同的。以下是对这两种信号的详细介绍:

SIGTERM (Signal Terminate) - 信号终止

  • 编号: 15

  • 作用: SIGTERM 是一种请求进程终止的信号。它通知进程优雅地退出,即让进程有时间完成清理工作、保存状态和释放资源。此信号是终止进程的默认信号。

  • 发送方式: 你可以使用 kill 命令发送 SIGTERM 信号,或者在程序中使用 kill(pid, SIGTERM) 来发送信号。

    示例:

1
  kill <pid>  # 默认发送 SIGTERM 信号
  • 特点:

    • SIGTERM 允许进程进行优雅的退出,它可以被进程捕获并处理。
    • 进程可以在接收到 SIGTERM 后执行清理操作,例如关闭数据库连接、保存临时数据、关闭文件句柄等。
    • 如果进程捕捉到 SIGTERM,它可以执行必要的清理工作后正常退出。
    • 如果进程没有响应 SIGTERM,操作系统会默认等待一段时间(通常是 30 秒),然后发送 SIGKILL
  • 响应方式:

    • 进程可以选择捕捉并处理 SIGTERM,比如通过注册一个信号处理函数。
    • 进程也可以选择忽略 SIGTERM,但如果它未在规定时间内退出,操作系统将发送 SIGKILL
  • 应用场景:

    • 当你希望让进程有机会进行清理操作后退出时使用,例如关闭网络连接、保存数据、日志记录等。
    • 在 Kubernetes 或 Docker 中,当你删除一个容器时,系统会首先发送 SIGTERM 请求容器优雅地停止。

SIGKILL (Signal Kill) - 信号强制终止

  • 编号: 9

  • 作用: SIGKILL 是一个强制终止进程的信号,直接要求操作系统停止目标进程,而不允许进程处理任何清理操作。它是无法被捕捉、忽略或处理的

    示例:

1
  kill -9 <pid>  # 发送 SIGKILL 信号
  • 特点:

    • SIGKILL 是强制终止进程的信号,进程无法进行任何清理操作。
    • 无论进程是否响应,操作系统都会立刻终止进程,释放其占用的资源。
    • 进程无法捕获或忽略 SIGKILL 信号,它会立即将进程从内存中移除。
    • 发送 SIGKILL 信号后,进程不会有机会关闭文件、释放内存、写入日志或执行其他必要的清理操作。
  • 应用场景:

    • 当进程无法正常响应 SIGTERM 或已经挂起(例如卡死或进入无限循环时),使用 SIGKILL 来强制终止进程。
    • 在操作系统中,SIGKILL 用于终止无响应的或僵尸进程,确保它们被完全清理。

对比:SIGTERM 与 SIGKILL

特性 SIGTERM (15) SIGKILL (9)
作用 请求进程优雅退出,允许进程处理清理操作 强制终止进程,无法被进程捕获或处理
是否可以捕捉/处理 可以被进程捕捉,进程可以自定义终止逻辑 无法捕捉或处理,进程立刻被终止
优雅退出 允许进程进行资源清理、关闭文件、保存数据等 进程立刻被终止,不执行任何清理操作
是否能被忽略 可以被进程忽略(如果没有捕捉 SIGTERM 信号) 不能被忽略或处理,强制终止
默认行为 系统通常等待进程在指定时间内退出(默认30秒) 立即终止进程,不等待
应用场景 需要优雅关闭进程、释放资源、保存状态等 强制终止无法退出的进程,或进程无法响应 SIGTERM
操作系统行为 操作系统等待进程在规定时间内退出 操作系统立即杀死进程,释放所有资源

Kubernetes 中的 SIGTERM 和 SIGKILL

在 Kubernetes 中,当你删除一个 Pod 或容器时,Kubernetes 会首先向容器发送 SIGTERM 信号,要求容器的主进程优雅地退出。容器内的进程有一定的时间(默认30秒)来响应 SIGTERM 并执行清理操作。如果容器在这个宽限期内没有正常退出,Kubernetes 会发送 SIGKILL 来强制终止容器。这个过程的目标是确保尽量让容器优雅关闭,但如果它无法响应,则使用强制方式来终止。

SIGTERM 信号

  • 发送对象: 容器内的主进程。

  • 行为: 容器运行时,会有一个主进程(通常是容器启动时定义的 CMDENTRYPOINT 进程)。当 Kubernetes 请求停止容器时,它会向容器的主进程发送 SIGTERM 信号。SIGTERM 是一个优雅的终止信号,意味着容器内的进程应当处理它,进行清理操作,并正常退出。

  • 容器内的行为: 容器的主进程有机会捕捉到 SIGTERM 信号,并在适当的时间内执行清理操作,例如:

    • 关闭数据库连接。
    • 保存日志文件或持久数据。
    • 清理临时文件或缓存。

    容器可以通过捕捉信号并在接收到 SIGTERM 后执行自定义的终止逻辑(例如通过生命周期钩子 PreStop)。

  • 宽限期(Grace Period): Kubernetes 默认给容器主进程 30 秒(可以配置)来优雅地关闭。如果容器内的进程在这个时间内没有退出,Kubernetes 将会发送 SIGKILL 信号,强制终止容器。

SIGKILL 信号

  • 发送对象: 容器内的进程(主进程或任何其他进程)。
  • 行为: SIGKILL 是一个无法被捕获或忽略的信号。它会直接杀死容器内的进程,且不允许容器内的进程进行任何清理操作。当容器在 SIGTERM 信号后的宽限期内没有正常退出时,Kubernetes 会发送 SIGKILL 来强制终止容器内的进程。
    • 容器内进程行为: 容器内的进程在接收到 SIGKILL 信号时,会立即停止,无法做任何清理工作。所有的文件句柄、网络连接、数据库事务等可能都会被中断,导致资源没有正常释放。
  • 容器的终止: 因为容器内的进程已经被强制终止,容器也会结束生命周期。此时,Pod 控制器(如 Deployment 或 ReplicaSet)会根据副本数重新调度新的容器。

容器与进程的关系

  • 在 Kubernetes 中,容器实际上是一个运行时环境,封装了一些进程(通常只有一个主进程)。当我们讨论容器的启动、停止或重启时,实际上是指管理容器内的进程的生命周期。
  • 当 Kubernetes 发送 SIGTERMSIGKILL 时,它是对容器内的进程发出的信号,而不是直接发给容器本身。容器本身并没有执行的代码或进程,它只是一个运行时环境,容器内的进程才是处理这些信号的对象。

容器内的进程如何响应 SIGTERM 和 SIGKILL

  • 响应 SIGTERM 容器内的进程可以捕捉到 SIGTERM 信号。容器主进程可以通过代码逻辑来处理这个信号,进行清理操作或释放资源。

    例如,如果容器中运行的是一个 HTTP 服务器进程,它可能会在接收到 SIGTERM 后,停止接受新请求并优雅地完成当前正在处理的请求,然后退出。

    示例代码(Python):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
  import signal
  import time
  
  def graceful_shutdown(signum, frame):
      print("Received SIGTERM, shutting down gracefully...")
      # 执行清理操作,比如关闭数据库连接、清理缓存等
      time.sleep(2)  # 模拟清理工作
      exit(0)
  
  signal.signal(signal.SIGTERM, graceful_shutdown)
  
  print("Running... Press CTRL+C to exit.")
  while True:
      time.sleep(1)
  • 响应 SIGKILL 容器内的进程无法捕捉或处理 SIGKILL 信号。SIGKILL 信号直接杀死进程,容器中的进程会立即退出,没有机会进行清理操作。

    在接收到 SIGKILL 时,进程不会有时间保存状态或清理资源,系统会立即终止进程,且无法进行任何形式的恢复。

总结

  • SIGTERM: 是一个优雅的请求,允许进程清理资源并优雅地退出。如果进程在规定时间内没有退出,操作系统会发送 SIGKILL
  • SIGKILL: 是一个强制终止的信号,进程无法响应或捕捉,进程会被立即终止,无法进行任何清理工作。

这两种信号是 Unix/Linux 系统管理中常用的信号,理解它们的作用和行为可以帮助你更有效地管理进程的生命周期,尤其是在容器化环境(如 Kubernetes)和自动化运维中。

SIGTERMSIGKILL 信号,虽然在 Kubernetes 中通常是通过容器管理的,但它们实际上是发给 容器内运行的进程 的信号,而不是直接发送给容器本身。容器是一个包含一个或多个进程的运行环境,因此,容器中的进程是这些信号的实际接收者。

  • SIGTERM 信号 发送给容器中的进程,允许它们优雅地退出并执行清理操作。如果容器内的进程在一定时间内(默认为 30 秒)没有退出,Kubernetes 会发送 SIGKILL
  • SIGKILL 信号 也是发送给容器内的进程,但它是无法被捕捉或忽略的,容器内的进程会被立即强制终止,并且不会有机会执行任何清理操作。

最终,容器作为运行时环境,管理的是容器内的进程,因此容器的生命周期管理依赖于容器内进程如何响应这些信号。

面朝大海,春暖花开。
使用 Hugo 构建
主题 StackJimmy 设计