☰
Popeye v0.3.10 新增 PodDisruptionBudget(PDB)可用性与配置检查实战指南
2026/10/15 20:46:26 网站建设 项目流程
  • 云原生
  • 运维
  • 可观测性

【免费下载链接】popeye

👀 A Kubernetes cluster resource sanitizer

项目地址:https://gitcode.com/gh_mirrors/po/popeye
点击查看免费下载

Popeye 是一款扫描 Kubernetes 生产集群、报告已部署资源配置问题的只读型集群消毒器(Cluster Sanitizer)。v0.3.10 版本的核心变化是:为 PodDisruptionBudget(PDB)新增了专门的 sanitizer 检查,在集群中存在 PDB 资源时,扫描器会报告其使用情况,并提示可能的错误配置。本文以该版本变更日志为主线,结合当前仓库源码,完整讲解 PDB 检查的判定逻辑、错误码体系、真实代码链路、测试验证方式,以及如何在 Spinach 配置中精确排除 PDB 检查,帮助你读懂并运用 Popeye 的 PDB 巡检能力。

一、版本背景与发布说明

v0.3.10 发布日志(对应仓库change_logs/release_v0.3.10.md)记录了该版本的两类信息:

  • 新增功能:为 PodDisruptionBudget 增加检查逻辑。原文表述为 "Added check for pbs",即扫描器在集群中存在 PodDisruptionBudget 资源时,会报告其使用情况(usage),并提示可能存在的错误配置(possible misconfiguration)。
  • 问题修复:修复了 Issue #34 与 Issue #21 两个缺陷。

说明:发布日志原文中 "PodDisruptionBugdet" 为拼写笔误,实际指 Kubernetes 的 PodDisruptionBudget 资源,下文统一使用 PDB。

当前仓库源码在 internal/glossary.go 中已将PDB定义为"poddisruptionbudgets",并在 internal/scrub/cache.go 中将NewPodDisruptionBudget注册为 PDB 资源的 scrubbing 入口,说明该检查在后续版本中持续保留并演进。

二、PDB 检查的整体工作流

Popeye 对每个资源类型的巡检遵循"预加载(Preload)→ 清扫(Scrub)→ 静态检查(Lint)"的三段式流水线。PDB 检查在源码中同样遵循该链路:

  1. 预加载:PodDisruptionBudget清扫器在其Preloads()中声明两类依赖资源——poddisruptionbudgets与pods(见 internal/scrub/pdb.go),即检查 PDB 时必须先把集群中的 Pod 数据也加载进内存数据库,才能做选择器匹配。
  2. 清扫:NewPodDisruptionBudget构造清扫器(见 internal/scrub/pdb.go),Lint方法先加载全部资源,再委托给 linter(见 internal/scrub/pdb.go)。
  3. 静态检查:internal/lint.PodDisruptionBudget逐条遍历内存数据库中的 PDB 对象,执行checkInUse使用性检查(见下文)。

从整体结构看,v0.3.10 引入的 PDB 检查属于"资源使用性(InUse)"类巡检:它的核心问题是"这个 PDB 真的在保护 Pod 吗?"——即 PDB 的spec.selector是否真的匹配到了集群中实际存在的 Pod。

三、核心检查逻辑:PDB 是否真正"在用"

PDB 检查的主入口位于 internal/lint/pdb.go:

// Lint cleanse the resource. func (p *PodDisruptionBudget) Lint(ctx context.Context) error { txn, it := p.db.MustITFor(internal.Glossary[internal.PDB]) defer txn.Abort() for o := it.Next(); o != nil; o = it.Next() { pdb := o.(*polv1.PodDisruptionBudget) fqn := client.FQN(pdb.Namespace, pdb.Name) p.InitOutcome(fqn) ctx = internal.WithSpec(ctx, SpecFor(fqn, pdb)) p.checkInUse(ctx, pdb) } return nil } func (p *PodDisruptionBudget) checkInUse(ctx context.Context, pdb *polv1.PodDisruptionBudget) { pp, err := p.db.FindPodsBySel(pdb.Namespace, pdb.Spec.Selector) if err != nil || len(pp) == 0 { p.AddCode(ctx, 900, dumpSel(pdb.Spec.Selector)) return } }

判定逻辑非常清晰:

  1. 遍历内存数据库中所有policy/v1版本的 PDB 对象(源码 import 了k8s.io/api/policy/v1);
  2. 对每个 PDB,调用db.FindPodsBySel在同一命名空间内按spec.selector查找匹配的 Pod;
  3. 如果FindPodsBySel返回错误(例如选择器为空、无 Pod 数据),或返回的 Pod 数量为 0,则上报错误码900,并附带dumpSel格式化后的选择器内容。

