浅析Kubernetes健康检查与优雅终止

目录

Pod探针

livenessProbe(存活检查)

readinessProbe(就绪检查)

startupProbe(启动检查)

支持的三种检查方法

minReadySeconds

示例Yaml

Hook钩子

postStart 钩子

preStop 钩子

terminationGracePeriodSeconds

示例Yaml


        在 Kubernetes 生态中,容器的生命周期管理和应用的优雅上下线至关重要。Kubernetes 通过 Pod 探针和生命周期钩子等机制,为容器提供了精细的健康监测和状态管理能力。Pod 探针确保只有处于健康状态的容器能够服务请求,而生命周期钩子则在容器启动和终止时执行定制化操作,从而实现应用的平滑启动和优雅终止。这些机制共同保障了应用的稳定运行和数据一致性,是 Kubernetes 高效管理容器化应用不可或缺的工具。

Pod探针

        Kubernetes中提供了三种Pod探针类型,用于确保容器的健康状态和可用性

livenessProbe(存活检查)

        存活检查用于判断容器是否存活。如果检查失败,Kubernetes将杀死容器,并根据Pod的restartPolicy来决定是否重启容器。

readinessProbe(就绪检查)

        就绪检查用于判断容器是否已经准备好接受请求。如果检查失败,Kubernetes会将Pod从Service的endpoints中移除,不再将请求转发给该Pod。这在应用启动时需要加载大量数据或配置文件,或者依赖外部服务的情况下特别有用。就绪检查是周期性运行的。

startupProbe(启动检查)

        启动检查用于保护慢启动的容器,如nacos、mysql等。它会周期性地检查容器,直到第一次成功响应。一旦成功响应,Kubernetes将认为应用已启动成功,并开始进行就绪检查和存活检查。如果提供了启动探针,则所有其他探针都会被禁用,直到此探针成功为止一旦成功响应,Kubernetes 将认为应用已启动成功,并开始进行 Readiness 和 Liveness 探针的检查。如果容器没有提供启动探测,则默认状态为 Success

健康检查的执行顺序为:startupProbe -> readinessProbelivenessProbe

支持的三种检查方法

  • httpGet:发送HTTP请求,返回200-400范围内的状态码视为成功。
  • exec:执行Shell命令,返回状态码为0视为成功。
  • tcpSocket:发起TCP Socket连接,建立成功视为成功。

minReadySeconds

readinessProbe参数 - minReadySeconds

        默认情况下,一旦新创建的Pod变成就绪状态,Kubernetes就会认为该Pod可用,并将旧的Pod删除。但有时问题可能会在新Pod真正处理用户请求时才暴露。因此,一个更稳健的做法是在新Pod就绪后对其观察一段时间再删除旧的Pod。如果配置了readinessProbe,则观察时间为readinessProbe消耗时间 + minReadySeconds

示例Yaml

  1. startupProbe使用HTTP GET请求/healthz路径来进行启动检查。如果连续30次检查失败(failureThreshold: 30),则认为容器启动失败。检查间隔为10秒(periodSeconds: 10)。

  2. readinessProbe使用TCP Socket连接来进行就绪检查。在容器启动5秒后开始第一次检查(initialDelaySeconds: 5),之后每5秒检查一次(periodSeconds: 5)。

  3. livenessProbe使用exec执行命令cat /tmp/healthy来进行存活检查。在容器启动10秒后开始第一次检查(initialDelaySeconds: 10),之后每5秒检查一次(periodSeconds: 5)。

  4. minReadySeconds设置为30,表示新Pod就绪后至少观察30秒再认为其可用。

  5. terminationGracePeriodSeconds设置为60,表示在收到停止请求后,容器有最多60秒的时间进行优雅关闭。

apiVersion: v1
kind: Pod
metadata:
  name: health-check-demo
