Lazy loaded image
k8s 调度管理
Words 4568Read Time 12 min
2025-12-8
2025-12-8
date
related_level
slug
k8s_schedule
type
Post
relate_date
summary
Kubernetes 调度管理的核心机制和配置方法
status
Published
tags
k8s
系统管理
实用教程
category
运维管理
last_updated
Dec 8, 2025 09:54 AM
是否已更新
orginal_page
是否推荐
 

Kubernetes Scheduler 调度器

kube-scheduler 给一个 Pod 做调度选择时包含两个步骤
  • Kubernetes 调度器默认为 kube-scheduler
  • 过滤
    • 执行一组过滤函数(Predicates / Filter Plugins)筛选出所有满足 Pod 调度需求的候选节点
  • 打分
    • 对每个可调度节点应用一组打分规则(Priorities / Score Plugins),从可调度节点中选出最合适的节点(总分最高的节点)
      • 如果存在多个得分最高的节点,kube-scheduler 会从中随机选取一个
部署自定义调度器
  • 参考资料
    • KubernetesKubernetesKubernetes 调度器
    • KubernetesKubernetes配置多个调度器
    • KubernetesKubernetes调度器配置
  • k8s 可以同时部署多种 scheduler
  • 部署 pod 时通过 spec.schedulerName 来指定调度器
使用 kube-scheduler 镜像并传递自定义配置来创建新的调度器
vim admin/sched/RBAC.yaml
vim admin/sched/my-custom-scheduler.yaml
在启用了 leader 选举的情况下运行多调度器需要进一步修改 Configmap 文件配置
  • kubectl get leases -n kube-system
    • 锁本质是一个 Lease 资源
  • Kubernetes 中多个调度器实例不能同时进行调度,否则会导致冲突
    • leaderElection.leaderElect to true
    • leaderElection.resourceNamespace to <lock-object-namespace>
      • 默认为 kube-system
    • leaderElection.resourceName to <lock-object-name>
      • 应该和 schedulerName 字段对应值相似或一致
  • kubectl apply -f ./admin/sched/
为 pod 指定调度器
  • 没有设置 spec.schedulerName 则默认为 default-scheduler
  • spec.schedulerNameKubeSchedulerProfile  的对应 schedulerName 字段一致
vim admin/sched/pod3.yaml
  • kubectl apply -f ./admin/sched/pod3.yaml
通过调度策略和调度配置来配置调度器的过滤和打分行为
  • 调度策略允许你配置过滤所用的断言(Predicates)和打分所用的优先级(Priorities)
调度阶段的扩展点包括:QueueSort、Filter、Score、Bind 等等
  • QueueSort 作用于 Pod 进入调度队列时
  • PreFilter, Filter, PostFilter 对每个候选节点逐一检查,过滤掉不满足条件的节点
  • preScore, Score 对通过 Filter 的节点进行打分
  • Reserve 在调度器内部预留资源,防止其他 Pod 同时调度到同一节点导致冲突
    • 非持久化的占位操作(仅存在于调度器内存中)
    • 如果后续 Bind 失败,会调用 Unreserve 回滚
  • Permit 允许插件延迟或拒绝 Pod 的绑定
    • 常见于等待外部系统就绪(如存储卷准备完毕)或实现批调度(等待同一批所有 Pod 都可调度后再放行)
  • PreBind, Bind, PostBind 将 Pod 绑定到节点
 

Kubernetes Pod 资源保障和抢占、驱逐机制

参考资料
  • KubernetesKubernetesPod Quality of Service Classes
QoS 等级由 Pod 的 resources 自动生成,决定在资源不足时 Pod 被驱逐的优先级
  • BestEffort(最低优先级,最先被驱逐)
    • 容器没有设置 requestslimits
  • Burstable(中等优先级)
    • 至少有一个容器的 requestslimits 不相等,或者只设置了 requests
  • Guaranteed(最高优先级,最后被驱逐)
    • 每个容器都设置了 limits,且 requestslimits 相等且不为 0
