From a345f6e6b98399592b3b628e5d10bb9ea68f20a4 Mon Sep 17 00:00:00 2001 From: baim0 <9030674+baim0@user.noreply.gitee.com> Date: Tue, 2 Jun 2026 21:44:49 +0800 Subject: [PATCH] add k8sTrouble notes and .gitignore --- .gitignore | 1 + k8sTrouble/01 数据不一致问题.md | 48 +++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 .gitignore create mode 100644 k8sTrouble/01 数据不一致问题.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e43b0f9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.DS_Store diff --git a/k8sTrouble/01 数据不一致问题.md b/k8sTrouble/01 数据不一致问题.md new file mode 100644 index 0000000..53c8be3 --- /dev/null +++ b/k8sTrouble/01 数据不一致问题.md @@ -0,0 +1,48 @@ +--- +title: APIServer Cache 脏数据导致 Ghost Pod 仍在调度 +date: 2026-06-02 +tags: +- kubernetes排障 +categories: +- kubernetes排障 +--- + +## 问题现象 + +发现调度器仍在调度已不存在或早已下线的 Pod。Pod 实际已不存在(etcd 中无记录),但 kube-scheduler 组件重启后 list/watch 仍能获取到该 Pod 信息,疑似脏数据导致。 + +## 问题原因 + +根因是 **APIServer cache 与 etcd 数据不一致**: + +- 部分 APIServer 副本的 watch cache 数据是旧的(stale),导致 scheduler 通过 informer → watch → APIServer cache 这条链路一直能读到旧的 pending Pod 数据。 +- 调度器写 binding 走的是 **etcd quorum**(强一致性),所以写的时候拿到的是真值(404,Pod 已不存在)。 +- 调度器读 Pod 走的是 **informer → watch → APIServer cache**(最终一致性),所以读到的是 stale 数据。 + +> **读写两条路径不同步,这是 ghost Pod 的本质。** + +### 架构示意 + +``` +调度器 ──读 Pod──→ Informer ──Watch──→ APIServer Cache(stale ❌) +调度器 ──写 Binding──→ APIServer ──→ etcd Quorum(真实 ✅) +``` + +## 解决方案 + +### 短期:滚动重启异常 APIServer + +滚动重启缓存数据异常的 APIServer 副本即可恢复。重启后 watch cache 重建,与 etcd 数据重新同步。 + +### 长期:升级集群至 1.34+ + +Kubernetes 1.34 及以上版本默认开启 `KUBE_WATCHCACHE_CONSISTENCY_CHECKER` 功能,会定期检查 APIServer cache 与 etcd 之间的一致性,并在检测到不一致时自动修复(自愈),从根源上杜绝该类问题。 + +## 关键要点 + +| 链路 | 一致性模型 | 结果 | +| ------ | --------------- | -------------- | +| 读 Pod | APIServer Cache | 可能读到 stale | +| 写 Pod | etcd Quorum | 始终为真实值 | + +排查此类问题时,核心思路是:**对比 informer 侧拿到的数据与直接查 etcd/APIServer 的结果是否一致**,若不一致,则高度怀疑 watch cache 脏数据。 \ No newline at end of file