kube-scheduler

    调度器需要充分考虑诸多的因素:

    • 公平调度
    • 资源高效利用
    • QoS
    • affinity 和 anti-affinity
    • 数据本地化(data locality)
    • 内部负载干扰(inter-workload interference)
    • deadlines

    有三种方式指定 Pod 只运行在指定的 Node 节点上

    • nodeSelector:只调度到匹配指定 label 的 Node 上
    • nodeAffinity:功能更丰富的 Node 选择器,比如支持集合操作
    • podAffinity:调度到满足条件的 Pod 所在的 Node 上

    首先给 Node 打上标签

    然后在 daemonset 中指定 nodeSelector 为 disktype=ssd

    1. spec:
    2. nodeSelector:
    3. disktype: ssd

    nodeAffinity 目前支持两种:requiredDuringSchedulingIgnoredDuringExecution 和 preferredDuringSchedulingIgnoredDuringExecution,分别代表必须满足条件和优选条件。比如下面的例子代表调度到包含标签 kubernetes.io/e2e-az-name 并且值为 e2e-az1 或 e2e-az2 的 Node 上,并且优选还带有标签 another-node-label-key=another-node-label-value 的 Node。

    1. apiVersion: v1
    2. kind: Pod
    3. metadata:
    4. name: with-node-affinity
    5. spec:
    6. affinity:
    7. nodeAffinity:
    8. requiredDuringSchedulingIgnoredDuringExecution:
    9. nodeSelectorTerms:
    10. - matchExpressions:
    11. - key: kubernetes.io/e2e-az-name
    12. operator: In
    13. values:
    14. - e2e-az1
    15. - e2e-az2
    16. preferredDuringSchedulingIgnoredDuringExecution:
    17. - weight: 1
    18. preference:
    19. matchExpressions:
    20. - key: another-node-label-key
    21. operator: In
    22. values:
    23. - another-node-label-value
    24. containers:
    25. - name: with-node-affinity
    26. image: gcr.io/google_containers/pause:2.0

    podAffinity 基于 Pod 的标签来选择 Node,仅调度到满足条件 Pod 所在的 Node 上,支持 podAffinity 和 podAntiAffinity。这个功能比较绕,以下面的例子为例:

    • 如果一个 “Node 所在 Zone 中包含至少一个带有 security=S1 标签且运行中的 Pod”,那么可以调度到该 Node
    • 不调度到 “包含至少一个带有 security=S2 标签且运行中 Pod” 的 Node 上
    1. apiVersion: v1
    2. kind: Pod
    3. metadata:
    4. name: with-pod-affinity
    5. spec:
    6. affinity:
    7. podAffinity:
    8. requiredDuringSchedulingIgnoredDuringExecution:
    9. - labelSelector:
    10. matchExpressions:
    11. - key: security
    12. operator: In
    13. - S1
    14. topologyKey: failure-domain.beta.kubernetes.io/zone
    15. preferredDuringSchedulingIgnoredDuringExecution:
    16. - weight: 100
    17. podAffinityTerm:
    18. labelSelector:
    19. matchExpressions:
    20. - key: security
    21. operator: In
    22. values:
    23. - S2
    24. topologyKey: kubernetes.io/hostname
    25. containers:
    26. - name: with-pod-affinity
    27. image: gcr.io/google_containers/pause:2.0

    Taints 和 tolerations

    Taints 和 tolerations 用于保证 Pod 不被调度到不合适的 Node 上,其中 Taint 应用于 Node 上,而 toleration 则应用于 Pod 上。

    目前支持的 taint 类型

    • NoSchedule:新的 Pod 不调度到该 Node 上,不影响正在运行的 Pod
    • PreferNoSchedule:soft 版的 NoSchedule,尽量不调度到该 Node 上
    • NoExecute:新的 Pod 不调度到该 Node 上,并且删除(evict)已在运行的 Pod。Pod 可以增加一个时间(tolerationSeconds),

    比如,假设 node1 上应用以下几个 taint

    下面的这个 Pod 由于没有 toleratekey2=value2:NoSchedule 无法调度到 node1 上

    1. tolerations:
    2. - key: "key1"
    3. operator: "Equal"
    4. value: "value1"
    5. effect: "NoSchedule"
    6. - key: "key1"
    7. operator: "Equal"
    8. value: "value1"
    9. effect: "NoExecute"

    而正在运行且带有 tolerationSeconds 的 Pod 则会在 600s 之后删除

    1. tolerations:
    2. - key: "key1"
    3. operator: "Equal"
    4. value: "value1"
    5. effect: "NoSchedule"
    6. - key: "key1"
    7. operator: "Equal"
    8. value: "value1"
    9. effect: "NoExecute"
    10. tolerationSeconds: 600
    11. - key: "key2"
    12. operator: "Equal"
    13. value: "value2"
    14. effect: "NoSchedule"

    注意,DaemonSet 创建的 Pod 会自动加上对 node.alpha.kubernetes.io/unreachablenode.alpha.kubernetes.io/notReady 的 NoExecute Toleration,以避免它们因此被删除。

    优先级调度

    从 v1.8 开始,kube-scheduler 支持定义 Pod 的优先级,从而保证高优先级的 Pod 优先调度。并从 v1.11 开始默认开启。

    在指定 Pod 的优先级之前需要先定义一个 PriorityClass(非 namespace 资源),如

    1. apiVersion: v1
    2. kind: PriorityClass
    3. metadata:
    4. name: high-priority
    5. value: 1000000
    6. globalDefault: false
    7. description: "This priority class should be used for XYZ service pods only."

    其中

    • 为 32 位整数的优先级,该值越大,优先级越高
    • globalDefault 用于未配置 PriorityClassName 的 Pod,整个集群中应该只有一个 PriorityClass 将其设置为 true

    如果默认的调度器不满足要求,还可以部署自定义的调度器。并且,在整个集群中还可以同时运行多个调度器实例,通过 podSpec.schedulerName 来选择使用哪一个调度器(默认使用内置的调度器)。

    1. apiVersion: v1
    2. kind: Pod
    3. metadata:
    4. name: nginx
    5. labels:
    6. app: nginx
    7. spec:
    8. # 选择使用自定义调度器 my-scheduler
    9. schedulerName: my-scheduler
    10. containers:
    11. - name: nginx
    12. image: nginx:1.10

    调度器的示例参见 这里

    调度器扩展

    kube-scheduler 还支持使用 --policy-config-file 指定一个调度策略文件来自定义调度策略,比如

    1. "kind" : "Policy",
    2. "apiVersion" : "v1",
    3. "predicates" : [
    4. {"name" : "PodFitsHostPorts"},
    5. {"name" : "PodFitsResources"},
    6. {"name" : "NoDiskConflict"},
    7. {"name" : "MatchNodeSelector"},
    8. {"name" : "HostName"}
    9. ],
    10. "priorities" : [
    11. {"name" : "LeastRequestedPriority", "weight" : 1},
    12. {"name" : "BalancedResourceAllocation", "weight" : 1},
    13. {"name" : "ServiceSpreadingPriority", "weight" : 1},
    14. {"name" : "EqualPriority", "weight" : 1}
    15. ],
    16. "extenders":[
    17. {
    18. "urlPrefix": "http://127.0.0.1:12346/scheduler",
    19. "apiVersion": "v1beta1",
    20. "filterVerb": "filter",
    21. "prioritizeVerb": "prioritize",
    22. "weight": 5,
    23. "enableHttps": false,
    24. "nodeCacheCapable": false
    25. }
    26. ]
    27. }

    其他影响调度的因素

    • 如果 Node Condition 处于 MemoryPressure,则所有 BestEffort 的新 Pod(未指定 resources limits 和 requests)不会调度到该 Node 上
    • 如果 Node Condition 处于 DiskPressure,则所有新 Pod 都不会调度到该 Node 上
    • 为了保证 Critical Pods 的正常运行,当它们处于异常状态时会自动重新调度。Critical Pods 是指
      • annotation 包括 scheduler.alpha.kubernetes.io/critical-pod=''
      • tolerations 包括 [{"key":"CriticalAddonsOnly", "operator":"Exists"}]
      • priorityClass 为 system-cluster-critical 或者 system-node-critical
    1. kube-scheduler --address=127.0.0.1 --leader-elect=true --kubeconfig=/etc/kubernetes/scheduler.conf

    kube-scheduler 工作原理

    kube-scheduler 调度原理:

    kube-scheduler 调度分为两个阶段,predicate 和 priority

    • predicate:过滤不符合条件的节点
    • priority:优先级排序,选择优先级最高的节点

    predicates 策略

    • PodFitsPorts:同 PodFitsHostPorts
    • PodFitsHostPorts:检查是否有 Host Ports 冲突
    • PodFitsResources:检查 Node 的资源是否充足,包括允许的 Pod 数量、CPU、内存、GPU 个数以及其他的 OpaqueIntResources
    • HostName:检查 pod.Spec.NodeName 是否与候选节点一致
    • MatchNodeSelector:检查候选节点的 是否匹配
    • NoVolumeZoneConflict:检查 volume zone 是否冲突
    • MaxEBSVolumeCount:检查 AWS EBS Volume 数量是否过多(默认不超过 39)
    • MaxGCEPDVolumeCount:检查 GCE PD Volume 数量是否过多(默认不超过 16)
    • MaxAzureDiskVolumeCount:检查 Azure Disk Volume 数量是否过多(默认不超过 16)
    • MatchInterPodAffinity:检查是否匹配 Pod 的亲和性要求
    • NoDiskConflict:检查是否存在 Volume 冲突,仅限于 GCE PD、AWS EBS、Ceph RBD 以及 ISCSI
    • GeneralPredicates:分为 noncriticalPredicates 和 EssentialPredicates。noncriticalPredicates 中包含 PodFitsResources,EssentialPredicates 中包含 PodFitsHost,PodFitsHostPorts 和 PodSelectorMatches。
    • PodToleratesNodeTaints:检查 Pod 是否容忍 Node Taints
    • CheckNodeMemoryPressure:检查 Pod 是否可以调度到 MemoryPressure 的节点上
    • CheckNodeDiskPressure:检查 Pod 是否可以调度到 DiskPressure 的节点上
    • NoVolumeNodeConflict:检查节点是否满足 Pod 所引用的 Volume 的条件

    priorities 策略

    • SelectorSpreadPriority:优先减少节点上属于同一个 Service 或 Replication Controller 的 Pod 数量
    • InterPodAffinityPriority:优先将 Pod 调度到相同的拓扑上(如同一个节点、Rack、Zone 等)
    • LeastRequestedPriority:优先调度到请求资源少的节点上
    • BalancedResourceAllocation:优先平衡各节点的资源使用
    • NodePreferAvoidPodsPriority:alpha.kubernetes.io/preferAvoidPods 字段判断, 权重为 10000,避免其他优先级策略的影响
    • NodeAffinityPriority:优先调度到匹配 NodeAffinity 的节点上
    • TaintTolerationPriority:优先调度到匹配 TaintToleration 的节点上
    • ServiceSpreadingPriority:尽量将同一个 service 的 Pod 分布到不同节点上,已经被 SelectorSpreadPriority 替代 [默认未使用]
    • EqualPriority:将所有节点的优先级设置为 1[默认未使用]
    • ImageLocalityPriority:尽量将使用大镜像的容器调度到已经下拉了该镜像的节点上 [默认未使用]
    • MostRequestedPriority:尽量调度到已经使用过的 Node 上,特别适用于 cluster-autoscaler[默认未使用]

    代码入口路径

    参考文档