Schedule 总结


kube-scheduler 是 kubernetes 集群的默认调度器,官方允许用户根据自己的需求编写特定的调度器来替换 kube-scheduler。kube-scheduler 通过以下 2 个步骤来实现对 Pod 的调度:

  1. 过滤,根据 Pod 定义的条件,如"required"强制限制节点 label 匹配,以及限制 Pod 必须满足某些条件,对于podAffinity可以有多个labelSelector等条件,对于nodeAffinity只能是一个,但是可用多个matchExpressions等条件
  2. 打分,根据 Pod 定义的nodeAffinitypodAffinity,以及nodeAntiAffinitypodAntiAffinity等"preferred"偏好条件,以及weight打分(weight 数值越高,Pod 越有可能被调度到对应条件的节点上)

可用的过滤条件

  1. 节点标签:如 kubernetes.io/hostname, kubernetes.io/os
  2. 节点隔离/限制:如NodeRestriction插件使用的带有node-restriction.kubernetes.io前缀的标签
  3. .spec.affinity.nodeAffinity
  4. .spec.affinity.podAffinity.spec.afffinity.podAntiAffinity,以及.spec.affinity.podAffinity.[].topologyKey集群用来标识域的节点标签键
  5. namespaceSelector (v1.29 alpha)
  6. .spec.nodeName 有一些局限性,这个条件不稳定
    1. 如节点不存在,Pod 无法运行,在某些情况下可能被自动删除
    2. 在云环境中的节点名称并总不是可预测与稳定的
    3. 当然节点没有对应的资源运行该 Pod,仍然会失败,这个条件在非.spec.nodeName情况都满足,只不过非.spec.nodeName条件 Pod 部署不一定会失败,有可能是处于pending

可选的方式

  1. requiredDuringSchedulingIgnoredDuringExecution 硬性条件,强制限制
  2. preferredDuringSchedulingIgnoredDuringExecution 软性条件,偏好限制,有更好,没有也可以,该方式是一个数组,可以提供weight(越大越优先)来加强或减弱某个条件

可用的选项

  1. nodeAffinity
    1. nodeSelectorTerms
  2. podAffinitypodAntiAffinity
    1. matchLabelKeys
    2. mismatchLabelKeys
    3. topologyKey
    4. labelSelector

可用的操作符

操作符 行为 适用对象
In 标签值匹配提供的字符串集 nodeAffinity, podAffinity, podAntiAffinity
NotIn 标签值不匹配提供的字符串集 nodeAffinity, podAffinity, podAntiAffinity
Exists 存在具有此键的标签 nodeAffinity, podAffinity, podAntiAffinity
DoesNotExist 不存在具有此键的标签 nodeAffinity, podAffinity, podAntiAffinity
Gt 标签的值 > 该数 nodeAffinity
Lt 标签的值 < 该数 nodeAffinity

调度方案

  1. 逐个调度方案中设置nodeAffinity,需要在调度适配器启用NodeAffinity 插件

    apiVersion: kubescheduler.config.k8s.io/v1beta3
    kind: KubeSchedulerConfiguration
    
    profiles:
      - schedulerName: default-scheduler
      - schedulerName: foo-scheduler
        pluginConfig:
          - name: NodeAffinity
            args:
              addedAffinity:
                requiredDuringSchedulingIgnoredDuringExecution:
                  nodeSelectorTerms:
                    - matchExpressions:
                        - key: scheduler-profile
                          operator: In
                          values:
                            - foo
    

Pod 调度就绪状态 (v1.27 beta)

通过指定.spec.schedulingGates可以控制 Pod 何时准备好被考虑调度。如果 Pod 已经就绪,可以将对应的字段清空,然后对 Pod 执行更新操作。如果指定了该字段,有以下情况允许,更新对应字段:

  1. 如果设置了该字段,在没有.spec.nodeSelector的情况下,可以允许更新此字段
  2. 如果spec.affinity.nodeAffinity为 nil,则允许设置任意值
  3. 如果NodeSelectorTerms之前没有设置,则现在允许设置;如果之前已经设置了,那么仅允许添加对应的条目,不允许更新之前已经存在的条目
  4. 对于preferredDuringSchedulingIgnoredDuringExecution,所有更新现在都允许