spec:
  containers:
  - name: my-app
    image: my-app:v1
    ports:
    - containerPort: 8080
    startupProbe:  # 启动检查
      httpGet:
        path: /healthz
        port: 8080
      failureThreshold: 30  # 失败阈值,最多重试30次
      periodSeconds: 10     # 检查间隔,每10秒检查一次
    readinessProbe:  # 就绪检查
      tcpSocket:
        port: 8080
      initialDelaySeconds: 5  # 延迟5秒后开始第一次检查
      periodSeconds: 5        # 检查间隔,每5秒检查一次
    livenessProbe:   # 存活检查
      exec:
        command:
        - cat
        - /tmp/healthy
      initialDelaySeconds: 10  # 延迟10秒后开始第一次检查
      periodSeconds: 5         # 检查间隔,每5秒检查一次
    minReadySeconds: 30  # 新Pod就绪观察时间,至少30秒
  terminationGracePeriodSeconds: 60  # 优雅关闭宽限期,最多60秒


Hook钩子

        Kubernetes 提供了两种容器生命周期钩子,用于在容器启动后和终止前执行特定的操作:postStart 和 preStop。

postStart 钩子

        postStart 钩子在容器启动后执行,适用于需要在容器启动后进行初始化的场景。postStart 不能保证钩子在容器的 ENTRYPOINT 和 CMD 之前运行。

应用场景

  • 初始化配置文件:在容器启动后,可以使用 postStart 钩子从配置管理系统(如 Consul、etcd)中获取最新的配置文件,并将其写入容器内的指定位置,以确保应用程序使用最新的配置。

  • 注册服务:对于微服务架构,可以在容器启动后使用 postStart 钩子将服务实例注册到服务发现系统(如 Eureka、Zookeeper),以便其他服务能够发现和调用该服务。

  • 初始化缓存:在容器启动后,可以使用 postStart 钩子预先加载常用数据到内存缓存(如 Redis),以提高应用程序的性能和响应速度。

preStop 钩子

     preStop 钩子是 Kubernetes 在终止容器前立即调用的一个机制,其主要目的是为了使应用程序能够优雅地关闭,同时也能够向其他系统发送必要的通知。这个钩子的执行是同步进行的,这意味着在 Kubernetes 发起删除容器的操作之前,preStop 钩子里的任务必须全部执行完毕。如果这个钩子在执行过程中出现了挂起的情况,那么相关的 Pod 将会一直保持在 Running 状态,并不会转变为 Failed 状态。

        在使用 preStop 钩子时,有一点需要特别注意:它与 SIGTERM 信号的处理是异步的,即 Kubernetes 在发送 SIGTERM 信号后,不会等待 preStop 钩子的执行完成。因此,在设计 preStop 钩子时,开发者需要考虑到 preStop 钩子的执行可能会与处理 SIGTERM 信号的逻辑同时进行。为了避免在终止过程中出现未完成的操作和潜在的数据丢失,开发者应确保 preStop 钩子中的所有操作都能在 terminationGracePeriodSeconds 指定的宽限期内完成如果容器因为崩溃等原因异常终止,preStop 钩子将不会被触发执行

应用场景

  • 关闭长连接:对于使用长连接的应用程序(如 WebSocket),可以在容器终止前使用 preStop 钩子优雅地关闭这些连接,以避免客户端出现连接中断的问题。

  • 刷新缓存到持久化存储:在容器终止前,可以使用 preStop 钩子将内存中的缓存数据刷新到持久化存储(如数据库),以确保数据的一致性和持久性。

  • 通知依赖服务:在微服务架构中,当一个服务实例即将终止时,可以使用 preStop 钩子通知依赖该服务的其他服务,以便它们能够及时更新服务调用的目标地址,避免出现服务不可用的情况。

  • 上传调试信息:在容器终止前,可以使用 preStop 钩子收集和上传应用程序的调试信息(如内存快照、线程转储等)到调试平台,以便开发人员进行问题排查和性能优化。

支持的两种方式

  • Exec:通过执行容器内的命令来触发操作。这种方式是直接在容器内部执行指定的 shell 命令或脚本。当使用 exec 方式时,需要提供一个命令(可能带有参数),Kubernetes 会在容器内部环境中执行这个命令。例如,可以使用 exec 方式在容器启动后初始化一些数据,或者在容器停止前清理临时文件。

  • HTTP Get:通过发送 HTTP GET 请求到容器的某个端口上的指定路径。这种方式适用于触发容器内部的 Web 服务接口,如健康检查端点或其他 RESTful API。使用 HTTP Get 方式时,需要指定请求的路径和端口,Kubernetes 会向该路径发送一个 HTTP GET 请求。如果请求成功,即视为操作成功完成。

