59 k8s集群调度

文章目录

前言

Kubernetes集群调度是确保工作负载高效运行的核心机制,通过组件协作、调度策略和控制机制实现资源优化分配。本文聚焦调度流程与策略,涵盖组件协作原理、调度过程、节点绑定方式、亲和性规则、污点容忍机制等关键内容。

  1. list-watch组件 controller-manager scheduler kubelet
  2. list-watch 工作机制
  3. 亲和性(节点亲和pod亲和)和反亲和性 以及硬策略和软策略
  4. 污点和容忍
  5. 驱逐

理论部分

1_调度基础

1.1_K8S组件协作机制

  • Kubernetes 通过 List-Watch 机制使各个组件协作、数据同步,从而实现解耦与实时一致性。
  • 适用于需要分布式系统实时数据同步的集群管理场景。
①_组件职责

Kubernetes 核心组件职能(关键组件定义):

  • kubectl:API客户端,向 APIServer 发起资源创建或管理请求
  • APIServer:负责API调用、权限校验、存储交互,是集群控制的核心入口(监听 HTTPS 6443 端口)
  • etcd:存储集群所有状态信息
  • Controller Manager:维持副本数、执行自愈逻辑(扩容、重建等)
  • Scheduler:调度器,将未分配节点的 Pod 分配到合适的 Node
  • kubelet:节点代理,负责 Pod 生命周期管理和容器运行状态上报
②_List-Watch 机制

List-Watch 协作模型

  • Controller Manager、Scheduler 和 kubelet 启动后分别通过 Watch API Server 监听集群资源事件变化
  • 事件类型包括:Create(创建)、Update(更新)、Delete(删除)
  • 通过 API Server 中转,实现组件间数据解耦与同步

1.2_Pod创建与工作机制流程

  • Pod 创建是通过多组件协同完成资源分配与容器启动的分布式工作流。
  • 适用于需要自动化容器编排的云原生应用部署场景。

Pod典型13步创建流程

  1. 三大组件启动监听:Controller Manager、Scheduler、kubelet 通过 Watch API Server (6443 端口) 监听事件
  2. 用户创建 Pod 对象 :kubectl 发送创建请求,例如:
    kubectl apply -f pod.yaml
  3. API Server 写入 etcd:校验后将 Pod 元数据存入 etcd
  4. etcd 通知事件:触发 Create 事件发送给 API Server
  5. Controller Manager 监听:接收 Pod 创建事件
  6. ReplicaSet 保证副本数:创建所需 Pod 副本
  7. API Server 更新 etcd:写入 Pod 详细信息
  8. etcd 触发更新事件:再次发送更新事件
  9. Scheduler 监听待调度 Pod:发现 Pending 状态 Pod
  10. Scheduler 更新调度结果:写入 Node 绑定信息到 API Server
  11. etcd 确认更新:同步 Pod 最新状态
  12. kubelet 拉取运行容器:调用容器运行时启动容器
  13. API Server 更新状态:etcd 确认后 Pod 进入 Running 状态

流程可视化
用户创建 Pod
kubectl 发送请求
APIServer 校验&写入 etcd
etcd 发出 Create 事件
Controller Manager 监听
ReplicaSet 创建 Pod 副本
API Server 更新 etcd
etcd 发出 Update 事件
Scheduler 监听 Pending Pod
Scheduler 选择 Node
API Server 更新 Pod 绑定
kubelet 监听本节点 Pod
拉取镜像/启动容器
上报 Pod 状态
APIServer 更新 etcd
Pod 进入 Running

1.3_Scheduler调度器

Scheduler 是负责将未绑定 Node 的 Pod (spec.nodeName == "")分配到合适节点的核心组件。
调度核心目标

  • 公平性:节点间资源分配均衡
  • 高效性:最大化集群资源利用率
  • 效率:快速完成大批量 Pod 调度
  • 灵活性:支持自定义调度策略

1.4_调度流程

调度是分阶段筛选和排序节点的自动化决策过程。

①_过滤阶段(Predicate)
  • 通过预设条件过滤无效节点,剩余节点进入优选阶段
  • 若无节点满足条件,Pod 持续处于 Pending 状态并重试调度

预算策略(Predicate)过滤算法

过滤掉不满足条件的节点

算法名称 功能描述
PodFitsResources 检查节点剩余资源是否满足 Pod 需求
PodFitsHost 检查 NodeName 是否匹配
PodFitsHostPorts 检查端口冲突
PodSelectorMatches label 匹配
NoDiskConflict Volume 挂载冲突检测
②_优选阶段(Priorities)
  • 对可行节点按权重评分排序
  • 选择分数最高节点执行调度
  • 最终输出调度决策结果

