4. 差异化准入核心思想:为什么需要差异化、场景分析
在 Kubernetes 节点滚动升级过程中,“一刀切”的准入策略往往导致运维事故或资源浪费。生产节点与测试节点、GPU 节点与普通 CPU 节点,对升级窗口、安全基线、资源预留的要求截然不同。差异化准入的核心思想是:根据节点角色、负载类型、安全等级,动态注入不同的策略规则,使 Policy as Code 从“全集群统一”进化为“按需适配”。
4.1 为什么需要差异化准入
统一准入策略在以下场景中暴露出严重缺陷:
| 问题 | 统一策略表现 | 差异化策略优势 |
|---|---|---|
| 升级窗口冲突 | 生产节点与测试节点同时触发升级 | 生产节点仅在维护窗口内准入,测试节点随时可升级 |
| 安全基线过严 | GPU 节点因驱动加载被 Pod Security Standards 拦截 | GPU 节点豁免特权容器检查,普通节点保持严格限制 |
| 资源预留失效 | 所有节点统一预留 5% 资源,GPU 节点显存溢出 | GPU 节点按显存比例预留,CPU 节点按内存比例预留 |
| 标签污染 | 升级后节点标签被覆盖,导致调度器无法识别节点类型 | 保留关键标签(如 gpu-type、env),仅清理临时标签 |
核心结论:差异化准入不是增加复杂度,而是将策略与节点元数据(标签、注解、资源容量)绑定,使 Policy as Code 具备上下文感知能力。
4.2 场景一:生产 vs 测试节点
生产节点与测试节点在升级容忍度、安全要求、回滚策略上存在本质差异。下表列出关键对比维度:
| 维度 | 生产节点 | 测试节点 |
|---|---|---|
| 升级窗口 | 仅允许 02:00-05:00(UTC) | 全天候允许 |
| 最大不可用节点数 | ≤ 1 个(或 10%) | ≤ 50% |
| Pod 安全标准 | 强制执行 Restricted 级别 | 允许 Baseline 级别 |
| 升级前检查 | 必须通过健康检查 + 备份验证 | 仅检查节点可达性 |
| 回滚策略 | 自动回滚 + 告警 | 手动回滚 |
差异化准入通过节点标签 env=production 或 env=staging 来区分策略路径。例如,在 Kyverno 中,使用 preconditions 字段匹配标签:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: node-upgrade-window
spec:
rules:
- name: production-window
match:
any:
- resources:
kinds:
- Node
selector:
matchLabels:
env: production
preconditions:
all:
- key: "{{ request.object.metadata.annotations['upgrade.time'] }}"
operator: NotIn
value:
- "02:00-05:00"
validate:
message: "生产节点升级仅允许在 02:00-05:00 UTC 窗口内进行。"
deny: {}
- name: staging-anytime
match:
any:
- resources:
kinds:
- Node
selector:
matchLabels:
env: staging
validate:
message: "测试节点升级无时间限制。"
patched: true
实践建议:生产节点建议额外绑定
node-role.kubernetes.io/control-plane 标签,控制面节点升级策略应比工作节点更保守。
4.3 场景二:GPU 节点 vs 普通节点
GPU 节点承载 AI/ML 训练任务,对驱动版本、显存隔离、NVIDIA 容器运行时有特殊要求。普通节点则运行通用微服务。差异化准入需要处理以下关键差异:
| 维度 | GPU 节点 | 普通 CPU 节点 |
|---|---|---|
| 驱动兼容性 | 升级前必须校验 NVIDIA 驱动版本 ≥ 525 | 无驱动依赖 |
| 容器运行时 | 必须保留 nvidia-container-runtime | 仅需 containerd |
| 显存预留 | 升级后保留 10% 显存给系统进程 | 无显存概念 |
| Pod 调度 | 禁止驱逐 nvidia-device-plugin DaemonSet | 允许驱逐所有非关键 Pod |
| 标签保护 | 保留 nvidia.com/gpu.present=true | 无特殊标签保护 |
以下 SVG 图展示了 GPU 节点与普通节点在滚动升级中的差异化准入流程:
在 Policy as Code 实现中,GPU 节点的差异化准入通常通过 nodeSelectorTerms 或 matchExpressions 来触发:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: gpu-node-protection
spec:
rules:
- name: protect-gpu-driver
match:
any:
- resources:
kinds:
- Node
selector:
matchExpressions:
- key: nvidia.com/gpu.present
operator: In
values:
- "true"
validate:
message: "GPU 节点升级前必须校验 NVIDIA 驱动版本 ≥ 525。"
deny:
conditions:
any:
- key: "{{ request.object.status.nodeInfo.kubeletVersion }}"
operator: NotEquals
value: "v1.28.0" # 示例版本
- name: preserve-gpu-labels
mutate:
patchStrategicMerge:
metadata:
labels:
nvidia.com/gpu.present: "true" # 强制保留
注意:GPU 节点升级时,如果驱逐了
nvidia-device-plugin DaemonSet,新节点将无法识别 GPU 设备,导致所有 GPU Pod 处于 Pending 状态。差异化准入必须包含对该 DaemonSet 的保护规则。
4.4 差异化准入的决策矩阵
综合以上场景,差异化准入的决策逻辑可以抽象为以下矩阵:
| 节点特征标签 | 升级窗口 | 安全基线 | 资源预留 | 标签保护 |
|---|---|---|---|---|
env=production |
02:00-05:00 UTC | Restricted | 5% 内存 | 保留 env、node-role |
env=staging |
全天候 | Baseline | 3% 内存 | 仅保留 env |
nvidia.com/gpu.present=true |
02:00-05:00 UTC | Baseline(豁免特权) | 10% 显存 | 保留所有 nvidia.* 标签 |
node-role.kubernetes.io/control-plane |
04:00-06:00 UTC | Restricted | 10% 内存 | 保留所有标签 |
关键设计原则:差异化准入的规则优先级为:GPU 标签 > 控制面标签 > 环境标签 > 默认规则。当节点同时携带多个标签时,按优先级最高的规则执行。