K8S——PaaS平台pod调度机制

发布于:2025-03-29 ⋅ 阅读:(27) ⋅ 点赞:(0)

1、 Pod调度

1.1、 pod调度概述

开始前,先来看看磐基 Kubernetes 的架构示意图,其中控制平面包含以下三大组件:kube-scheduler、kube-apiserver、kube-controller-manager,kubelet 及 kube-proxy 组件为工作节点(node)服务,本次重点梳理核心组件之一的kube-scheduler。

kube-scheduler ,主要负责pod的调度,监听 kube-apiserver,查询未分配 Node 的 Pod(未分配、分配失败及尝试多次无法分配),根据配置的调度策略,将 Pod 调度到最优的工作节点上,从而高效、合理的利用集群的资源,帮助用户提升效率、降低能耗。

kube-scheduler 负责将 Pod 调度到集群内的最佳节点(基于相应策略计算出的最佳值)上,它监听 kube-apiserver,查询还未分配节点的 Pod,然后根据调度策略为这些 Pod 分配节点,执行绑定节点的操作(更新 Pod 的 nodeName 字段)。

pod调度过程中,需要考虑以下问题:

  1. 如何确保节点分配的公平性
  2. 如何确保节点资源分配的高效性
  3. 如何确保Pod调度的公平性
  4. 如何确保Pod调度的高效性
  5. 如何扩展Pod调度策略

为了解决上述的问题,kube-scheduler 通过汇集节点资源、节点地域、节点镜像、Pod调度等信息综合决策,确保Pod分配到最佳节点,以下为 kube-scheduler 的主要目标:

  1. 公平性:在调度Pod时需要公平的决策,每个节点都有被分配的机会,调度器需要针对不同节点作出平衡决策。
  2. 资源高效:最大化提升所有可调度资源的利用率,使有限的 CPU、内存等资源服务尽可能更多的 Pod。
  3. 性能:能快速的完成对大规模Pod的调度工作,在集群规模扩增的情况下,依然能确保调度的性能。
  4. 灵活性:在实际生产中,用户希望 Pod 的调度策略是可扩展的,从而可以定制化调度算法以处理复杂的实际问题。因此平台要允许多种调度器并行工作,并支持自定义调度器。
调度流程

首先通过下面整体的交互图,来构建 Pod 调度的直观感受。

上述以创建一个Pod为例,简要介绍调度流程:

  1. 用户通过命令行创建 Pod(选择直接创建 Pod 而不是其他 workload,是为了省略 kube-controller-manager);
  2. kube-apiserver 经过对象校验、admission、quota等准入操作,写入etcd;
  3. kube-apiserver 将结果返回给用户;
  4. 同时 kube-scheduler 一直监听节点、Pod事件等(流程1);
  5. kube-scheduler 将 spec.nodeName 的 pod 加入到调度队列中,进行调度周期(流程2-3
  6. kube-scheduler 将 pod 与得分最高的节点进行 binding 操作(流程4
  7. kube-apiserver 将 binding 信息写入 etcd
  8. kubelet 监听分配给自己的Pod,调用 CRI 接口进行 Pod 创建
  9. kubelet 创建 Pod 后,更新 Pod 状态等信息,并向 kube-apiserver 上报
  10. kube-apiserverPod 状态等信息数据写入到etcd

通过kube-scheduler实现pod容器的完全自动化调度,调度流程分为:调度周期Scheduling Cycle和绑定周期Binding Cycle,其中调度周期细分为过滤filter和weight重,按照指定的调度策略将满足运行pod节点的主机筛选出来,然后进行排序;绑定周期是经过kube-scheduler调度优选的pod后,由特定node节点上的kubelet 服务watch到创建pod的events,然后通过kubelet创建并运行。

过滤阶段包含预选Predicate和scoring排序,预选是筛选满足条件的node,排序是满足条件的node打分并排序,预选的算法包含有:

  • CheckNodeConditionPred   节点是否ready
  • MemoryPressure             节点内存是否压力大(内存是否足够)
  • DiskPressure                  节点磁盘压力是否大(空间是否足够)
  • PIDPressure                   节点Pid是否有压力(Pid进程是否足够)
  • GeneralPred                   匹配pod.spec.hostname字段
  • MatchNodeSelector         匹配pod.spec.nodeSelector标签
  • PodFitsResources           判断resource定义的资源是否满足
  • PodToleratesNodeTaints    能容忍的污点pod.spec.tolerations
  • CheckNodeLabelPresence
  • CheckServiceAffinity
  • CheckVolumeBinding
  • NoVolumeZoneConflict

过滤条件需要检查node上满足的条件,可以通过kubectl describe node node-ip方式查看,如下图:

优选调度算法有:

  • least_requested  资源消耗最小的节点
  • balanced_resource_allocation 各项资源消耗最均匀的节点
  • node_prefer_avoid_pods  节点倾向
  • taint_toleration  污点检测,检测有污点条件的node,得分越低
  • selector_spreading  节点selector
  • interpod_affinity      pod亲和力遍历
  • most_requested      资源消耗最大的节点
  • node_label             node标签

kubernetes提供了四大类调度方式:

  1. 默认的自动调度:运行在哪个节点上完全由Scheduler经过一系列的算法计算得出。

kube-scheduler的主要作用就是根据特定的调度算法和调度策略将Pod调度到合适的Node节点上去,是一个独立的二进制程序,启动之后会一直监听API Server,获取Pod Spec.NodeName为空的Pod,对每个Pod都会创建一个binding。

  kube-scheduler给一个pod做调度包含两个步骤,具体流程如下:

  1.)首先,客户端通过API Server的REST API或者kubectl 工具创 Pod资源API Server收到用户请求后,存储相关数据到etcd数据库中

  2.)调度器监听API Server查看到还未被调度(bind)的Pod列表,循环遍历地为每个 Pod 尝试分配节点。

    a.)预选阶段(Predicates),过滤节点,调度器用一组规则过滤掉不符合要求的 Node 节点,比如 Pod 设置了资源的 request,那么可用资源比 Pod 需要的资源少的主机显然就会被过滤掉

    b.)优选阶段(Priorities),为节点的优先级打分,将上一阶段过滤出来的 Node 列表进行打分,调度器会考虑一些整体的优化策略,比如把 Deployment 控制的多个 Pod 副本尽量分布到不同的主机上使集群主机资源使用尽量均衡,使用最低负载的主机等等策略

