Kubernetes拦截pods/binding时偶发无法获取对应Pod的原因
问题根本原因
首先明确核心前提:你配置拦截的pods/binding子资源CREATE请求,是kube-scheduler完成调度决策后向apiserver发起的节点绑定请求,该请求触发时,目标Pod已经被持久化写入apiserver后端的etcd存储,不存在Pod真实不存在的情况。
偶发NotFound错误的核心原因和controller-runtime客户端的实现机制、K8s资源事件的同步链路有关:
- 你代码中使用的
p.Client是controller-runtime默认提供的缓存客户端,并非每次读请求都直连apiserver查etcd,而是优先读取本地Informer组件维护的内存缓存。 - 本地缓存的更新是完全异步的:Informer通过和apiserver建立的长连接Watch资源变更事件,再增量更新本地缓存。从Pod被写入etcd,到apiserver把Pod创建事件推送给webhook的Informer、再到Informer完成本地缓存更新,整个链路存在毫秒到百毫秒级的传输延迟。
- 偶发错误的典型触发场景:Pod刚写入etcd后,调度器很快完成调度逻辑并立刻发起binding请求,此时该Pod的创建事件还没同步到webhook的本地缓存,用缓存客户端查询就会返回NotFound;等很短一段时间后缓存同步完成,查询就能正常返回,这也是你添加重试机制后问题不再复现的核心原因。
- 服务部署阶段该错误更易触发:webhook新实例刚启动时,Informer还没完成全量资源的初始列表同步,本地缓存数据不完整,此时如果收到binding请求,也会大量返回NotFound错误。
额外优化建议
如果不想依赖重试机制规避问题,可以选择更稳定的实现方式:
- 调整webhook拦截规则,直接拦截核心组
v1版本pods资源的CREATE操作,准入请求体中会直接携带完整的Pod对象,不需要额外调用客户端查询,从根源上避免缓存不同步的问题。注意这种方式是在Pod持久化前执行修改,如果你添加的标签和调度策略(节点亲和、节点选择器等)相关,这个时机也比拦截binding更合理——拦截binding时调度决策已经完成,调度相关的配置修改不会再生效。 - 如果确实需要在binding阶段做逻辑,可以单独初始化一个直连apiserver的无缓存客户端,查询Pod时直接走强一致读请求,跳过本地缓存,也不会出现NotFound问题。
内容的提问来源于stack exchange,提问作者moluzhui
相关产品推荐
相关产品推荐

