如何判断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的状态,判断是否因删除导致终止:
配置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。
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的操作。示例配置:
这种方式更可靠,不需要依赖Pod的信号捕获逻辑,确保在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}}'"]
内容的提问来源于stack exchange,提问作者Mahesh Prakash
相关产品推荐
相关产品推荐

