0%

K8s-调度问题

Kubernetes的调度和资源限制问题

调度

在Kubernetes中,调度(Scheduling),指的是为 Pod 找到一个合适的节点,并由该节点上的 kubelet 运行 Pod。

概述

每当集群中有新的 Pod 创建时,Kubernetes 调度器将负责为其找到最合适的节点去运行。调度器按照本文后面描述的原则执行执行调度工作。如果您想了解为什么 Pod 被分配到了具体的某一个节点,或者您打算自己实现一个定制化的调度器,本文可以帮助您更好的理解 Kubernetes 的调度工作

kube-scheduler

kube-scheduler是 Kubernetes 中默认的调度器,并且运行在 Master 组件中。

kube-scheduler 虽然是默认的调度器,但是,在需要的时候,可以自定义调度器以替代 kube-scheduler。

对于每一个新创建的或者未调度的 Pod,kube-scheduler 为其选择一个合适的节点去运行。问题是,每一个 Pod 以及其中的每一个容器,都有不同的资源需求,在调度时,必须选择那些能够满足 Pod 的资源需求的节点才可以。

集群中能够满足某一个 Pod 的资源需求的节点,称为 可选节点(feasible node)。如果某一个 Pod 没有合适的 可选节点,则该 Pod 将一直停留在 Pending 状态,直到集群中出现了对于该 Pod 来说合适的 可选节点

调度器在执行调度时,执行的步骤如下:

  1. 找出该 Pod 的所有 可选节点
  2. 按照某种方式对每一个 可选节点 评分
  3. 选择评分最高的 可选节点
  4. 将最终选择结果通知 API Server,这个过程,称为绑定(binding)

在为 可选节点 评分时,需要考虑的因素有:

  • 单个 Pod 和所有 Pod 的资源需求
  • 硬件、软件、策略(Policy,例如Limit Range、Resource Quota等)
  • 亲和与反亲和(affinity and anti-affinity)
  • 数据存储的位置
  • 工作负载之间的相互影响,等。

使用kube-scheduler调度

kube-schduler在执行调度时,将上述过程分成两个阶段来执行:

  1. Filtering (筛选/过滤)
  2. Scoring (评分)

Filtering(筛选/过滤)阶段,kube-scheduler找出所有对待调度的 Pod 来说合适的 可选节点。例如,PodFitsResources 过滤器检查候选节点是否具备足够的资源可以满足 Pod 的资源需求。在筛选阶段结束后,通常可以找出多个 可选节点,如果没有找到,则 Pod 一直停留在 Pending 状态。

Scoring(评分)阶段,kube-scheduler 先按照当前可用的评分规则为每一个 可选节点 频分, 然后,按评分结果对所有的 可选节点 排序,以找出最适合 Pod 运行的节点。

最后,kube-scheduler 将 Pod 分配到评分最高的 可选节点。如果有多个节点评分一样且最高,kube-scheduler 将随机从中选择一个节点。

Filtering

Filtering(筛选/过滤)阶段,使用的过滤器有:

  • PodFitsHostPorts: 检查Pod需要的 hostPort 在该节点上是否可用
  • PodFitsHost:检查 Pod 是否通过 hostname 指定了节点,
  • PodFitsResource:检查节点是否满足 Pod 的资源需求(例如,CPU 和 Memory)
  • PodMatchNodeSelector:检查 Pod 的节点选择器(nodeSelector)是否和节点的标签匹配
  • NoVolumeZoneConflict:评估 Pod 所需要的 数据卷是否在节点上可用(数据卷的 failure zone restrictions)
  • NoDiskConflict:评估Pod请求的数据卷是否和节点已经加载的数据卷冲突
  • MaxCSIVolumeCount:计算节点可以挂载多少个 CSI(Container Storage Interface)数据卷,确保不会超出限定的数字
  • CheckNodeMemoryPressure:检查节点是否有内存紧张的情况
  • CheckNodePIDPressure:检查节点是否有 PID 短缺的情况
  • CheckNodeDiskPressure:检查节点是否有存储空间吃紧的情况(文件系统已满,或者将要满)
  • CheckNodeCondition:检查节点的 Condition 字段,该字段中包含关于 文件系统已满网络不可用kubelet未就绪 等相关的条件
  • PodToleratesNodeTaints:检查 Pod 是否容忍 Pod 的污点
  • CheckVolumeBinding:检查存储卷声明是否可绑定

