k8sday16调度器

目录

一、调度器概念

1、调度器的主要功能

①、过滤 (Filtering)

②、评分 (Scoring)

③、绑定 (Binding)

2、调度流程

①、Pod 创建

②、调度队列

③、调度周期

④、绑定

⑤、kubelet 执行

3、调度策略

①、预选策略 (Predicates)

②、优选策略 (Priorities)

4、自定义调度器

二、亲和性

1、节点亲和性的类型

①、硬性约束

Ⅰ、配置文件

Ⅱ、实操效果

②、软性约束

Ⅰ、配置文件

Ⅱ、实操效果

2、Pod亲和/反亲和性的类型

三、容忍和污点

1、污点

①、污点语法

②、小细节

③、操作语法

2、容忍

①、容忍语法

②、特殊写法

四、固定节点调度

1、直接指定节点名称 (nodeName)

2、 节点选择器 (nodeSelector)


一、调度器概念

Kubernetes 调度器 Scheduler 是 Kubernetes 控制平面的核心组件之一,通过 API Server 监听尚未被绑定到具体节点的 Pod(即 Pod 的 spec 中的 NodeName 为空的 Pod),最终实现将 Pod 分配到集群中合适的 Node 上运行。

1、调度器的主要功能

①、过滤 (Filtering)

根据 Pod 的资源需求和 Node 的资源容量,筛选出可调度的 Node

②、评分 (Scoring)

对通过过滤的 Node 进行评分,选择最优的 Node

③、绑定 (Binding)

将 Pod 绑定到选定的 Node 上

2、调度流程

①、Pod 创建

用户通过 kubectl 或其他方式创建 Pod

②、调度队列

Pod 进入调度器的待调度队列

③、调度周期
  • 过滤阶段:排除不满足条件的 Node(预选策略)

  • 评分阶段:对剩余 Node 进行评分(优选策略)

  • 选择阶段:选择分数最高的 Node

④、绑定

将 Pod 绑定到选定的 Node

⑤、kubelet 执行

相应 Node 上的 kubelet 创建并运行 Pod 容器

3、调度策略

首先“预选",排除掉不满足条件的节点,然后”优选“,将满足条件的节点按照优先级排序,最后选出优先级最高的节点。当其中有一步发生错误,就会直接返回错误。

预选策略必须每一个都通过,否则Pod会一直处于“Pending”状态,不断重试调度,直到找到满足条件的节点。

有多个节点通过预选后会进行优选进行排序,选择最高优先级的节点绑定Pod。

①、预选策略 (Predicates)
  • PodFitsResources:检查 Node 是否有足够的资源,即当前节点剩余资源是否大于Pod请求资源

  • PodFitsHostPorts:检查 Node 是否有可用的端口,即已使用的端口是否和Pod请求的端口冲突

  • HostName:检查 Pod 是否指定了特定 Node

  • MatchNodeSelector:检查 Node 标签是否匹配 Pod 的 nodeSelector

  • NoDiskConflict:检查存储卷是否冲突,即已挂载的卷是否和Pod请求的卷冲突

注意,每个版本的K8S其对应的预选策略有部分差别

②、优选策略 (Priorities)
  • LeastRequestedPriority:选择资源利用率最低的 Node

  • BalancedResourceAllocation:平衡 CPU 和内存的使用

  • NodeAffinityPriority:根据 Node 亲和性规则评分

  • TaintTolerationPriority:根据污点和容忍度评分

  • ImageLocalityPriority:优先选择已经有所需镜像的 Node

注意,每个版本的K8S其对应的优选策略有部分差别

4、自定义调度器

自定义调度器是 Kubernetes 中一个强大的功能,允许我们实现自己的调度逻辑来替代或补充默认调度器。

官方的默认调度器已经很优秀了,要使用自定义的调度器多为要我们的特殊调度需求,针对某些特定领域等等。这里就不给大家演示了,有兴趣的可以自己去搜索创建。

二、亲和性

节点亲和性(Node Affinity) 是一种调度约束,用于指定 Pod 应该或不应该调度到哪些节点 上运行。它基于节点的 标签(Labels) 进行匹配,比传统的 nodeSelector 更灵活,支持 软约束(偏好)硬约束(要求)

1、节点亲和性的类型

节点亲和性通过 nodeAffinity 字段定义,分为两种规则:

类型字段说明类比
必需(硬约束)requiredDuringSchedulingIgnoredDuringExecution必须满足,否则 Pod 无法调度nodeSelector 的增强版
偏好(软约束)preferredDuringSchedulingIgnoredDuringExecution尽量满足,但不强制类似“优先选择”
  • 硬性约束即必须满足,带有强制性,达不到则Pod一直处于"Pending"

  • 软性约束即我的期望,不带有强制性,达不到则Pod找其他节点绑定

①、硬性约束
Ⅰ、配置文件
  apiVersion: v1
  kind: Pod
  metadata:
    name: nginx-ssd
  spec:
    containers:
    - name: nginx
      image: nginx:1.24.0
    affinity:                        # 亲和性
      nodeAffinity:                  # 节点亲和性
        requiredDuringSchedulingIgnoredDuringExecution:      # 表明是硬性约束
          nodeSelectorTerms:         # 选择的节点
          - matchExpressions:        # 匹配运算符
            - key: disktype          # 匹配的节点标签的键
              operator: In           # 在列表
              values: ["ssd"]        # 匹配的节点标签的值
              # 即该 Pod 只能 调度到带有 disktype=ssd 标签的节点,没有则一直"Pending"。
Ⅱ、实操效果

刚开始我的所有节点都没有目标标签,这时候创建Pod,查看nginx-ssd的状态

现在我向我的节点my-multi-node-cluster1-worker2添加标签disktype=ssd,观察nginx-ssd的状态:

  # 给节点添加标签格式如下:
  # kubectl label nodes <node-name> <key>=<value>
  kubectl label nodes my-multi-node-cluster1-worker2 disktype=ssd
  ​
  # 查看是否添加成功
  kubectl get nodes --show-labels
  ​
  # 再次查看nginx-ssd的状态
  kubectl get po -o wide
  ​
  # 结束后删除特定标签格式: kubectl label nodes <node-name> <key>-  (可选)

可见该 Pod 只能调度到带有 disktype=ssd 标签的节点,没有则一直"Pending"。

②、软性约束
Ⅰ、配置文件
  apiVersion: v1
  kind: Pod
  metadata:
    name: nginx-testlabel
  spec:
    containers:
    - name: nginx
      image: nginx:1.24.0
    affinity:                        
      nodeAffinity:                    # 亲和性
        preferredDuringSchedulingIgnoredDuringExecution:       # 表明是软性约束
        # 注意权重只在软性约束出现,硬性约束没有
        - weight: 50                  # 权重 1-100,越高越优先
        
          preference:                  # 亲和类型
            matchExpressions:          # 匹配运算符
            - key: testlabel           # 匹配的节点标签的键
              operator: In
              values: ["a"]       # 匹配的节点标签的值
              # 调度器会优先选择 testlabel=a 的节点,但如果没有,也可以调度到其他节点。
Ⅱ、实操效果

刚开始我的所有节点都没有目标标签,这时候创建Pod,查看nginx-testlabel的状态

可见即使没有 testlabel=a 的节点,该 Pod 也可以调度到其他节点。

现在我向我的节点my-multi-node-cluster1-worker添加标签 testlabel=a,观察nginx-testlabel的状态:

  # 给节点添加标签格式如下:
  # kubectl label nodes <node-name> <key>=<value>
  kubectl label nodes my-multi-node-cluster1-worker  testlabel=a
  ​
  # 查看是否添加成功
  kubectl get nodes --show-labels
  ​
  # 再次查看nginx-ssd的状态
  kubectl get po -o wide
  ​
  # 结束后删除特定标签格式: kubectl label nodes <node-name> <key>-  (可选)

可见调度器会优先选择 testlabel=a 的节点,但如果没有,也可以调度到其他节点。

2、Pod亲和/反亲和性的类型

Pod 亲和性(Pod Affinity)与反亲和性(Pod Anti-Affinity)用来控制 Pod 之间 的“吸引”或“排斥”关系——也就是「这个 Pod 想/不想和哪些 Pod 跑在一起」。它们同样通过节点上的 topologyKey(通常是主机名、机架、可用区等)来划定“拓扑域”,然后在该域内按标签匹配其它 Pod,即拓扑域就是通过节点标签来规定范围。