可以使用scheduler_pending_pods{queue="gated"}查看调度的具体指标情况。需结合一些指标组件,如metric-server

Pod 拓扑分布域

分布域是一个类似组的概念对集群中的节点进行分组,按区域划分,使整个大的集群有一定的抗风险与自愈能力。.spec.topologySpreadConstraints定义了对集群可用区使用的调度规则,使用该功能最重要的要求是如果集群自动为节点打的标签无法满足需求,用户需要自定义标签的时候,需要保证集群所有的 key 的一致性,否则调度结果可能会匪夷所思,排查也会很困难。

---
apiVersion: v1
kind: Pod
metadata:
  name: example-pod
spec:
  # 配置一个拓扑分布约束
  topologySpreadConstraints: # 多个条目之间是逻辑与关系,默认无特别说明都是逻辑与
    - maxSkew: <integer>
      minDomains: <integer> # 可选;自从 v1.25 开始成为 Beta
      topologyKey: <string>
      whenUnsatisfiable: <string>
      labelSelector: <object>
      matchLabelKeys: <list> # 可选;自从 v1.27 开始成为 Beta
      nodeAffinityPolicy: [Honor|Ignore] # 可选;自从 v1.26 开始成为 Beta
      nodeTaintsPolicy: [Honor|Ignore] # 可选;自从 v1.26 开始成为 Beta
  ...
  1. maxSkew 描述这些 Pod 可能被不均匀分布的程度,具体受制于
    1. whenUnsatisfiable: DoNotSchedule 描述可用区分布 Pod 数量最小值的差值
    2. whenUnsatisfiable: ScheduleAnyway 该调度器会更为偏向能够降低偏差值的拓扑域
  2. minDomains 表示符合条件的域的最小数量
  3. topologyKey 节点标签 key
  4. whenUnsatisfiable: DoNotSchedule(default), ScheduleAnyway
  5. labelSelector 用于查找匹配的 Pod
  6. matchLabelKeys 用于选择需要计算分布方式的 Pod 集合,matchLabelKeyslabelSelector不允许有相同的 key
  7. nodeAffinityPolicy: Honor, Ignore
  8. nodeTaintsPolicy: Honor, Ignore

隐式约定

  1. 只有与新来的 Pod 具有相同命名空间的 Pod 才能作为匹配候选者
  2. 调度器会忽略没有任何 topologySpreadConstraints[*].topologyKey 的节点,意味着这些节点上的 Pod 不会影响maxSkew的计算
  3. topologySpreadConstraints[*].labelSelector与 Pod 自身的标签不匹配,将不会改善集群的不平衡程度

集群级别的默认约束

apiVersion: kubescheduler.config.k8s.io/v1beta3
kind: KubeSchedulerConfiguration
profiles:
  - schedulerName: default-scheduler
    pluginConfig:
      - name: PodTopologySpread
        args:
          defaultConstraints:
            - maxSkew: 1
              topologyKey: topology.kubernetes.io/zone
              whenUnsatisfiable: ScheduleAnyway
          defaultingType: List

为集群设置默认的拓扑约束,可以在以下条件满足时被应用到 Pod 上:

  1. Pod 没有在其 .spec.topologySpreadConstraints 中定义任何约束
  2. Pod 隶属于某个 Service、ReplicaSet、StatefulSet 或 ReplicationController

内置的默认约束 (v1.24 stable)

defaultConstraints: # 可以被用户覆写
  - maxSkew: 3
    topologyKey: "kubernetes.io/hostname"
    whenUnsatisfiable: ScheduleAnyway
  - maxSkew: 5
    topologyKey: "topology.kubernetes.io/zone"
    whenUnsatisfiable: ScheduleAnyway

已知的局限 (截止 v1.29.3)

  1. 当缩减某个控制器控制的 Pod 时,现阶段的方案无法保证 Pod 分布均衡
  2. 具有污点的节点上匹配的 Pod 也会被统计
  3. 任何情况下至少保证每个拓扑域(节点组)中至少有一个可用节点,否则调度可能会异常