干扰(Disruption)和干扰预算(PodDisruptionBudget, PDB)
干扰分为自愿干扰和非自愿干扰
类型
说明
是否受 PDB 限制
自愿(Voluntary)中断
由集群管理员或控制器主动触发的操作
✅ 受 PDB 限制
非自愿(Involuntary)中断
节点宕机、内核 panic、硬件故障等意外事件
❌ 不受 PDB 限制
减轻非自愿干扰的一些方法
  • 确保 Pod 在请求中给出 requests
  • 设置 replicas 实现 Pod 的高可用性
  • 设置 PodAntiAffinity 和 topologySpreadConstraints 来实现副本集的高可用性
健康 Pod 定义:status.conditions[] 中有 item 为 type="Ready" 且 status="True"
  • 健康 Pod 始终受 PDB 保护
    • 健康的 Pod 总是根据 PDB 进行驱逐
正在运行但不健康的 Pod 的驱逐行为由策略 spec.unhealthyPodEvictionPolicy 决定
  • 正在运行但尚未达到健康状态的 Pod
    • status.phase="Running"
  • 默认为 IfHealthyBudget
    • 仅当 status.currentHealthy >= status.desiredHealthy(即未违反 PDB)时,才允许驱逐正在运行但不健康的 Pod
      • status 特指 PodDisruptionBudgetStatus,即 PodDisruptionBudget 对象本身的 status
  • AlwaysAllow 总是允许驱逐正在运行但尚未达到健康状态的 Pod