优选策略(Priorities)评分算法

对可行节点进行打分排序

优先级项 描述
LeastRequestedPriority 资源使用率越低,权重越高
BalancedResourceAllocation CPU 与内存使用率越接近越好
ImageLocalityPriority 优先节点上已有目标镜像的节点

2_调度策略

2.1_指定调度节点方式

  • 通过直接绑定或标签匹配实现 Pod 与 Node 的关联。
  • 适用于需要精确控制 Pod 位置的特殊部署场景。
①_nodeName(强制绑定)
  • pod.spec.nodeName 将 Pod 直接调度到指定的 Node 节点上;
  • 会跳过 Scheduler 的调度策略;
  • 该匹配规则是强制匹配。
②_nodeSelector(基于标签匹配)
  • pod.spec.nodeSelector:通过 kubernetes 的 label-selector 机制选择节点;
  • 由调度器调度策略匹配 label,然后调度 Pod 到目标节点;
  • 该匹配规则属于强制约束。

2.2_Node与Pod的亲和性

  • 使用规则定义 Pod 与节点/Pod 之间的吸引关系。
  • 适用于需要控制 Pod 分布策略的高级拓扑场景。
①_节点亲和性(NodeAffinity)

关键特性

  • 操作符:In、NotIn、Exists、DoesNotExist、Gt、Lt
  • 硬策略 (requiredDuringSchedulingIgnoredDuringExecution):必须满足
  • 软策略 (preferredDuringSchedulingIgnoredDuringExecution):尽量满足但非强制

运算符逻辑

运算符 含义 通俗理解 示例
In label 的值在列表中 "只要值在名单里就选上" env In (dev, test)
NotIn label 的值不在列表中 "黑名单里的不要" env NotIn (prod)
Gt label 的值大于某数 "比数字大的才要" version Gt 3
Lt label 的值小于某数 "比数字小的才要" version Lt 3
Exists label 存在即可 "有标签就算数" Exists zone
DoesNotExist label 不存在 "无标签才要" DoesNotExist debug
②_Pod亲和性与反亲和性

调度策略对比

调度策略 匹配目标 操作符 拓扑域支持 调度目标
nodeAffinity 主机 In, NotIn, Exists等 指定主机
podAffinity Pod In, NotIn, Exists等 与指定 Pod 同域
podAntiAffinity Pod In, NotIn, Exists等 与指定 Pod 不同域

拓扑域说明

  • topologyKey 定义,相同键值标签的节点属于同一拓扑域(如 yjs=a 表示相同拓扑域)

2.3_污点和容忍

Taint and Tolerations

  • 污点使节点排斥特定 Pod,容忍使 Pod 能接受带污点的节点。
  • 适用于需要隔离节点资源的特殊环境管理场景。
①_污点(Taint)

污点机制

  • 格式:key=value:effect

  • effect 类型

    • NoSchedule:不调度到此节点
    • PreferNoSchedule:尽量避免调度到该节点
    • NoExecute:不调度 + 驱逐已存在 Pod
  • 污点命令:

    shell 复制代码
    kubectl taint node node01 key1=value1:NoSchedule  # 设置污点
    kubectl taint node node01 key1:NoSchedule-        # 清除污点
②_容忍(Tolerations)

容忍规则

  • 关键字段需与节点污点完全匹配(key, value, effect)

  • operator: "Exists" 表示只要存在 key 即可容忍(忽略 value)

  • tolerationSeconds 定义驱逐前保留时间

  • 全容忍配置:

    yaml 复制代码
    tolerations:
    - operator: "Exists"  # 容忍所有污点 key

3_运维操作

3.1_节点维护操作

cordon/drain/uncordon

  • 通过指令管理节点调度状态与 Pod 迁移。
  • 适用于节点维护或升级时的流量调度场景。

关键命令

