Deployment删除后Pod仍在,因默认Foreground级联策略仅先打deletionTimestamp并等待ReplicaSet和Pod逐级终止,实际清理需时间;后台删除用Background策略可异步释放。

直接调用 Delete 方法不等于资源已消失,尤其对 Deployment、Namespace 等含控制器逻辑的资源,必须区分“API 删除请求发出”和“实际清理完成”两个阶段。
Deployment 删除后 Pod 还在?检查 PropagationPolicy
默认 DeleteOptions{} 使用 Foreground 级联策略:先打上 deletionTimestamp,再等 ReplicaSet 和 Pod 逐级终止。若你删完就走,常看到旧 Pod 仍在 Running 或 Terminating。
-
metav1.DeletePropagationBackground:立即返回,后台异步删子资源(ReplicaSet + Pod),适合 CI/CD 中快速释放命名空间上下文 -
metav1.DeletePropagationForeground:阻塞直到所有依赖资源进入 Terminating 状态(但不保证它们已被删除) - 别用
metav1.DeletePropagationOrphan除非你明确要孤立子资源——这会导致残留 Pod 成为“孤儿”,且不再受 Deployment 控制
示例:
deleteOption := metav1.DeleteOptions{
PropagationPolicy: &metav1.DeletePropagationBackground,
}
err := clientset.AppsV1().Deployments("myns").Delete(context.TODO(), "my-deploy", deleteOption)
Namespace 卡在 Terminating 怎么办
这是最典型的 finalizer 陷阱。调用 clientset.CoreV1().Namespaces().Delete() 后,Namespace 进入 Terminating 状态,但不会自动消失——它在等所有 metadata.finalizers 被 controller 清除。
- 先查 finalizer:
kubectl get ns my-ns -o yaml,看metadata.finalizers列表,常见有kubernetes(内置)、kubernetes.io/pv-protection(PV 挂载未解绑)、example.com/my-finalizer(自定义) - 不要直接 patch 掉 finalizer——绕过 controller 可能导致 PV 未释放、LB 未解绑、etcd 数据残留
- 若确认 controller 已停机且下游已手动清理(如手动删除了关联 PVC、解绑了 Service),才执行 patch:
clientset.CoreV1().Namespaces().Patch(context.TODO(), "my-ns", types.JSONPatchType, []byte(`[{"op":"remove","path":"/metadata/finalizers"}]`), metav1.PatchOptions{})
用 dynamic 客户端删任意资源(包括 CRD)
Typed 客户端(如 AppsV1().Deployments())只能操作预编译的资源类型;遇到 CRD 或未来版本新增资源,就得切 dynamic 客户端。
- 关键三要素:
schema.GroupVersionResource(GVR)、unstructured.Unstructured对象、dynamic.Interface - 删 CRD 实例时,GVR 必须严格匹配该 CRD 的
spec.group、spec.version、spec.names.kind小写复数形式(如myapps.example.com/v1/myresources) - dynamic.Delete 不支持
PropagationPolicy参数,所有级联行为由对应 controller 决定,无法强制 background
示例(删一个自定义资源):
gvr := schema.GroupVersionResource{
Group: "example.com",
Version: "v1",
Resource: "myresources",
}
dynamicClient.Resource(gvr).Namespace("myns").Delete(context.TODO(), "my-instance", metav1.DeleteOptions{})
删完就认为“干净了”?轮询才是唯一可靠手段
Kubernetes 的声明式语义决定了:API Server 返回成功 ≠ 资源已从集群中消失。特别是带 finalizer 的资源,或被多个 controller 共同管理的对象(如 Istio VirtualService + Gateway),状态收敛可能延迟数秒甚至更久。
- 对 Namespace:轮询
Get,直到返回404 NotFound或对象存在但DeletionTimestamp != nil且后续若干次 Get 都返回 404 - 对 Deployment:不能只看是否存在,要确认
Status.ObservedGeneration == Generation且Status.AvailableReplicas == Spec.Replicas才算真正 Ready;删除后则需等Get返回 404 - 超时时间建议 ≥ 30s:image pull、node 压力、controller 队列积压都可能导致延迟
最容易被忽略的是:很多脚本在 Delete 后直接 Create 同名资源,结果因旧资源尚未彻底退出,新资源创建失败(如 namespace 名冲突、deployment generation 冲突)。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