FindPodsBySel的底层实现在 internal/db/db.go:它会先校验选择器非空,再遍历数据库中的全部 Pod,过滤出命名空间一致且标签匹配选择器的对象。标签匹配由MatchSelector(见 internal/db/db.go)完成,它同时支持matchLabels(等值匹配,见MatchLabels)和matchExpressions(In、NotIn、Exists、DoesNotExist等集合操作,见matchExp/matchSel)两种选择器形式。

实战含义:如果集群中存在一个 PDB,但其spec.selector匹配不到任何运行中的 Pod(例如标签写错、Pod 已被清理、选择器正则过宽或过窄),Popeye 会将其标记为"未使用",并给出告警。这有助于发现"僵尸 PDB"——看似配置了中断预算、实则没有保护任何工作负载的失效资源。

选择器展示辅助函数

dumpSel用于把metav1.LabelSelector转为人类可读字符串,供错误消息展示,实现在 internal/lint/np.go(该函数被 PDB 与 NetworkPolicy 检查共用):

  • 对matchLabels,按key=value形式拼接(如app=p2);
  • 对matchExpressions,按key-operator-values形式拼接(如app-In-test1,test2);
  • 两类条件同时存在时以|分隔。

因此 900 号错误消息实际形如:

[POP-900] No pods match pdb selector: app=p2

四、PDB 相关的错误码体系

4.1 PDB 自身的错误码(900 / 901)

在 internal/issues/assets/codes.yaml 中定义了两个 PDB 错误码:

错误码消息模板severity(严重度)含义
900No pods match pdb selector: %s2PDB 未被使用,选择器匹配不到任何 Pod
901MinAvailable (%d) is greater than the number of pods(%d) currently running2minAvailable配置值大于当前运行的 Pod 数,保护能力配置错误

其中:

  • severity 2 对应 warn 级别。Popeye 在 internal/rules/level.go 中定义了Ok → Info → Warn → Error四级严重度,900/901 属于 Warn 警告,表示存在配置隐患而非立即致命的错误。
  • 代码 901 目前只在错误码字典中定义(internal/issues/assets/codes.yaml),对应变更日志中"报告可能的错误配置(possible misconfiguration)"的承诺;v0.3.10 实际落地的是 900 号"未使用"检查(checkInUse)。

4.2 Pod 视角的 PDB 关联检查(200/209)

PDB 检查不只存在于 PDB 自身的 linter 中,Pod linter 也会反向交叉检查 PDB 覆盖情况,二者共同构成完整的 PDB 保护面巡检:

  • 代码 206:No PodDisruptionBudget defined(severity 1,info 级别)——Pod 没有任何 PDB 保护。逻辑见 internal/lint/pod.go:Pod 检查时调用ForLabels在数据库中查找选择器能匹配该 Pod 标签的 PDB,找不到就报 206。
  • 代码 209:Pod is managed by multiple PodDisruptionBudgets (%s)(severity 2)——同一个 Pod 被多个 PDB 同时匹配,属于配置冲突。逻辑见checkForMultiplePdbMatches(internal/lint/pod.go):遍历所有 PDB,用metav1.LabelSelectorAsSelector将选择器转换为标准 selector 并逐一Matches该 Pod 标签,命中超过 1 个 PDB 时上报,并列出按字典序排序后的 PDB 名称列表。

因此,v0.3.10 引入的 PDB 巡检是一套"双视角"体系:

  • PDB 视角(900):PDB 的选择器是否匹配到 Pod(防僵尸 PDB);
  • Pod 视角(206 / 209):Pod 是否被 PDB 保护、是否被多个 PDB 重复保护(防保护缺失 / 保护冲突)。

五、真实测试用例:PDB 检查如何被验证

仓库在 internal/lint/pdb_test.go 中提供了 PDB 检查的完整测试,使用的测试数据位于 internal/lint/testdata/pol/pdb/1.yaml,其中定义了 5 个 PDB:

- apiVersion: policy/v1 kind: PodDisruptionBudget metadata: name: pdb1 namespace: default spec: minAvailable: 2 selector: matchLabels: app: p1 - apiVersion: policy/v1 kind: PodDisruptionBudget metadata: name: pdb2 namespace: default spec: minAvailable: 1 selector: matchLabels: app: p2

测试同时加载core/pod/1.yaml中的 Pod 数据,随后断言:

ii := pdb.Outcome()["default/pdb1"] assert.Equal(t, 0, len(ii)) // pdb1 的 selector 命中 Pod,无问题 ii = pdb.Outcome()["default/pdb2"] assert.Equal(t, 1, len(ii)) assert.Equal(t, `[POP-900] No pods match pdb selector: app=p2`, ii[0].Message) assert.Equal(t, rules.WarnLevel, ii[0].Level) // 900 属于 Warn 级别