Pod 设置 status.conditions[] 特定 item 的 type 为 DisruptionTarget 表示当前受到干扰
  • status.conditions[].type: DisruptionTarget
  • status.conditions[].reason 可能的情况
    • PreemptionByScheduler:被高优先级 Pod 抢占
    • DeletionByTaintManager:无法容忍 NoExecute 污点而被驱逐
    • EvictionByEvictionAPI:通过 Eviction API 主动驱逐(如 kubectl drain
    • DeletionByPodGC:所属节点已不存在,被 Pod 垃圾回收器清理
    • TerminationByKubelet:因节点压力、优雅关机或系统 Pod 抢占被 kubelet 终止
PDB 保障应用的高可用性和最小可用实例数
  • PDB 不能防止非自愿干扰,但非自愿干扰造成的影响仍会计入 PDB 计算
  • deploy, sts 进行滚动升级时不受 PDB 的限制
PDB 规范 selector, minAvailable, maxUnavailable, unhealthyPodEvictionPolicy
  • KubernetesKubernetesPodDisruptionBudget
  • 一个 PDB 对象同时只能够指定 maxUnavailable 和 minAvailable 中的一个
  • spec.selector 用于指定其所作用的 Pod 集合
    • policy/v1 中,空的选择算符 {} 会匹配名字空间中所有 Pod
    • 属于 LabelSelector 对象
      • matchExpressions 
      • matchLabels
  • spec.minAvailable 表示驱逐后仍须保证可用的 Pod 数量
    • 可以是绝对值或是百分比
  • spec.maxUnavailable 表示驱逐后允许不可用的 Pod 的最大数量
    • 可以是绝对值或是百分比
  • spec.unhealthyPodEvictionPolicy 定义不健康的 Pod 应被考虑驱逐时的标准
    • 可用策略,默认为 IfHealthyBudget
      • IfHealthyBudget 仅当 status.currentHealthy >= status.desiredHealthy(即未违反 PDB)时,才允许驱逐正在运行但不健康的 Pod
        • status 特指 PodDisruptionBudgetStatus,即 PodDisruptionBudget 对象本身的 status
      • AlwaysAllow 总是允许驱逐正在运行但不健康的 Pod
  • 针对 CRD 使用 PDB 时只能使用 .spec.minAvailable 且只能指定整数值
  • kubectl drain --force 忽略 PDB 清空节点
PDB 样例
minAvailable
maxUnavailable
基于 PriorityClass 的 Pod 优先级
  • PriorityClass 是集群级资源,定义了从优先级类名称到优先级整数值的映射
PriorityClass 规范
  • value:整数,表示优先级的数值
    • 数值越大,优先级越高
    • 用户可以设置任何小于或等于 10 亿的 32 位整数值,从 -2,147,483,648 到 1,000,000,000(含)
  • globalDefault:(可选)是否为默认优先级,布尔值
    • 若设为 true,则未显式指定 PriorityClass 的 Pod 将自动使用该 PriorityClass
  • description:(可选)描述信息
  • preemptionPolicy 用于控制是否允许该优先级的 Pod 抢占其他 Pod
    • 可选值,默认为 PreemptLowerPriority
      • PreemptLowerPriority
        • 允许该 PriorityClass 的 Pod 抢占较低优先级的 Pod
      • Never
        • 被放置在调度队列中较低优先级 Pod 之前,直到有足够的可用资源, 它才可以被调度
仅限系统可用的最高优先级 PriorityClass
  • system-cluster-critical
    • value 为 2,000,000,000,还要用户可定义的最大值 1,000,000,000 大一倍
  • system-node-critical
    • value 为 2,000,000,000
    • system-cluster-critical 优先
PriorityClass 示例
抢占(Preemption)和驱逐(evict)
  • 触发条件:当一个 Pod 创建后无法被调度(即没有节点满足其资源或约束要求)时,调度器会尝试抢占
  • 调度器查找可以通过驱逐(evict)低于当前 Pod 优先级的低优先级 Pod 来腾出资源的节点,并对这些 Pod 执行驱逐后将 Pod 调度到该节点上
抢占过程
  1. 调度器识别出高优先级 Pod 无法调度
  1. 查找具有可以被抢占的低优先级 Pod 且可释放足够资源的节点
      • 优先级需要低于当前 Pod
  1. 删除(优雅终止)这些低优先级 Pod
  1. 高优先级 Pod 被调度到腾出资源的节点上
 

将 Pod 指派给 Node

通过 spec.nodeName 手动调度 Pod 到某个 Node
  • 不设置 schedulerName(或设为默认但确保调度器未运行),Kubernetes 将跳过调度阶段,直接绑定
  • 手动调度 Pod 跳过调度阶段的影响
    • 不检查资源可用性
    • 不应用调度策略
      • 如亲和性(affinity)、污点容忍(tolerations)、Pod 拓扑分布等全部失效
    • 不检查节点存在性
    • DaemonSet 不适用
spec.nodeName 样例
  • vim pods/pod-nginx-specific-node.yaml
通过 spec.nodeSeletor 指派 pod 给特定标签的 Node
  • 参考资料
  • 查看现有标签
    • kubectl get nodes --show-labels
  • 添加与撤销标签
    • kubectl label nodes <your-node-name> key=value
    • kubectl label nodes <your-node-name> key=value-
spec.nodeSeletor 样例
  • vim pods/pod-nginx.yaml
taint 和 toleration 限制 pod 是否可以调度到特定节点
  • 污点(taint)使节点能够排斥一类特定的 Pod
    • 其中 NoExecute 还会驱逐不具备对应 toleration 的已运行 Pod
taint 规范
  • key
  • value
    • 可选
  • effect:污点的效果,有三种:
    • NoSchedule不允许新 Pod 调度到该节点(已运行的不受影响)
      • key=value:NoSchedule
    • PreferNoSchedule尽量避免调度(软性约束,调度器会尽量避开)
    • NoExecute不仅禁止调度,还会驱逐节点上已运行的、不满足容忍的 Pod
toleration 规范
  • key
  • operator
    • 必填,两种可选值,默认为 Equal
      • Equal
      • Exists
  • value
    • 可选,仅当 operator 为 Equal 时可用
  • effect:可选,可容忍的 taint effect
    • NoSchedule
    • PreferNoSchedule
    • NoExecute
添加和移除 taint
  • kubectl taint nodes node1 key1=value1:NoSchedule
  • kubectl taint nodes node1 key1=value1:NoSchedule-
    • 移除污点
kubectl 查看当前 nodes taint
  • kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.taints}{"\n"}{end}'