命令 功能
kubectl cordon <node> 标记为不可调度
kubectl drain <node> --ignore-daemonsets --delete-local-data --force 驱逐 Pod(drain = cordon + 驱逐
kubectl uncordon <node> 恢复可调度状态

3.2_Pod生命周期

Phase

  • Phase 反映 Pod 运行阶段的状态特征。
  • 适用于诊断 Pod 异常状态的场景。

阶段状态说明

Phase 描述
Pending 已创建但未调度/拉取镜像中
Running 容器已启动运行中
Succeeded 所有容器成功终止(Job 类)
Failed 容器失败退出(非0状态)
Unknown 无法获取状态(通信异常)

3.3_故障排查命令

  • 通过系统命令诊断调度问题。
  • 适用于实时排查 Pod 调度失败的场景。

排错工具集

操作 命令
查看事件 kubectl describe pod <POD>
查看日志 kubectl logs <POD> [-c 容器名]
进入容器 kubectl exec -it <POD> bash
查看集群状态 kubectl cluster-info
查看节点状态 kubectl get nodes
查看 kubelet 日志 journalctl -xefu kubelet

3.4_总结图

核心调度策略层次

复制代码
kubectl → APIServer → etcd
          ↓     ↑
Controller Manager ←→ Scheduler ←→ kubelet(Node)

策略演进路径

  1. nodeName(直接绑定)
  2. nodeSelector(Label 匹配)
  3. nodeAffinity / podAffinity(亲和性调度)
  4. Taint & Toleration(污点/容忍机制)
  5. cordon & drain(节点维护与Pod迁移)

核心口诀

"调度是吸引,污点是排斥,亲和性是偏好,容忍是例外。"

实验部分

1_nodeName 强制绑定

1.1_创建强制绑定 Deployment

  • 通过 nodeName 跳过 Scheduler 直接指定节点
yaml 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      nodeName: node01  # 强制绑定到 node01
      containers:
      - name: myapp
        image: soscscs/myapp:v1
        ports:
        - containerPort: 80

nodeName: node01:强制将 Pod 调度到 node01 节点,直接跳过 Scheduler

操作验证:执行 kubectl apply -f myapp.yaml 后,所有 Pod 均在 node01 启动

1.2_验证调度结果

  • 检查 Pod 分布和调度事件
shell 复制代码
kubectl get pods -o wide

输出表明所有 Pod 均分配到 NODE: node01

事件验证:kubectl describe pod myapp-6bc58d7775-6wlpp 显示 "Normal Scheduled" 事件缺失,证明未经过 Scheduler

2_nodeSelector 标签匹配

2.1_设置节点标签

  • 为节点添加自定义标签
shell 复制代码
kubectl label nodes node01 yjs=a
kubectl label nodes node02 yjs=b

kubectl label:标签管理命令,为 node01 设置 yjs=a、node02 设置 yjs=b

验证命令:kubectl get nodes --show-labels 查看标签状态

2.2_应用标签选择部署

  • 创建 nodeSelector 配置的 Deployment
yaml 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp1
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp1
  template:
    metadata:
      labels:
        app: myapp1
    spec:
      nodeSelector:  # 通过标签匹配节点
        yjs: a      # 要求节点标签 yjs=a
      containers:
      - name: myapp1
        image: soscscs/myapp:v1
        ports:
        - containerPort: 80

nodeSelector:启用标签选择器调度,要求节点必须存在 yjs=a 标签

调度引擎:Scheduler 通过标签匹配将 Pod 分配到 node01

2.3_验证调度过程

  • 检查 Pod 分布及调度日志
shell 复制代码
kubectl get pods -o wide

所有 Pod 分配到 NODE: node01

事件验证:kubectl describe pod myapp1-58cff4d75-52xm5 显示 "Normal Scheduled" 事件,证明经过 Scheduler

3_节点亲和性实验

3.1_硬策略实验

  • 创建硬策略亲和性 Pod 配置
yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: affinity
  labels:
    app: node-affinity-pod
spec:
  containers:
  - name: with-node-affinity
    image: soscscs/myapp:v1
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:  # 硬策略定义
        nodeSelectorTerms:
        - matchExpressions:
          - key: kubernetes.io/hostname
            operator: NotIn
            values:
            - node02  # 排除 node02

required...:硬策略生效条件
NotIn:Pod 不会被调度到 kubernetes.io/hostname=node02 的节点

执行验证:Pod 被分配到 node01,如替换 values 为当前所有节点将导致 Pending 状态

3.2_软策略实验

  • 设置软策略优先级调度
yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: affinity
  labels:
    app: node-affinity-pod
spec:
  containers:
  - name: with-node-affinity
    image: soscscs/myapp:v1
  affinity:
    nodeAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:  # 软策略定义
      - weight: 1  # 权重值
        preference:
          matchExpressions:
          - key: kubernetes.io/hostname
            operator: In
            values:
            - node01  # 优先 node01

preferred...:软策略仅影响调度优先级
weight:1:权重值越高优先级越高(最大值100)

调度结果:若 node01 可用则 Pod 分配到 node01,否则分配到其他节点

3.3_软硬策略组合

  • 混合策略配置示例
yaml 复制代码
affinity:
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:  # 先满足硬策略
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: NotIn
          values:
          - node02  # 排除 node02
    preferredDuringSchedulingIgnoredDuringExecution:  # 再满足软策略
    - weight: 1
      preference:
        matchExpressions:
        - key: yjs
          operator: In
          values:
          - a  # 优先选择 yjs=a 节点

策略优先级:硬策略 > 软策略

执行效果:先排除 node02,再优先选择 yjs=a 的节点

4_Pod 亲和性实验

4.1_亲和性调度

  • 要求 Pod 与指定 Pod 部署在同一拓扑域
yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: myapp02
  labels:
    app: myapp02
spec:
  containers:
  - name: myapp02
    image: soscscs/myapp:v1
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:  # 硬策略
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - myapp01  # 必须与 app=myapp01 的 Pod 同域
        topologyKey: yjs  # 拓扑域标识

topologyKey: yjs:当节点 yjs 标签值相同时视为同一拓扑域

验证前提:需先存在 app=myapp01 的 Pod(如 node01 和 node02 都有 yjs=a 时,Pod 会调度到同一节点)

4.2_反亲和性调度

  • 防止 Pod 与指定 Pod 部署在同一拓扑域
yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: myapp20
  labels:
    app: myapp20
spec:
  containers:
  - name: myapp20
    image: soscscs/myapp:v1
  affinity:
    podAntiAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - myapp01  # 排斥与 app=myapp01 的 Pod 同域
        topologyKey: yjs

执行结果:当 node01 和 node02 的 yjs=a 时,Pod 无法调度(Pending);若将 node02 改为 yjs=b 则调度成功

5_污点与容忍实验

5.1_设置节点污点

  • 在 node02 上创建驱逐型污点
shell 复制代码
kubectl taint node node02 check=mycheck:NoExecute

NoExecute:新调度拒绝 + 驱逐现有 Pod

效果:kubectl get pods -o wide 显示 node02 的 Pod 被全部驱逐

5.2_配置 Pod 容忍

  • 添加匹配污点的容忍配置
yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: myapp01
  labels:
    app: myapp01
spec:
  containers:
  - name: with-node-affinity
    image: soscscs/myapp:v1
  tolerations:
  - key: "check"
    operator: "Equal"
    value: "mycheck"
    effect: "NoExecute"
    tolerationSeconds: 3600  # 驱逐前保留 1 小时

operator: "Equal":必须 key/value/effect 完全匹配
tolerationSeconds:定义驱逐前的等待时间

验证:Pod 成功调度到被标记污点的 node01 上

5.3_节点维护操作

  • 模拟节点维护流程
shell 复制代码
kubectl cordon node01        # 标记为不可调度
kubectl drain node01 --ignore-daemonsets --delete-local-data --force  # 驱逐 Pod
kubectl uncordon node01      # 恢复调度

drain 命令等同于 "cordon + 驱逐" 操作

关键选项:--ignore-daemonsets(忽略 DaemonSet)、--force(强制执行)

结语

Kubernetes 调度核心要点:调度是吸引(亲和性)、污点是排斥、容忍是例外、节点维护保障业务连续性。硬策略确保调度刚性规则,软策略实现弹性负载分配,污点机制隔离特殊节点,List-Watch 机制维持集群状态一致性。

!question\] 请说明 Scheduler 的过滤阶段与优选阶段的区别 过滤阶段(Predicate)通过预定义条件筛选可行节点;优选阶段(Priorities)对可行节点评分排序,选出最优节点 \[!question\] 污点 effect 的 NoSchedule 与 NoExecute 有何本质差异 NoSchedule 仅阻止新调度不驱逐现有 Pod;NoExecute 既阻止新调度也强制驱逐现有 Pod \[!question\] 节点亲和性中 hard strategy 与 soft strategy 的应用场景如何选择 硬策略用于必须满足的约束场景(如安全合规);软策略用于优化资源分配但非强制的场景(如负载均衡) \[!question\] 为什么 kubelet 需要持续监听 Pod 事件而非仅完成初始化调度 为响应动态变化:副本数调整、镜像更新、节点故障等,确保集群始终处于期望状态

相关推荐
独自归家的兔2 小时前
K8s 核心概念深度解析:Pod 是什么?
云原生·容器·kubernetes
智能化咨询3 小时前
(122页PPT)数字化架构演进和治理(附下载方式)
微服务·云原生·架构
释怀不想释怀3 小时前
Zabbix(安装模式)
运维·云原生·zabbix
陈陈CHENCHEN3 小时前
【Kubernetes】现有 K8s 集群上部署 Kuboard v4
kubernetes
zcz160712782119 小时前
nfs挂载pv,pvc
kubernetes
Cyber4K21 小时前
【Kubernetes专项】K8s集群1.31版本安装手册
linux·docker·云原生·容器·kubernetes
Exquisite.1 天前
云原生高级前置复习
linux·云原生·云计算
bentengjiayou1 天前
K8S是用来解决什么问题的?
云原生·容器·kubernetes
2501_901164411 天前
我们如何把“配环境一天”缩短到“3秒启动”?
kubernetes