Kubernetes中如何区分新Pod部署与副本集、扩缩容等其他场景?
Mutation Webhook 区分新Deployment与其他Pod创建场景的实现方案
核心逻辑
你要处理的Pod创建请求本身不直接关联Deployment,需要通过所有者引用链溯源+ 自定义标记的方式做判断,完全可以通过client-go的corev1、apps v1包实现。
具体实现步骤
- 第一步:校验Pod的所有者层级
直接读取Pod结构体的pod.ObjectMeta.OwnerReferences字段:- 先确认Pod的直接所有者是
apps/v1版本的ReplicaSet,排除直接通过ReplicaSet、DaemonSet、Job等资源创建的Pod - 再读取对应ReplicaSet的
OwnerReferences,确认其上层所有者是apps/v1版本的Deployment,否则直接跳过处理逻辑
- 先确认Pod的直接所有者是
- 第二步:判断是否为首次创建的新Deployment
最稳妥的方案是给已经处理过的Deployment加自定义注解标记,避免重复处理:- 读取溯源得到的Deployment对象,检查是否携带自定义注解(比如
your-webhook.io/processed: "true") - 如果无该注解,说明是首次触发的新Deployment,正常执行Pod补丁逻辑,完成后给当前Deployment写入上述自定义注解
- 如果已经有该注解,说明是已处理过的Deployment触发的扩缩容、滚动更新等场景,直接跳过补丁
- 读取溯源得到的Deployment对象,检查是否携带自定义注解(比如
- 第三步:规避边界问题
- Webhook对应的ServiceAccount需要提前配置Deployment的
get、update权限 - 给Deployment打标记时要加乐观锁重试逻辑,避免多个Pod并发请求时的更新冲突
- 可以额外加判断条件做兜底:溯源得到的ReplicaSet的
deployment.kubernetes.io/revision注解值为1,且Deployment的创建时间与ReplicaSet的创建时间差小于10秒,进一步降低误判概率
- Webhook对应的ServiceAccount需要提前配置Deployment的
核心代码示例(基于client-go)
import ( "context" "encoding/json" corev1 "k8s.io/api/core/v1" appsv1 "k8s.io/api/apps/v1" "sigs.k8s.io/controller-runtime/pkg/client" admissionv1 "k8s.io/api/admission/v1" ) func handleMutation(ctx context.Context, req admissionv1.AdmissionRequest, k8sClient client.Client) admissionv1.AdmissionResponse { // 解析请求中的Pod对象 pod := &corev1.Pod{} if err := json.Unmarshal(req.Object.Raw, pod); err != nil { return allowResponse() } // 溯源找所属ReplicaSet var rsName string for _, owner := range pod.OwnerReferences { if owner.APIVersion == "apps/v1" && owner.Kind == "ReplicaSet" { rsName = owner.Name break } } if rsName == "" { return allowResponse() } // 拿ReplicaSet对象溯源找Deployment rs := &appsv1.ReplicaSet{} if err := k8sClient.Get(ctx, client.ObjectKey{Name: rsName, Namespace: pod.Namespace}, rs); err != nil { return allowResponse() } var deployName string for _, owner := range rs.OwnerReferences { if owner.APIVersion == "apps/v1" && owner.Kind == "Deployment" { deployName = owner.Name break } } if deployName == "" { return allowResponse() } // 检查Deployment是否已经处理过 deploy := &appsv1.Deployment{} if err := k8sClient.Get(ctx, client.ObjectKey{Name: deployName, Namespace: pod.Namespace}, deploy); err != nil { return allowResponse() } if deploy.Annotations != nil && deploy.Annotations["your-webhook.io/processed"] == "true" { return allowResponse() } // 执行你的Pod补丁逻辑 patchBytes := generatePodPatch(pod) // 给Deployment打处理标记 if deploy.Annotations == nil { deploy.Annotations = make(map[string]string) } deploy.Annotations["your-webhook.io/processed"] = "true" if err := k8sClient.Update(ctx, deploy); err != nil { // 按需添加重试逻辑,避免并发更新冲突 } return patchResponse(patchBytes) }
注:allowResponse、generatePodPatch、patchResponse为webhook框架自带或自定义的通用方法,可根据你使用的框架替换
内容的提问来源于stack exchange,提问作者Lior Kesten
相关产品推荐
相关产品推荐