toleration 允许调度器调度 Pod 到带有对应污点的 Node
affinity (nodeaffinity, podAffinity, podAntiAffinity) 控制 Pod 调度位置
  • taint, toleration 限制调度时的可用节点,affinity 控制 Pod 调度的节点选择
    • 可用不代表会调度到对应节点,因为可能存在其他可用节点
  • 使用 .spec.affinity.nodeAffinity 字段来设置节点亲和性
    • 影响 pod 调度时选择的节点
  • 使用 .spec.affinity.podAffinity 字段来设置 pod 间亲和性
    • 让 Pod 尽量/必须和某些已存在的 Pod 跑在一起,实现微服务同机部署、降低延迟
  • 使用 .spec.affinity.podAntiAffinity 字段来设置 pod 间反亲和性
    • 让 Pod 避开某些已存在的 Pod,实现高可用,避免单点故障
node 间亲和性字段规范
  • preferredDuringSchedulingIgnoredDuringExecution
    • weight,范围 1-100
    • preference
      • matchExpressions
      • matchFields
        • 用于匹配资源的字段(fields),而非标签(labels)
        • 仅用于系统内部,不推荐用户使用
  • requiredDuringSchedulingIgnoredDuringExecution
    • nodeSelectorTerms
      • matchExpressions
      • matchFields
pod 间亲和性字段规范
  • preferredDuringSchedulingIgnoredDuringExecution
    • weight,范围 1-100
    • podAffinityTerm
      • labelSelector
      • topologyKey
      • namespaces,可选
      • namespaceSelector,可选
  • requiredDuringSchedulingIgnoredDuringExecution
    • 每个可用字段均为 PodAffinityTerm 的键值
    • labelSelector
    • topologyKey
    • namespaces,可选
    • namespaceSelector,可选
podAffinityTermtopologyKey 指定在哪个拓扑域内进行 Pod 的亲和性/反亲和性计算
众所周知的常用 topologyKey
  • kubernetes.io/hostname:表示节点级别
    • 这是最细粒度的拓扑域,意味着规则会在单个节点上生效
  • topology.kubernetes.io/zone:表示可用区级别
    • 规则会在可用区这一层级上生效
    • 可以将新 Pod 调度到与特定 Pod 在同一可用区的节点上,以减少网络延迟
  • topology.kubernetes.io/region:表示区域级别
    • 规则会在区域这一层级上生效
  • 自定义 topologyKey:可以使用任何在节点上定义的标签作为 topologyKey
    • 例如 rackfloorbuilding 等,只要节点上存在对应的标签
一些限制
  • 对于 Pod 亲和性而言,在 requiredDuringSchedulingIgnoredDuringExecution 和 preferredDuringSchedulingIgnoredDuringExecution 中,topologyKey 不允许为空
  • 对于 requiredDuringSchedulingIgnoredDuringExecution 要求的 Pod 反亲和性, 准入控制器 LimitPodHardAntiAffinityTopology 要求 topologyKey 只能是 kubernetes.io/hostname
Pod 亲和性/反亲和性 topologyKey 示例
可用的亲和性类型
可以拆分为两部分来理解
  • requiredDuringScheduling / preferredDuringScheduling
    • 调度是否必须满足亲和性要求
  • IgnoredDuringExecution / RequiredDuringExecution
    • 是否驱逐已经部署但不满足条件的 pod
requiredDuringSchedulingIgnoredDuringExecution
  • 必须满足
preferredDuringSchedulingIgnoredDuringExecution
  • 最好满足
  • 通过 weight 字段来设置权重,取值范围是 1 到 100
  • 不同 label 的 weight 加总求和,优先取总分最高的节点
requiredDuringSchedulingRequiredDuringExecution
  • 必须满足并驱逐当前不满足的节点
  • 目前还没实现该功能
其中 matchExpressions.operator 设置要使用的逻辑操作符
  • InNotInExistsDoesNotExistGt 和 Lt
    • NotInDoesNotExist 可以用来实现节点反亲和