可见:只有选择器真正命中 Pod 的 PDB(如pdb1)才会判定为正常(Outcome 为空),其余选择器失配的 PDB(pdb2、pdb3、pdb4、pdb4-1)全部上报 900 号 Warn 告警。这与变更日志"报告 PDB 使用情况"的描述完全一致,也印证了 v0.3.10 时代码的判定口径至今仍被测试用例锁定。

六、如何运行 PDB 检查与查看报告

PDB 检查随 Popeye 默认扫描自动启用,无需额外开关。运行方式与常规扫描一致(参见 README.md 的命令行说明):

# 使用当前 kubeconfig 环境扫描整个集群 popeye # 仅扫描指定命名空间 popeye -n fred # 扫描全部命名空间 popeye -A # 指定 kubeconfig 上下文 popeye --context olive # 只跑指定 linter(PDB 的资源名为 poddisruptionbudgets,别名 pdb) popeye -s poddisruptionbudgets

PDB 的 linter 资源名与别名在 README.md 的 Linters 清单中有明确记录:资源名poddisruptionbudgets,别名pdb。Popeye 的 linter 以 Kubernetes 资源复数形式命名,例如 PodDisruptionBudget linter 扫描的是policy/v1/poddisruptionbudgets(见 README.md)。

扫描结果会按资源 FQN(namespace/name形式,如default/pdb1)聚合展示,每条 Issue 包含错误码、消息与严重度。你可以选择控制台(Console)、JSON、HTML 等多种报告输出格式(仓库assets/screens/目录下分别提供了对应截图),也可以将扫描结果保存后分析 PDB 相关的 900/206/209 告警。

七、用 Spinach 配置精确控制 PDB 检查

Popeye 支持通过 Spinach YAML 配置文件(-f选项指定)精细控制各 linter 的行为,包括排除特定的资源或错误码。PDB 相关排除规则示例如下(配置文件语法参考 README.md):

# spinach.yaml popeye: excludes: # 全局排除:任何资源、任何 linter 都跳过 kube-system 等命名空间 global: fqns: [rx:^kube-] # 全局排除 PDB 相关的 900、206、209 错误码 codes: ["900", "206", "209"] # 按 linter 粒度配置 linters: # 仅对 poddisruptionbudgets linter 排除 900 号告警 poddisruptionbudgets: codes: ["900"]

配置要点:

  • FQN 排除:资源全限定名采用namespace/name形式,例如排除default/pdb1可写fqns: ["default/pdb1"];支持rx:前缀的正则匹配。
  • 错误码排除:可写死错误码("900")或使用正则("rx:^90"匹配 900、901 等)。global.codes对所有 linter 生效,linters.poddisruptionbudgets.codes仅对该 linter 生效。
  • 注意排除规则的"副作用":正则过宽可能连带排除其他资源,建议仅在明确需要时使用,并定期以"全开"方式运行 Popeye,避免因排除规则掩盖新出现的集群问题(README.md 有同样的提醒)。

八、从 v0.3.10 看 PDB 检查的演进脉络

  • v0.3.10 首次引入 PDB 检查,落地"PDB 是否被使用"(代码 900)的判定;
  • 后续版本的错误码字典进一步补充了901(minAvailable大于当前运行 Pod 数)与 Pod 视角的206、209,形成完整的双视角保护面检查;
  • 当前源码中 PDB 检查已稳定运行在policy/v1API 版本之上,且与 Pod、NetworkPolicy(共用dumpSel)等检查共享内存数据库基础设施,整体架构一致。

如果你正在治理集群中的 PDB 资源,建议把 900(僵尸 PDB)、206(无保护 Pod)、209(多重保护冲突)三类告警纳入例行巡检,结合 docs/codes.md 的完整错误码表,逐项收敛集群的中断预算配置风险。

相关资源

  • v0.3.10 发布日志
  • PDB linter 实现
  • PDB 清扫器实现
  • PDB 测试用例
  • PDB 测试数据
  • 错误码字典(900/901)
  • 错误码总表(PDB 章节)
  • Linters 清单与别名(pdb)
  • Spinach 配置说明
  • 云原生
  • 运维
  • 可观测性

【免费下载链接】popeye

👀 A Kubernetes cluster resource sanitizer

项目地址:https://gitcode.com/gh_mirrors/po/popeye
点击查看免费下载
上一篇:如何快速掌握英国生物银行数据分析:UKB_RAP完整入门指南
下一篇:微信聊天记录永久保存完全指南:3步实现数据自主管理

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询