GitOps流水线集成K8s调度优化同步窗口 - 第2节
Kubernetes 调度器工作原理与调度流程
Kubernetes 调度器(kube-scheduler)是控制平面的核心组件之一,负责将待调度的 Pod 绑定到最合适的 Node 上。调度器不负责创建 Pod,而是监听未调度的 Pod(spec.nodeName 为空),通过一系列调度算法选出目标节点,并将绑定结果写入 API Server。
调度器工作流程
调度过程分为两个阶段:过滤(Predicates / Filtering) 和 打分(Priorities / Scoring)。过滤阶段排除不满足条件的节点,打分阶段对剩余节点排序,选出最优节点。
核心调度流程: 调度器通过 Informer 机制监听 Pod 和 Node 变化,每次调度一个 Pod 时,先执行 Filtering 阶段,再执行 Scoring 阶段,最后将 Pod 与 Node 绑定。
- Pod 入队: 调度器通过 Informer 监听 API Server,发现未调度的 Pod 后将其加入调度队列。
- 过滤阶段(Filtering): 遍历所有 Node,应用预选策略(如资源充足、端口冲突、节点污点容忍等),生成候选节点列表。
- 打分阶段(Scoring): 对候选节点执行优先级函数(如资源利用率、Pod 亲和性、节点亲和性等),计算每个节点的综合得分。
- 绑定(Binding): 选择得分最高的节点,将 Pod 的
spec.nodeName设置为该节点,并通过 API Server 写入 etcd。 - 异步优化(可选): 调度器支持抢占调度(Preemption),当 Pod 无法调度时,可以抢占低优先级 Pod 的资源。
调度队列: Kubernetes 1.23+ 使用三种队列(activeQ、backoffQ、unschedulableQ)管理 Pod 调度状态,避免无效重试。
调度器架构图
下图展示了调度器内部组件与调度流程的交互关系:
NodeSelector:简单的节点选择器
nodeSelector 是 Kubernetes 提供的最简单的节点选择机制,通过 Pod 的 spec.nodeSelector 字段指定键值对,调度器只将 Pod 调度到包含所有指定标签的节点上。
使用方式
apiVersion: v1
kind: Pod
metadata:
name: nginx-selector
spec:
nodeSelector:
disktype: ssd
containers:
- name: nginx
image: nginx:1.25
上述 Pod 只会被调度到带有 disktype=ssd 标签的节点上。如果没有任何节点匹配,Pod 将保持 Pending 状态。
局限性:
nodeSelector 只支持精确匹配(AND 逻辑),不支持多条件组合、范围匹配或软约束。对于复杂调度需求,应使用 NodeAffinity。
NodeAffinity:灵活的节点亲和性调度
NodeAffinity 是 nodeSelector 的增强版,支持更丰富的匹配规则和调度策略。NodeAffinity 分为两种类型:
| 类型 | 字段 | 行为 | 调度阶段 |
|---|---|---|---|
| requiredDuringSchedulingIgnoredDuringExecution | required |
硬约束:必须满足规则才能调度,否则 Pod 保持 Pending | 过滤阶段 |
| preferredDuringSchedulingIgnoredDuringExecution | preferred |
软约束:调度器优先选择满足规则的节点,但不强制 | 打分阶段 |
NodeAffinity 匹配操作符
NodeAffinity 支持多种匹配操作符,满足不同场景的调度需求:
| 操作符 | 说明 | 示例 |
|---|---|---|
In |
标签值在指定集合中 | disktype In [ssd, nvme] |
NotIn |
标签值不在指定集合中 | region NotIn [us-east-1] |
Exists |
标签键存在(不关心值) | gpu-node Exists |
DoesNotExist |
标签键不存在 | spot-instance DoesNotExist |
Gt |
标签值大于指定数值(字符串比较) | memory-size Gt 32 |
Lt |
标签值小于指定数值 | cpu-cores Lt 8 |
NodeAffinity 配置示例
apiVersion: v1
kind: Pod
metadata:
name: nginx-affinity
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: topology.kubernetes.io/zone
operator: In
values:
- us-west-1a
- us-west-1b
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 80
preference:
matchExpressions:
- key: disktype
operator: In
values:
- ssd
- weight: 20
preference:
matchExpressions:
- key: environment
operator: In
values:
- production
containers:
- name: nginx
image: nginx:1.25
调度逻辑: 上述 Pod 必须调度到
us-west-1a 或 us-west-1b 可用区(硬约束),优先选择带有 disktype=ssd 标签的节点(权重 80),其次考虑 environment=production 标签(权重 20)。
NodeSelector 与 NodeAffinity 对比
| 特性 | NodeSelector | NodeAffinity |
|---|---|---|
| 匹配逻辑 | 精确键值对(AND) | 多条件组合(AND/OR),支持 In/NotIn/Exists 等 |
| 软约束 | 不支持 | 支持(preferred) |
| 权重 | 不支持 | 支持(weight 字段) |
| 范围匹配 | 不支持 | 支持(Gt/Lt) |
| 配置复杂度 | 低 | 中 |
| 适用场景 | 简单标签匹配 | 复杂调度策略、多维度约束 |
NodeAffinity 调度决策流程
下图展示了 NodeAffinity 在调度器中的决策路径:
最佳实践与注意事项
- 组合使用: 将
required用于硬性约束(如可用区、GPU 节点),preferred用于优化目标(如高性能磁盘、低负载节点)。 - 权重设计: 权重范围 1-100,多个 preferred 规则通过权重累加影响最终得分,权重越高优先级越大。
- 标签一致性: 确保 Node 标签与 Pod 的 NodeAffinity 规则一致,避免因标签缺失导致 Pod 无法调度。
- 性能考虑: 过多的 NodeAffinity 规则会增加调度器计算开销,建议将规则数量控制在 10 条以内。
- 与 Taint/Toleration 配合: NodeAffinity 控制 Pod 选择哪些节点,Taint/Toleration 控制哪些 Pod 可以进入节点,两者结合实现精细调度。
GitOps 场景提示: 在 GitOps 流水线中,NodeAffinity 规则通常定义在 Helm Chart 或 Kustomize 的 values 文件中,通过环境参数动态注入,实现多集群、多环境的差异化调度策略。