terminationGracePeriodSeconds

  terminationGracePeriodSeconds 参数指定了从 Kubernetes 发送 SIGTERM 信号给 Pod 开始,到 Kubernetes 强制结束 Pod 为止的时间窗口长度。这个时间段允许 Pod 有序地进行关闭流程,包括执行 preStop 钩子里定义的任务。系统默认的 terminationGracePeriodSeconds 时间为 30 秒。

        如果 Pod 在执行 preStop 钩子的过程中,如关闭数据库连接或者完成正在处理的请求,所需时间超过了 terminationGracePeriodSeconds 所设定的时间,那么 Kubernetes 将不会等待 preStop 钩子执行完毕,Pod 将会在 preStop 钩子完成之前被强制终止。这可能会导致应用程序的不稳定和数据的不一致性。因此设置一个合理的terminationGracePeriodSeconds 值尤为重要!

示例Yaml

postStart 和 preStop 钩子可以在 Kubernetes 的 Pod 配置中的 spec.containers.lifecycle 字段中定义。可以指定在容器启动后(postStart)或终止前(preStop)执行的操作。这些操作可以是执行命令(exec)或发送 HTTP 请求(httpGet)。

        在这个例子中,在MySQL 容器的生命周期中使用 postStart 和 preStop 钩子执行特定的操作,如初始化数据库、导出数据和优雅地关闭 MySQL 进程:

  1. postStart 钩子

    • 在 MySQL 容器启动后,通过 exec 执行一系列 MySQL 命令。
    • 首先,使用 mysqladmin 创建一个名为 mydb 的数据库。
    • 然后,使用 mysql 命令将 /init-data.sql 文件中的 SQL 语句导入到 mydb 数据库中,用于初始化数据。
    • /init-data.sql 文件通过 ConfigMap 挂载到容器中。
  2. preStop 钩子

    • 在 MySQL 容器终止前,通过 exec 执行一系列 MySQL 命令。
    • 首先,使用 mysqldump 将 mydb 数据库的数据导出到 /final-data.sql 文件中,用于持久化数据。
    • 然后,使用 mysql 命令执行 STOP SLAVE; 语句,停止 MySQL 复制进程(如果有的话)。
    • /final-data.sql 文件通过 emptyDir 卷挂载到容器中,用于临时存储导出的数据。
apiVersion: v1
kind: Pod
metadata:
  name: mysql-with-lifecycle
spec:
  containers:
  - name: mysql
    image: mysql:5.7
    env:
    - name: MYSQL_ROOT_PASSWORD
      value: "password"
    ports:
    - containerPort: 3306
    lifecycle:
      postStart:
        exec:
          command:
          - /bin/bash
          - -c
          - |
            # 在容器启动后执行的操作
            # 1. 创建名为 mydb 的数据库
            mysqladmin -uroot -p$MYSQL_ROOT_PASSWORD create mydb
            # 2. 将 /init-data.sql 文件中的 SQL 语句导入到 mydb 数据库中
            mysql -uroot -p$MYSQL_ROOT_PASSWORD mydb < /init-data.sql
      preStop:
        exec:
          command:
          - /bin/bash
          - -c
          - |
            # 在容器终止前执行的操作
            # 1. 将 mydb 数据库的数据导出到 /final-data.sql 文件中
            mysqldump -uroot -p$MYSQL_ROOT_PASSWORD mydb > /final-data.sql
            # 2. 停止 MySQL 复制进程(如果有的话)
            mysql -uroot -p$MYSQL_ROOT_PASSWORD -e "STOP SLAVE;"
    volumeMounts:
    - name: init-data
      mountPath: /init-data.sql
      subPath: init-data.sql
    - name: final-data
      mountPath: /final-data.sql
      subPath: final-data.sql
  volumes:
  - name: init-data
    configMap:
      name: mysql-init-data
  - name: final-data
    emptyDir: {}

  • 36
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值