深入研究Kubernetes调度

“本文从 pod 和节点的配置开始,介绍了 kubernetes scheduler 框架、扩展点、api 以及可能发生的与资源相关的瓶颈,并展示了性能调整设置,涵盖了 kubernetes 中调度的大多方面。
kubernetes scheduler 是 kubernetes 控制平面的核心组件之一。它在控制平面上运行,将 pod 分配给节点,同时平衡节点之间的资源利用率。将 pod 分配给新节点后,在该节点上运行的 kubelet 会在 kubernetes api 中检索 pod 定义,根据节点上的 pod 规范创建资源和容器。换句话说,scheduler 在控制平面内运行,并将工作负载分配给 kubernetes 集群。
本文将对 kubernetes scheduler 进行深入研究,首先概述一般的调度以及具有亲和力(affinity)和 taint 的驱逐调度,然后讨论调度程序的瓶颈以及生产中可能遇到的问题,最后研究如何微调调度程序的参数以适合集群。
调度简介
kubernetes 调度是将 pod 分配给集群中匹配节点的过程。scheduler 监控新创建的 pod,并为其分配最佳节点。它会根据 kubernetes 的调度原则和我们的配置选项选择最佳节点。最简单的配置选项是直接在 podspec 设置 nodename:
apiversion: v1
kind: pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx
nodename: node-01
上面的 nginx pod 默认情况下将在 node-01 上运行,但是 nodename 有许多限制导致无法正常运行 pod,例如云中节点名称未知、资源节点不足以及节点网络间歇性问题等。因此,除了测试或开发期间,我们最好不使用 nodename。
如果要在一组特定的节点上运行 pod,可以使用 nodeselector。我们在 podspec 中将 nodeselector 定义为一组键值对:
apiversion: v1
kind: pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx
nodeselector:
disktype: ssd
对于上面的 nginx pod,kubernetes scheduler 将找到一个磁盘类型为 ssd 的节点。当然,该节点可以具有其他标签。我们可以在 kubernetes 参考文档中查看标签的完整列表。
地址:https://kubernetes.io/docs/reference/kubernetes-api/labels-annotations-taints/
使用 nodeselector 有约束 pod 可以在有特定标签的节点上运行。但它的使用仅受标签及其值限制。kubernetes 中有两个更全面的功能来表达更复杂的调度需求:节点亲和力(node affinity),标记容器以将其吸引到一组节点上;taint 和 toleration,标记节点以排斥 pod。这些功能将在下面讨论。
节点亲和力
节点亲和力(node affinity)是在 pod 上定义的一组约束,用于确定哪些节点适合进行调度,即使用亲和性规则为 pod 的节点分配定义硬性要求和软性要求。例如可以将 pod 配置为仅运行带有 gpu 的节点,并且最好使用 nvidia_tesla_v100 运行深度学习工作负载。scheduler 会评估规则,并在定义的约束内找到合适的节点。与 nodeselectors 相似,节点亲和性规则可与节点标签一起使用,但它比 nodeselectors 更强大。
我们可以为 podspec 添加四个相似性规则:
requiredduringschedulingignoredduringexecution
requiredduringschedulingrequiredduringexecution
preferredduringschedulingignoredduringexecution
preferredduringschedulingrequiredduringexecution
这四个规则由两个条件组成:必需或首选条件,以及两个阶段:计划和执行。以 required 开头的规则描述了必须满足的严格要求。以 preferred 开头的规则是软性要求,将强制执行但不能保证。调度阶段是指将 pod 首次分配给节点。执行阶段适用于在调度分配后节点标签发生更改的情况。
如果规则声明为 ignoredduringexecution,scheduler 在第一次分配后不会检查其有效性。但如果使用 requiredduringexecution 指定了规则,scheduler 会通过将容器移至合适的节点来确保规则的有效性。
以下是示例:
apiversion: v1kind: pod
metadata:
name: nginx
spec:
affinity:
nodeaffinity:
requiredduringschedulingignoredduringexecution:
nodeselectorterms:
- matchexpressions:
- key: topology.kubernetes.io/region
operator: in
values:
- us-east
preferredduringschedulingignoredduringexecution:
- weight: 1
preference:
matchexpressions:
- key: topology.kubernetes.io/zone
operator: in
values:
- us-east-1
- us-east-2
containers:
- name: nginx
image: nginx
上面的 nginx pod 具有节点亲和性规则,该规则让 kubernetes scheduler 将 pod 放置在 us-east 的节点上。第二条规则指示优先使用 us-east-1 或 us-east-2。
使用亲和性规则,我们可以让 kubernetes 调度决策适用于自定义需求。
taint 与 toleration
集群中并非所有 kubernetes 节点都相同。某些节点可能具有特殊的硬件,例如 gpu、磁盘或网络功能。同样,我们可能需要将一些节点专用于测试、数据保护或用户组。我们可以将 taint 添加到节点以排斥 pod,如以下示例所示:
kubectl taint nodes node1 test-environment=true:noschedule
使用 test-environment=true:noscheduletaint 时,除非在 podspec 具有匹配的 toleration,否则 kubernetes scheduler 将不会分配任何 pod:
apiversion: v1kind: pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx
tolerations:
- key: “test-environment”
operator: “exists”
effect: “noschedule”
taint 和 tolerations 共同发挥作用,让 kubernetes scheduler 专用于某些节点并分配特定 pod。
调度瓶颈
尽管 kubernetes scheduler 能选择最佳节点,但是在 pod 开始运行之后,“最佳节点”可能会改变。所以从长远来看,pod 的资源使用及其节点分配可能存在问题。
资源请求(request)和限制(limit):“noisy neighbor”
“noisy neighbor”并不特定于 kubernetes。任何多租户系统都是它们的潜在地。假设有两个容器 a 和 b,它们在同一节点上运行。如果 pod b 试图通过消耗所有 cpu 或内存来创造 noise,pod a 将出现问题。如果我们为容器设置了资源请求和限制就能控制住 neighbor。kubernetes 将确保为容器安排其请求的资源,并且不会消耗超出其资源限制的资源。如果在生产中运行 kubernetes,最好设置资源请求和限制以确保系统可靠。
系统进程资源不足
kubernetes 节点主要是连接到 kubernetes 控制平面的虚拟机。因此,节点上也有自己的操作系统和相关进程。如果 kubernetes 工作负载消耗了所有资源,则这些节点将无法运行,并会发生各种问题问题。我们需要在 kubelet 中使用 –system -reserved 设置保留资源,以防止发生这种情况。
抢占或调度 pod
如果 kubernetes scheduler 无法将 pod 调度到可用节点,则可以从节点抢占(preempt)或驱逐(evict)一些 pod 以分配资源。如果看到 pod 在集群中移动而没有发现特定原因,可以使用优先级类对其进行定义。同样,如果没有调度好 pod,并且正在等待其他 pod,也需要检查其优先级。
以下是示例:
apiversion: scheduling.k8s.io/v1kind: priorityclass
metadata:
name: high-priority-nonpreempting
value: 100000preemptionpolicy: neverglobaldefault: false
description: “this priority class will not preempt other pods.”
可以通过以下方式在 podspec 中为分配优先级:
apiversion: v1kind: pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx
priorityclassname: high-priority-nonpreempting
调度框架
kubernetes scheduler 具有可插拔的调度框架架构,可向框架添加一组新的插件。插件实现 plugin api,并被编译到调度程序中。下面我们将讨论调度框架的工作流、扩展点和 plugin api。
工作流和扩展点
调度 pod 包括两个阶段:调度周期(scheduling cycle)和绑定周期(binding cycle)。在调度周期中,scheduler 会找到一个可用节点,然后在绑定过程中,将决策应用于集群。
工作流中的以下几点对插件扩展开放:
queuesort:对队列中的 pod 进行排序
prefilter:检查预处理 pod 的相关信息以安排调度周期
filter:过滤不适合该 pod 的节点
postfilter:如果找不到可用于 pod 的可行节点,调用该插件
prescore:运行 prescore 任务以生成一个可共享状态供 score 插件使用
score:通过调用每个 score 插件对过滤的节点进行排名
normalizescore:合并分数并计算节点的最终排名
reserve:在绑定周期之前选择保留的节点
permit:批准或拒绝调度周期结果
prebind:执行任何先决条件工作,例如配置网络卷
bind:将 pod 分配给 kubernetes api 中的节点
postbind:通知绑定周期的结果
插件扩展实现了 plugin api,是 kubernetes scheduler 的一部分。我们可以在 kubernetes 存储库中检查。插件应使用以下名称进行注册:
// plugin is the parent type for all the scheduling framework plugins.
type plugin interface {
name() string
}
插件还实现了相关的扩展点,如下所示:
// queuesortplugin is an interface that must be implemented by “queuesort” plugins.
// these plugins are used to sort pods in the scheduling queue. only one queue sort plugin may be enabled at a time.
type queuesortplugin interface {
plugin
// less are used to sort pods in the scheduling queue.
less(*queuedpodinfo, *queuedpodinfo) bool
}
scheduler 性能调整
kubernetes scheduler 有一个工作流来查找和绑定 pod 的可行节点。当集群中的节点数量非常多时,scheduler 的工作量将成倍增加。在大型集群中,可能需要很长时间才能找到最佳节点,因此要微调调度程序的性能,以在延迟和准确性之间找到折中方案。
percentageofnodestoscore 将限制节点的数量来计算自己的分数。默认情况下,kubernetes 在 100 节点集群的 50% 和 5000 节点集群的 10% 之间设置线性阈值。默认最小值为 5%,它要确保至少考虑集群中 5% 节点的调度。
下面的示例展示了如何通过性能调整 kube-scheduler 来手动设置阈值:
apiversion: kubescheduler.config.k8s.io/v1alpha1
kind: kubeschedulerconfiguration
algorithmsource:
provider: defaultprovider
percentageofnodestoscore: 50
如果有一个庞大的集群并且 kubernetes 工作负载不能承受 kubernetes scheduler 引起的延迟,那么更改百分比是个好主意。
总结
本文涵盖了 kubernetes 调度的大多方面,从 pod 和节点的配置开始,包括 nodeselector、亲和性规则、taint 和 toleration,然后介绍了 kubernetes scheduler 框架、扩展点、api 以及可能发生的与资源相关的瓶颈,最后展示了性能调整设置。尽管 kubernetes scheduler 能简单地将 pod 分配给节点,但是了解其动态性并对其进行配置以实现可靠的生产级 kubernetes 设置至关重要。
原文链接:https://thenewstack.io/a-deep-dive-into-kubernetes-scheduling/
作者:ron sobol. 翻译:bach(才云)
校对:星空下的文仔(才云)、bot(才云)


柔宇科技推出了全新升级的第三代蝉翼全柔性屏
redis的持久化方式RDB和AOF的区别
DTU配电终端产品的工作原理与特点功能分析
隐藏在Microsoft Designer背后的新科技,让人人都是设计师
精密列头柜电源管理系统
深入研究Kubernetes调度
到底什么是人工智能对于人工智能而言到底什么才是最重要的
如何设计一个三极管放大电路
守望产业朝阳,622“潮电”在行动
大幅改进物联网路线图,英特尔让物联网开发不再复杂
摩托罗拉p50入网 6GB+128GB版售价2499元
三星电子推出新款图像传感器ISOCELL 缩短中端智能手机开发周期有望
脉冲信号怎么产生
SKYLAB:带PA、传输距离更远的蓝牙网关TD05A
雷柏新款键盘来袭,颜值与实力皆在线不容错过
国务委员兼外长王毅表示华为是百分之百的民营企业
基于CS42L37设计的低功耗音频CODEC技术
多家手机厂商抱团: 担心苹果垄断OLED供应
低功耗WiFi模块,让智能穿戴更便捷
LG手机国内销量惨淡,G6或不在中国发售