经过上面的阶段过滤后选择打分最高的 Node 节点和 Pod 进行 binding 操作,然后将结果存储到 etcd 中 最后被选择出来的 Node 节点对应的 kubelet 去执行创建 Pod 的相关操作(当然也是 watch APIServer 发现的)。

  最后,kube-scheduler会将Pod调度到得分最高的Node上。如果存在多个得分最高的Node,kube-scheduler会从中随机选取一个。最后,调度器将这个调度决定告知kube-apiserver,这个过程叫做绑定(Binding)。
2)定向调度:NodeName,NodeSelector
3)亲和性调度:NodeAffinity,PodAffinity,PodAntiAffinity
4)污点(容忍)调度:Taints,Toleration

2. 高级调度

2. 1指定nodeName调度

nodeName是PodSpec中的一个字段,可以通过pod.spec.nodeName指定将pod调度到某个具体的node节点上,该字段比较特殊一般都为空,如果有设置nodeName字段,kube-scheduler会直接跳过调度,在特定节点上通过kubelet启动pod。通过nodeName调度并非是集群的智能调度,通过指定调度的方式可能会存在资源不均匀的情况,建议设置Guaranteed的Qos,防止资源不均时候Pod被驱逐evince。如下以创建一个pod运行在node-3上为例:

QoS类型:

Guaranteed - 所有的 container[s] 的 cpu 、 memory 有 limit 和 request, 且 limit 和 request 值相等

Burstable - 不符合 Guaranteed, 且有 cpu 或 memory 的 request或者request小于limit

BestEffort -  limit 和 request或者limit 和 request的值均为0

1.编写yaml将pod指定在node-3节点上运行

2.运行yaml配置使之生效

3.查看确认pod的运行情况,已运行在node-3节点

2.2 通过nodeSelector调度

4.给node-2添加labels

5.查看校验labels设置情况,node-2增加多了一个app=web的labels

6.通过nodeSelector将pod调度到app=web所属的labels

7.应用yaml文件生成pod

8.检查验证pod的运行情况,已经运行在node-2节点

系统默认预先定义有多种内置的labels,这些labels可以标识node的属性,如arch架构,操作系统类型,主机名等

  • beta.kubernetes.io/arch=amd64
  • beta.kubernetes.io/os=linux
  • kubernetes.io/arch=amd64
  • kubernetes.io/hostname=node-3
  • kubernetes.io/os=linux

2.3 node Affinity and anti-affinity

affinity/anti-affinity和nodeSelector功能相类似,相比于nodeSelector,affinity的功能更加丰富,未来会取代nodeSelector,affinity增加了如下的一些功能增强:

  1. 表达式更加丰富,匹配方式支持多样,如In,NotIn, Exists, DoesNotExist. Gt, and Lt;
  2. 可指定soft和preference规则,soft表示需要满足的条件,通过requiredDuringSchedulingIgnoredDuringExecution来设置,preference则是优选选择条件,通过preferredDuringSchedulingIgnoredDuringExecution指定
  3. affinity提供两种级别的亲和和反亲和:基于node的node affinity和基于pod的inter-pod affinity/anti-affinity,node affinity是通过node上的labels来实现亲和力的调度,而pod affinity则是通过pod上的labels实现亲和力的调度,两者作用的范围有所不同。

下面通过一个例子来演示node affinity的使用,requiredDuringSchedulingIgnoredDuringExecution指定需要满足的条件,preferredDuringSchedulingIgnoredDuringExecution指定优选的条件,两者之间取与关系。

1.查询node节点的labels,默认包含有多个labels,如kubernetes.io/hostname

2.通过node affiinity实现调度,通过requiredDuringSchedulingIgnoredDuringExecution指定满足条件kubernetes.io/hostname为node-2和node-3,通过preferredDuringSchedulingIgnoredDuringExecution优选条件需满足app=web的labels

3.应用yaml文件生成pod

4.确认pod所属的node节点,满足require和 preferre条件的节点是node-2


网站公告

今日签到

点亮在社区的每一天
去签到