Scoring

  • SelectorSpreadPriority:将 Pod 分散到不同的节点,主要考虑同属于一个 Service、StatefulSet、Deployment的情况
  • InterPodAffinityPriority:遍历 weightedPodAffinityTerm 并求和,找出结果最高的节点
  • LeastRequestedPriority:已被消耗的资源最少的节点得分最高。如果节点上的 Pod 越多,被消耗的资源越多,则评分约低
  • MostRequestedPriority:已被消耗的资源最多的节点得分最高。此策略会把 Pod 尽量集中到集群中的少数节点上
  • RequestedToCapacityRatioPriority:按 requested / capacity 的百分比评分
  • BalancedResourceAllocation:资源使用均衡的节点评分高
  • NodePreferAvoidPodsPriority:根据节点的 annotation scheduler.alpha.kubernetes.io/preferAvoidPods 评分。可使用此 annotation 标识哪些 Pod 不能够运行在同一个节点上
  • NodeAffinityPriority:基于 PreferredDuringSchedulingIgnoredDuringExecution 指定的 node affinity 偏好评分。
  • TaintTolerationPriority: 根据节点上不可容忍的污点数评分
  • ImageLocalityPriority:有限选择已经有该 Pod 所需容器镜像的节点
  • ServiceSpreadingPriority:确保 Service 的所有 Pod 尽量分布在不同的节点上。
  • CalculateAntiAffinityPriorityMap:anti-affinty
  • EqualPriorityMap:为每个节点指定相同的权重

策略

默认情况下,容器在 Kubernetes 集群上运行时,不受计算资源的限制。使用 Resource quota,集群管理员可以针对名称空间限定资源的使用情况。在名称空间内部,一个 Pod(或容器)的资源消耗不受限制。此时的顾虑在于,可能有一个 Pod(或容器)独占了名称空间的大部分资源。Limit Range 是一种用来限定名称空间内 Pod(或容器)可以消耗资源数量的策略(Policy)。

Kubernetes LimitRange 对象可以:

  • 限制名称空间中每个 Pod 或容器的最小最大计算资源
  • 限制名称空间中每个 PersistentVolumeClaim 可使用的最小最大存储空间
  • 限制名称空间中计算资源请求request、限定limit之间的比例
  • 设置名称空间中默认的计算资源的 request/limit,并在运行时自动注入到容器中

启用 Limit Range

执行命令 kubectl api-resources 可查看集群是否支持 Limit Range( 通常 LimitRange 是默认启用的 ),输出结果如下所示:

1
2
[root@k8s-master 0426]# kubectl api-resources | grep limit
limitranges limits true LimitRange

基本介绍

  • 集群管理员在名称空间中创建一个 LimitRange 对象
  • 用户在名称空间中创建工作负载等对象,例如 Pod、Container、PersistentVolumeClaim 等
  • 针对那些没有设置计算资源请求 request 和限制 limit 的 Pod 和容器,LimitRanger 根据名称空间中的 LimitRange 对象为其设定默认的资源请求和响应,并确保 Pod 和容器对计算资源的实际消耗不会超过指定的值
  • 如果创建或更新对象(Pod、Container、PersistentVolumeClaim)的请求与 Limit Range 的限定相冲突,apiserver 将返回 HTTP status 状态码 403 FORBIDDEN,以及相应的错误提示信息
  • 如果名称空间中激活了 limit range 来限定 cpu 和内存等计算资源的使用,则用户创建 Pod、Container 时,必须指定 cpu 或内存的 requestlimit,否则系统将拒绝创建 Pod
  • Kubernetes 只在 Pod 创建阶段检查 LimitRange 的限定,而不在 Pod 运行时执行任何检查

使用 LimitRange 的例子有:

  • 在一个总容量为 8G内存 16核CPU 的 2 节点集群上,限定某个名称空间中的 Pod 使用 100m的CPU请求(request)且不超过 500m的CPU上限(limit),200Mi的内存请求(request)且不超过 600Mi的内存上线(limit)
  • 为没有定义cpu和内存请求的容器,指定默认的 CPU 请求(request)和限制(limit)均为 150m,默认的内存请求为 300Mi

当名称空间总的 limit 小于名称空间中 Pod/Container 的 limit 之和时,将发生资源争夺的现象,容器或者 Pod 将不能创建。

在资源争夺现象发生时,或者修改 limitrange 的时候,这两种情况都不会影响到已经创建的 Pod/Container。