You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何判断Pod是否因StatefulSet删除而终止?(使用client-go)

区分Pod终止原因(StatefulSet删除 vs 其他)及StatefulSet状态查询方案

StatefulSet的自身状态说明

StatefulSet有自身的状态信息,核心分为两部分:

  • Status字段:包含副本状态统计,比如Replicas(期望副本数)、ReadyReplicas(就绪副本数)、CurrentReplicas(当前运行的旧版本副本数)等,用于跟踪控制器的副本管理状态。
  • 删除状态标识:判断StatefulSet是否正在被删除,关键看metadata.deletionTimestamp字段——当执行删除操作后,K8s会给该字段赋值一个时间戳,直到资源完全清理完成前这个字段都会存在。

你用kubectl describe statefulset看不到删除状态的话,可以用kubectl get statefulset <sts-name> -o yaml直接查看metadata.deletionTimestamp是否存在。

实现Pod仅在StatefulSet删除时触发操作的方案

方案1:Pod内通过client-go查询StatefulSet删除状态

在Pod捕获SIGTERM后,通过client-go查询所属StatefulSet的状态,判断是否因删除导致终止:

  1. 配置RBAC权限:给Pod绑定的ServiceAccount添加读取StatefulSet的权限,示例ClusterRole:

    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
      name: sts-reader
    rules:
    - apiGroups: ["apps"]
      resources: ["statefulsets"]
      verbs: ["get"]
    

    再将该ClusterRole绑定到Pod所在命名空间的ServiceAccount。

  2. Pod内逻辑实现:
    从环境变量获取当前Pod的名称和命名空间(需要在Pod模板中注入POD_NAME和POD_NAMESPACE环境变量),然后通过OwnerReferences找到所属的StatefulSet,查询其是否存在deletionTimestamp,或者是否已被删除(404状态)。

    核心代码片段:

    import (
        "context"
        "fmt"
        "os"
        "k8s.io/apimachinery/pkg/api/errors"
        "k8s.io/client-go/kubernetes"
        "k8s.io/client-go/rest"
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    )
    
    func isStatefulSetBeingDeleted() (bool, error) {
        // 加载集群内client配置
        config, err := rest.InClusterConfig()
        if err != nil {
            return false, err
        }
        clientset, err := kubernetes.NewForConfig(config)
        if err != nil {
            return false, err
        }
    
        // 获取当前Pod的名称和命名空间
        podName := os.Getenv("POD_NAME")
        podNS := os.Getenv("POD_NAMESPACE")
        if podName == "" || podNS == "" {
            return false, fmt.Errorf("missing POD_NAME or POD_NAMESPACE env var")
        }
    
        // 获取Pod对象
        pod, err := clientset.CoreV1().Pods(podNS).Get(context.TODO(), podName, metav1.GetOptions{})
        if err != nil {
            return false, err
        }
    
        // 查找所属的StatefulSet
        var stsName string
        for _, ref := range pod.OwnerReferences {
            if ref.Kind == "StatefulSet" {
                stsName = ref.Name
                break
            }
        }
        if stsName == "" {
            return false, fmt.Errorf("pod has no StatefulSet owner")
        }
    
        // 查询StatefulSet状态
        sts, err := clientset.AppsV1().StatefulSets(podNS).Get(context.TODO(), stsName, metav1.GetOptions{})
        if err != nil {
            // 如果StatefulSet已被删除,返回404,此时可判定是删除导致Pod终止
            if statusErr, ok := err.(*errors.StatusError); ok && statusErr.ErrStatus.Code == 404 {
                return true, nil
            }
            return false, err
        }
    
        // 检查是否存在删除时间戳
        return sts.DeletionTimestamp != nil, nil
    }
    

    在SIGTERM信号处理函数中调用这个方法,返回true时执行对服务端StatefulSet的特定操作。

方案2:使用StatefulSet的PreDelete钩子主动触发操作

如果不需要Pod内的判断逻辑,可以在客户端StatefulSet中配置PreDelete钩子,在删除Pod前先执行操作:

  • 直接在StatefulSet的lifecycle.preDelete中执行命令,或者启动一个Job来完成服务端StatefulSet的操作。示例配置:
    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      name: client-statefulset
    spec:
      replicas: 3
      template:
        metadata:
          labels:
            app: client
        spec:
          serviceAccountName: client-sa
          containers:
          - name: client-container
            image: your-image:tag
      lifecycle:
        preDelete:
          exec:
            command: ["/bin/sh", "-c", "kubectl patch statefulset server-sts -n default --type merge -p '{\"spec\":{\"replicas\":0}}'"]
    
    这种方式更可靠,不需要依赖Pod的信号捕获逻辑,确保在StatefulSet删除流程初期就执行目标操作。

内容的提问来源于stack exchange,提问作者Mahesh Prakash

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 05:40:26