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 节点与普通节点在滚动升级中的差异化准入流程:

GPU 节点 vs 普通节点差异化准入流程 GPU 节点 vs 普通节点差异化准入流程 GPU 节点(nvidia.com/gpu.present=true) 普通 CPU 节点 步骤 1:校验 NVIDIA 驱动版本 ≥ 525 步骤 2:保留 nvidia-container-runtime 步骤 3:保留 10% 显存给系统进程 步骤 4:禁止驱逐 nvidia-device-plugin 步骤 5:保留 nvidia.com/gpu.present 标签 步骤 1:检查节点可达性 步骤 2:驱逐所有非关键 Pod 步骤 3:升级 kubelet 版本 步骤 4:清理临时标签 步骤 5:标记升级完成 说明:GPU 节点多出驱动校验、运行时保留、显存预留、DaemonSet 保护、标签保护 5 项差异化准入规则

在 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 标签 > 控制面标签 > 环境标签 > 默认规则。当节点同时携带多个标签时,按优先级最高的规则执行。