nodeAffinity 带亲和性权重的样例
  • vim pods/pod-with-affinity-preferred-weight.yaml
    podAffinity 带反亲和性权重的样例
    • vim pods/pod-with-pod-affinity.yaml
      topologySpreadConstraints 控制 Pod 在集群内拓扑域之间的分布
      参考资料
      • KubernetesKubernetesPod 拓扑分布约束
      • topologySpreadConstraints 依赖于节点标签来标识每个节点所在的拓扑域
      • 一些众所周知的标签键
        • topology.kubernetes.io/zone
        • topology.kubernetes.io/region
      topologySpreadConstraints 规范
      minDomains 参与计算的最小拓扑域数量(必须 >0)
      • 未指定时默认为 1
      • 若实际域数 < minDomains,则全局最小值(符合条件的域中匹配的最小 Pod 数量)视为 0
      • maxSkew 允许各拓扑域中匹配 Pod 数量的最大偏差(必须 >0)
      topologyKey 节点标签键,如 topology.kubernetes.io/zone
      • 众所周知的标签键
        • topology.kubernetes.io/zone
        • topology.kubernetes.io/region
      whenUnsatisfiable 约束不满足时的行为
      • whenUnsatisfiable: DoNotSchedule 硬限制偏差
        • 目标拓扑中匹配 Pod 的数量与全局最小值之间的最大允许差值
      • whenUnsatisfiable: ScheduleAnyway 软策略
        • 更为偏向能够降低偏差值的拓扑域
      • labelSelector 选择用于计算分布的已有 Pod(通过标签匹配)
      matchLabelKeys Pod 标签键的列表
      • 便于按版本分组分布
        • 如Deployment 控制器自动添加的一个标签 pod-template-hash
      • 创建 Pod 时,动态从新 Pod 标签中提取对应键值,自动合并到 labelSelector
        • 必须先设置 labelSelector
        • 相同的键不允许同时出现在 matchLabelKeys 和 labelSelector 中
        • 如果键在 Pod 标签中不存在,则会被忽略
      • 不建议将 matchLabelKeys 与可能直接在 Pod 上更新的标签一起使用
        • kube-apiserver 不会将标签更新反映到合并的 labelSelector 上
      nodeAffinityPolicy 是否考虑 Pod 的 nodeAffinity/nodeSelector
      • Honor:默认,只包含匹配节点
      • Ignore:忽略 nodeAffinity/nodeSelector ,所有节点均包括到计算中
      nodeTaintsPolicy 是否考虑节点污点
      • Ignore:默认,忽略节点污点,所有节点均包括到计算中
      • Honor:仅包含无污点或可容忍污点的节点
      集群级别的默认约束和内置默认约束
      • 集群级别的默认拓扑分布约束在且仅在以下条件满足时才会被应用到 Pod 上:
        • Pod 没有在其 .spec.topologySpreadConstraints 中定义任何约束
        • Pod 隶属于某个 Service、ReplicaSet、StatefulSet 或 ReplicationController
      通过调度方案中配置 PodTopologySpread 插件来设置集群级别的默认拓扑分布约束
      • 规范同上,只是不能设置 labelSelector
        • 由 Pod 所属的 Service、ReplicaSet、StatefulSet 或 ReplicationController 来设置
      • 样例
        没有手动修改则默认采用以下内置默认约束
        配置 PodTopologySpread 插件禁用内置默认约束
        • defaultingType 改为 List
        • defaultConstraints 改为空列表 []
        一些隐式约定
        • 命名空间隔离:调度器仅考虑与新 Pod 同一命名空间中的现有 Pod 作为分布计算的匹配对象
        • 节点必须包含所有 topologyKey 标签
        • labelSelector 应匹配新 Pod 自身标签
          • 如果新 Pod 的标签不满足 topologySpreadConstraints.labelSelector,它仍可被调度(只要约束条件在已有 Pod 上成立),但不会被计入后续的分布统计,从而导致分布失衡
        topologySpreadConstraints 均匀分布样例
        • 假设有 zoneA 和 zoneB,node1~4
        topologySpreadConstraints 多约束样例
        • 假设有 zoneA 和 zoneB,node1~4
        上一篇
        helm 管理 Kubernetes 集群软件
        下一篇
        Prometheus 客户端 Python 库 prometheus_client

        Comments
        Loading...