语义字段场景示例
required…(硬约束)requiredDuringSchedulingIgnoredDuringExecution“必须”和某类 Pod 同域/异域
preferred…(软约束)preferredDuringSchedulingIgnoredDuringExecution“尽量”和某类 Pod 同域/异域

Pod的亲和性和反亲和性都有两种类型,即硬性约束和软性约束。

  • 亲和性软性约束:最好和哪个Pod在一起运行

  • 亲和性硬性约束:必须和哪个Pod在一起运行

  • 反亲和性软性约束:最好不和哪个Pod在一起运行

  • 反亲和性硬性约束:必须不和哪个Pod在一起运行

和节点亲和性的配置文件类似,以下给出配置文件大致模板:

  affinity:
    podAffinity:              # Pod 亲和性(想在一起)
      <required|preferred>DuringSchedulingIgnoredDuringExecution:   # 硬性约束/软性约束
      - topologyKey: <key>    # 划定“拓扑域”的节点标签
        labelSelector:        # 匹配其它 Pod 的标签
          matchExpressions:
          - {key: app, operator: In, values: [backend]}
        namespaces: [ns1, ns2]  # 默认当前命名空间
        # 注意:权重只在软性约束时出现,硬性约束没有
        weight: 50            # 权重 1-100,越高越优先
  ​
    podAntiAffinity:          # Pod 反亲和性(不想在一起)
      <required|preferred>DuringSchedulingIgnoredDuringExecution:    # 硬性约束/软性约束
      - topologyKey: kubernetes.io/hostname
        labelSelector:
          matchLabels:
            app: nginx

给出一个Pod亲和软性约束+一个Pod反亲和硬性约束的配置文件:

  apiVersion: apps/v1
  kind: Deployment
  metadata:
    name: cache
  spec:
    replicas: 1
    selector:
      matchLabels: { app: nginx }       # 和下方 Pod 模板中的标签相同
    template:
      metadata:
        labels: { app: nginx }          # 和上方的匹配标签相同
      spec:
        containers:
        - name: nginx
          image: nginx:1.24.0
        affinity:
          podAffinity:                  # Pod 亲和性(想在一起)
            preferredDuringSchedulingIgnoredDuringExecution:   # 软性约束
            # 注意:权重只在软性约束中出现,硬性约束没有
            - weight: 80                # 权重越高,优先级越高
            
              topologyKey: kubernetes.io/hostname  # 拓扑域
              labelSelector:            # 匹配的 Pod 标签
                matchLabels: { app: backend }
  # 即该配置文件创建的 Pod 最好和在 kubernetes.io/hostname 这一拓扑域中含有的带有 app=backend 标签的 Pod 在一起运行,如果没有则 Pod 随便选取要绑定的节点
                
  ---
  apiVersion: apps/v1
  kind: Deployment
  metadata:
    name: nginx
  spec:
    replicas: 3
    selector:
      matchLabels: { app: nginx }
    template:
      metadata:
        labels: { app: nginx }
      spec:
        containers:
        - name: nginx
          image: nginx:1.24.0
        affinity:
          podAntiAffinity:                          # Pod 反亲和性(不想在一起)
            requiredDuringSchedulingIgnoredDuringExecution:     # 硬性约束
            - topologyKey: kubernetes.io/hostname   # 拓扑域
              labelSelector:                        # 匹配的 Pod 标签
                matchLabels: { app: nginx }
  # 即该配置文件创建的 Pod 必须不能和在 kubernetes.io/hostname 拓扑域中含有的带有 app=nginx 标签的 Pod 在一起运行,如果没有则 Pod 一直 "Pending",不绑定节点

三、容忍和污点

污点和容忍(Taints & Tolerations)是 Kubernetes 用来 “排斥” Pod 与节点 的强耦合机制:

  • Taint(污点) 打在节点上 → “拒绝” 没有对应容忍度的 Pod。

  • Toleration(容忍度) 写在 Pod 上 → “允许” 被调度到带有对应污点的节点。

精简总结:只有可容忍节点的污点的Pod才有可能被绑定注意是有可能,不是一定

1、污点

在node节点设置污点,可以一定程度上根据对应effect策略和Pod之间产生排斥,Pod一定程度上不会被调度到含污点的节点上。

①、污点语法
  key=value:effect

每个污点都有匹配的key和value,value可为空,effect描述污点的作用

effect当前包含三个选项:

Effect调度阶段已运行 Pod 是否驱逐
NoSchedule新 Pod 不可调度不驱逐
PreferNoSchedule软排斥(尽量不去)不驱逐
NoExecute新 Pod 不可调度 + 已运行且无容忍的 Pod 立即驱逐驱逐

精简总结:NoSchedule 是不会将 Pod 调度到含该污点的节点上,PreferNoSchedule是尽量不将 Pod 调度到含该污点的节点上,NoExecute 是不会将 Pod 调度到含该污点的节点上且原有的 Pod 会进行驱逐

②、小细节

我们在之前不管是创建DeployMent还是StatefulSet等等,他们创建出来的Pod都是运行在副节点,也就是worker节点上的,没有运行在主节点(master节点)上的,这是为什么呢?答案就是因为主节点有污点,不参与调度。如图:

但真的所有Pod都不能在主节点运行吗,实际不然,设置了容忍的Pod可以在主节点运行,如图:

③、操作语法
  # 添加污点
  kubectl taint nodes <node-name> key=value:NoSchedule
  # 例:让 master 节点只接受控制面 Pod
  kubectl taint nodes master-0 node-role.kubernetes.io/master:NoSchedule
  ​
  # 查看污点
  kubectl describe nodes <node-name>
  ​
  # 删除污点
  kubectl taint nodes <node-name> key=value:NoSchedule-
  # 或
  kubectl taint nodes <node-name> key:NoSchedule-

2、容忍

在node节点设置污点,可以一定程度上根据对应effect策略和Pod之间产生排斥,Pod一定程度上不会被调度到含污点的节点上。但也只是一定程度,我们如果在Pod上设置了容忍度(Toleration),就代表着我的这个Pod容忍这个带污点的node节点,那么就可以在这个节点上运行。

①、容忍语法
  tolerations:                # 容忍度
  - key: "key1"               # 污点的键
    operator: "Equal"         # 比较操作符(Equal 或 Exists)
    value: "value1"           # 污点的值
    effect: "NoSchedule"      # 污点效果作用  
    
    tolerationSeconds: 3600   # 仅对 NoExecute 有效,表示容忍时间(秒),超过这个时间驱离所有 Pod

effect的三个污点作用就是上面的NoSchedule, PreferNoSchedule, NoExecute

②、特殊写法
  
  tolerations:                # 容忍度
  - key: "key1"               # 污点的键
    operator: "Exists"        # 比较操作符(Equal 或 Exists)
    effect: "NoSchedule"      # 污点效果作用  
  # 即不写污点的值,比较操作符写为Exists

即只要是key1污点内所有设置为驱离(NoSchedule)的污点我都容忍

  tolerations:                # 容忍度
  - key: "key1"               # 污点的键
    operator: "Exists"        # 比较操作符(Equal 或 Exists)
  # 即不写污点的值和污点效果,比较操作符写为Exists

即容忍所有key1污点

  tolerations:                # 容忍度
    - operator: "Exists"        # 比较操作符(Equal 或 Exists)
  # 即不写污点的键、值和污点效果,比较操作符写为Exists

即容忍所有污点

四、固定节点调度

1、直接指定节点名称 (nodeName)

使用 spec.nodeName 直接指定节点名称后,会直接跳过调度器(Scheduler)的调度,而是直接匹配到你指定的node节点。

  apiVersion: v1
  kind: Pod
  metadata:
    name: nginx
  spec:
    nodeName: node-1  # 直接指定节点名称
    containers:
    - name: nginx
      image: nginx:1.24.0
  • 最直接、最高优先级的调度方式

  • 绕过调度器,直接绑定到指定节点

  • 如果节点不存在或资源不足,Pod 会保持 Pending 状态

  • 适用于开发和测试环境,生产环境不推荐

2、 节点选择器 (nodeSelector)

使用 spec.nodeSelector 直接指定节点标签后,由调度器(Scheduler)按照调度策略进行调度,之后匹配Pod到你指定的node节点,这是强制约束,类似硬性约束。

  apiVersion: v1
  kind: Pod
  metadata:
    name: nginx
  spec:
    containers:
    - name: nginx
      image: nginx:1.24.0
    nodeSelector:
      disktype: ssd  # 只调度到有 disktype=ssd 标签的节点
  • 简单易用

  • 只能简单匹配,不支持复杂表达式

  • 适用于简单的节点选择需求

  • 无节点满足则一直"Pending"

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值