Kubernetes调度器深度解析:从资源分配到亲和性策略的架构师之路
目录
专栏介绍
作者与平台
您将学到什么?
学习特色
Kubernetes调度器深度解析:从资源分配到亲和性策略的架构师之路
第一部分:调度器工作原理——Pod的“空中交通管制”全流程揭秘
1.1 调度器的生命周期与核心循环
1.2 调度框架:现代调度器的可扩展架构
1.3 过滤阶段:从“所有”到“可行”的严格筛选
1.4 打分阶段:从“可行”到“最优”的智能决策
第二部分:资源限制——为Pod申请和划定“专属领地”的艺术
2.1 requests与limits的深层含义
2.2 QoS(Quality of Service)等级:集群资源紧张时的生存法则
2.3 实践示例与架构师决策
第三部分:亲和性与反亲和性调度——Pod的“社交”智慧
3.1 节点亲和性
3.2 Pod亲和性与反亲和性
总结:从调度器到集群资源策略的升华
专栏介绍
作者与平台
作者:庸子
用户ID:2401_86478612
第一发表平台:CSDN
欢迎来到《Kubernetes架构师之路:系统化学习与实践》专栏!在这个容器化技术主导的时代,Kubernetes已成为云原生应用编排的事实标准,掌握Kubernetes已成为每位开发者和运维工程师的必备技能。
本专栏采用系统化学习方法,从基础概念到高级实践,循序渐进地带您全面掌握Kubernetes技术栈。无论您是刚接触容器技术的初学者,还是希望深入理解Kubernetes架构的资深工程师,这里都将为您提供清晰的学习路径和实用的实战指导。
您将学到什么?
- 基础理论:深入理解容器、容器编排、Kubernetes核心概念和架构设计
- 核心组件:掌握etcd、API Server、Controller Manager、Scheduler等核心组件的工作原理
- 资源管理:学会Pod、Deployment、Service、Ingress等核心资源的创建与管理
- 网络与存储:理解Kubernetes网络模型和存储方案,解决实际部署中的网络与存储问题
- 高可用与扩展:构建高可用的Kubernetes集群,实现应用的自动扩展与故障恢复
- 监控与日志:掌握集群监控、日志收集与应用性能优化方法
- CI/CD集成:学习如何将Kubernetes与CI/CD流程结合,实现自动化部署
- 安全实践:了解Kubernetes安全模型,掌握RBAC、网络策略等安全配置
学习特色
- 系统化知识体系:从零开始,构建完整的Kubernetes知识框架
- 实战导向:每个知识点都配有实际操作案例,让您"学以致用"
- 问题驱动:针对实际部署中常见的问题提供解决方案
- 最新版本覆盖:基于最新稳定版Kubernetes,紧跟技术发展趋势
- 架构师视角:不仅教您"如何做",更解释"为什么这样设计"
无论您是想提升个人竞争力,还是为企业构建高效的云原生基础设施,本专栏都将助您成为真正的Kubernetes专家。让我们一起开启这段激动人心的Kubernetes学习之旅!
立即订阅,开启您的Kubernetes架构师成长之路!
Kubernetes调度器深度解析:从资源分配到亲和性策略的架构师之路
Hello 大家好,在云原生的世界里,Kubernetes已然成为分布式应用的基石。而在这个复杂的操作系统中,调度器扮演着“内核调度器”的角色,其决策的优劣直接决定了整个集群的效率、稳定性和成本效益。它不是简单的资源分配器,而是一个复杂的、可扩展的、基于策略的决策引擎。
今天,我们将戴上架构师的显微镜,对Kubernetes调度器的三大核心支柱——工作原理、资源限制以及亲和性与反亲和性调度——进行一次彻底的、不留死角的解剖。我们将深入源码逻辑,探讨设计哲学,并结合真实世界的复杂场景,力求让每一位读者都能站在架构师的高度,彻底掌握驾驭Kubernetes调度能力的艺术。
第一部分:调度器工作原理——Pod的“空中交通管制”全流程揭秘
想象一个全球顶级的国际机场,每天都有数以万计的飞机(Pod)请求起降。空中交通管制系统(Scheduler)的核心职责,就是为每一架飞机规划出最优的跑道(Node)和时间窗口,确保整个机场的运行高效、安全且有序。Kubernetes调度器正是这样一个系统,它是一个独立运行在控制平面的组件,通过kube-scheduler进程实现。
1.1 调度器的生命周期与核心循环
kube-scheduler启动后,其核心是一个永不停止的循环。它通过Kubernetes的Informer机制,持续监听API Server中Pod和Node的资源变化。它的主要工作可以概括为以下几个步骤:
监听:持续关注API Server,一旦发现有新的Pod被创建且状态为Pending(同时nodeName字段为空),调度器就会将其放入内部的调度队列中。
调度:从队列中取出一个Pod,执行我们即将详细剖析的“过滤”和“打分”流程,为其选择一个最优的Node。
绑定:一旦做出决策,调度器会向API Server发送一个Binding API请求,将Pod的nodeName字段更新为目标节点的名称。
异步执行:目标节点上的kubelet组件会监听到与自己相关的Pod的Binding事件,随后开始在本节点上拉取镜像、创建容器并启动Pod。
这个流程是异步的,调度器只负责“决策”,不负责“执行”。这种职责分离的设计是Kubernetes高可用的关键。
1.2 调度框架:现代调度器的可扩展架构
在早期,调度器的逻辑是硬编码的。为了增强其可扩展性,Kubernetes引入了调度框架。它不是一个新组件,而是kube-scheduler内部的一套插件化架构,将调度过程定义为一系列的“扩展点”,每个扩展点都注册了相应的插件。
主要扩展点包括:
QueueSort:对调度队列中的Pod进行排序。默认插件是PrioritySort,根据Pod的priorityClassName确定优先级。
PreFilter:在过滤阶段之前进行预处理或预检查,用于快速排除一些明显不符合条件的Pod或节点。
Filter:就是我们熟知的“过滤”阶段。每个插件都会对节点进行判断,只要有一个插件返回false,节点就会被淘汰。
PostFilter:当所有节点都无法通过过滤阶段时调用,可用于实现“抢占”逻辑(即高优先级Pod驱逐低优先级Pod)。
PreScore:在打分阶段之前进行一些状态准备。
Score:就是我们熟知的“打分”阶段。每个插件都会对节点打分(通常是0-10分),最终分数是所有插件分数的加权和。
NormalizeScore:对最终的分数进行标准化处理。
Reserve:在调度器即将向API Server发送Binding请求前调用。它会在调度器的缓存中“预留”这个Pod在目标节点上的位置,以防止在Bind完成前有其他Pod被调度到同一位置,造成资源冲突。
Permit:这是一个非常特殊的扩展点,可以阻止或延迟Bind操作。例如,可以用于实现外部系统(如安全策略检查)的审批。
PreBind:在Bind之前执行,可用于执行一些准备工作,如挂载外部存储。
Bind:执行实际的绑定操作,向API Server发送Binding请求。
PostBind:在Bind成功后执行,可用于清理或记录日志。
这个框架使得我们可以通过开发自定义插件,轻松地扩展调度器的功能,而无需修改其核心代码。例如,可以实现一个基于GPU型号、网络延迟或成本的调度插件。
1.3 过滤阶段:从“所有”到“可行”的严格筛选
这是调度的第一道关卡,目标是快速、高效地排除掉所有不符合Pod基本运行需求的节点。这个过程是严格的、非黑即白的,任何一个规则不满足,该节点就会被立即淘汰。以下是几个核心的Filter插件及其工作细节:
NodeUnschedulable:最简单的过滤器。检查节点的spec.unschedulable字段是否为true。这个状态通常由管理员通过kubectl cordon <node-name>(禁止调度)或kubectl drain <node-name>(驱逐并禁止调度)命令设置,用于节点维护。
NodeName:检查Pod的spec.nodeName字段是否已指定。如果已指定,则只检查该节点是否存在且健康。
PodFitsResources:这是最核心的过滤器。它会检查节点的可分配资源是否满足Pod的resources.requests。
关键细节:它比较的是requests,而不是limits。调度器只关心你“保证”需要多少,而不关心你“最多”能用多少。
计算逻辑:它会从节点的status.allocatable字段中,减去该节点上所有已调度Pod(包括正在Reserve状态的Pod)的requests总和,得到剩余可用资源。然后与当前待调度Pod的requests进行比较。
PodFitsHostPorts:检查Pod的spec.containers.ports.hostPort是否与节点上已存在的其他Pod的hostPort冲突。这是一个避免端口抢占的简单但必要的检查。
NodeAffinity:检查Pod是否定义了nodeAffinity中的requiredDuringSchedulingIgnoredDuringExecution规则。如果定义了,只有节点的标签满足这些规则的“硬性要求”,节点才能通过此过滤器。这里的匹配逻辑支持In, NotIn, Exists, DoesNotExist, Gt, Lt等多种操作符。
TaintToleration:这是实现节点隔离和专用化的核心机制。节点可以被“污染”,例如Master节点默认有node-role.kubernetes.io/control-plane:NoSchedule的污点。Pod则可以声明“容忍”,表明自己可以接受某些污点。只有当Pod的容忍度能够“覆盖”节点的污点时,该Pod才能被调度到此节点。一个Pod可以容忍多个污点,一个节点也可以有多个污点,它们之间是“与”的关系。污点效果有三种:
NoSchedule:新Pod不能调度上来,但已在运行的Pod不受影响。
PreferNoSchedule:调度器会尽量避免,但没有强制禁止。
NoExecute:新Pod不能调度上来,且已在运行的不容忍该污点的Pod会被驱逐。
经过这一轮严格的筛选,调度器会得到一个可行节点列表。如果这个列表为空,Pod将一直处于Pending状态,并且调度器会生成一个FailedScheduling事件,通过kubectl describe pod <pod-name>可以查看到具体原因(例如 “0/3 nodes are available: 3 Insufficient memory”)。
1.4 打分阶段:从“可行”到“最优”的智能决策
现在,调度器手上有了一份“入围”的节点列表。但哪个才是“最佳选择”呢?调度器会对列表中的每个节点进行打分,分数范围通常是0-10分(某些插件可能给更高分)。得分最高的节点将成为Pod的最终归宿。如果多个节点得分相同,调度器会从中随机选择一个,以避免总是倾向于某个特定节点。
以下是几个核心的Score插件及其评分逻辑:
NodeResourcesMostAllocated / NodeResourcesLeastAllocated:这两个插件是互斥的,默认启用NodeResourcesLeastAllocated。
NodeResourcesLeastAllocated(即旧版的LeastRequestedPriority)的目标是实现负载均衡。它的评分公式大致为:score = (sum(requested_resources) / sum(node_capacity))。也就是说,节点上已分配的资源比例越低,得分就越高。这会促使Pod被均匀地分散到集群中,避免出现“热点”节点。
NodeResourcesMostAllocated则相反,它会倾向于将Pod填满已经有很多资源的节点,用于“装箱”场景,目的是为了节省资源,关闭空闲节点。
BalancedResourceAllocation:这个函数的目标是资源均衡。它倾向于选择CPU和内存资源分配更均衡的节点。例如,如果一个节点CPU已请求90%,但内存只请求了20%,而另一个节点CPU和内存都请求了50%,那么后者的得分会更高。这可以防止某种特定资源(如CPU)成为瓶颈。
ImageLocalityPriority:这个函数非常智能。它会检查Pod所需容器镜像是否已存在于节点上。如果一个节点已经拥有Pod所需的全部镜像,它会得到最高分。如果拥有部分镜像,得到中等分数。如果完全没有镜像,得0分。这极大地缩短了Pod的启动时间,因为Kubelet无需再去远程仓库拉取镜像。
InterPodAffinityPriority:根据Pod的亲和/反亲和性规则进行打分。满足亲和性偏好或避免反亲和性冲突的节点会获得更高分数。
NodeAffinityPriority:根据节点的软性亲和性规则进行打分。满足preferredDuringSchedulingIgnoredDuringExecution规则的节点会获得额外的加权分数。
工作流程可视化:
graph TD
subgraph 控制平面
A[用户创建Pod] --> B{API Server};
B --> C[Pod状态: Pending, nodeName: ""];
C --> D{Scheduler Watch到新Pod};
D --> E[放入调度队列];
end
subgraph 调度器内部
E --> F[从队列取出Pod];
F --> G[过滤阶段];
subgraph 过滤阶段
G1[NodeUnschedulable]
G2[PodFitsResources]
G3[TaintToleration]
G4[NodeAffinity]
end
G --> H{生成可行Node列表?};
H -- 否 --> I[Pod保持Pending, 生成FailedScheduling事件];
H -- 是 --> J[打分阶段];
subgraph 打分阶段
J1[NodeResourcesLeastAllocated]
J2[BalancedResourceAllocation]
J3[ImageLocalityPriority]
J4[InterPodAffinityPriority]
end
J --> K[选择得分最高的Node];
K --> L[在缓存中Reserve];
L --> M[向API Server发送Binding请求];
end
subgraph 目标Node
M --> N{API Server};
N --> O[更新Pod的nodeName];
O --> P[Kubelet监听到变化];
P --> Q[创建并启动Pod];
Q --> R[Pod状态: Running];
end
第二部分:资源限制——为Pod申请和划定“专属领地”的艺术
在一个多租户的集群环境中,如果没有资源限制,一个“贪婪”的应用可能会耗尽节点的所有资源,导致其他应用无响应甚至崩溃,引发“雪崩效应”。Requests和Limits就是Kubernetes用来解决这个问题的核心机制,它们是Kubernetes资源模型的基石,其背后是Linux内核的cgroups技术。
2.1 requests与limits的深层含义
requests(资源请求):保证Pod能够获得的资源量。这是Kubernetes向Pod做出的承诺。它有两个关键作用:
调度依据:如前所述,调度器使用requests来决定Pod可以调度到哪个节点。这是Kubernetes进行资源规划和容量管理的根本。
资源分配:当一个Pod被调度到节点上后,Kubelet会使用requests来设置Pod的cgroup。
对于CPU,requests值会被转换为cpu.shares。cpu.shares是一个相对权重值,默认是1024。一个requests: "500m"(0.5核)的Pod,其cpu.shares会被设置为512。当CPU资源紧张时,内核会按照shares的比例来分配CPU时间片。但这并不保证它总能获得0.5核,只有在所有Pod都争抢CPU时,这个比例才生效。
对于内存,requests主要作用于Kubernetes的内存回收和驱逐策略。Kubelet会确保节点上所有Pod的memory.requests之和不超过节点的allocatable内存。
limits(资源限制):限制Pod能够使用的资源上限。当Pod尝试使用超过limits的资源时:
CPU:CPU是可压缩资源。如果Pod尝试使用超过其CPU limit的算力,系统会对其进行限流,Pod的CPU使用率会被严格限制在limit值,但Pod不会被终止,只是性能会下降。
内存:内存是不可压缩资源。当Pod尝试使用超过其内存limit时,它会被Linux内核的OOM Killer(Out of Memory Killer)直接杀死。Kubelet会检测到这一点,并将Pod的状态标记为OOMKilled,然后根据其重启策略进行重启。
2.2 QoS(Quality of Service)等级:集群资源紧张时的生存法则
Kubernetes根据requests和limits的设置,将Pod分为三种QoS等级。当节点资源不足时,Kubelet会根据这个等级来决定优先驱逐哪些Pod,以释放资源保障更重要的服务。这是一个架构师必须深刻理解的概念。
| QoS等级 | requests与limits的关系 | cgroup设置 | 描述 | 驱逐优先级 |
| Guaranteed | CPU和内存的requests等于limits | cpu.cfs_quota_us和cpu.cfs_period_us被精确设置,实现硬限制。内存有硬限制。 | 资源有保证,性能最稳定。适用于对性能和稳定性要求极高的核心业务,如数据库、核心API、ETCD。 | 最低(最后被驱逐) |
| Burstable | requests和limits设置不同,或只设置了requests | CPU有cpu.shares,可能有cpu.cfs_quota_us。内存有memory.soft_limit_in_bytes(软限制)和硬限制。 | 资源有保证,但可以弹性扩展。当节点资源紧张时,只要其使用量未超过requests,就不会被优先驱逐。适用于大多数Web应用、微服务。 | 中等 |
| BestEffort | requests和limits均未设置 | CPU只有默认的cpu.shares(1024),内存无限制。 | “尽力而为”,没有资源保证。可以使用节点上任何空闲资源,但也是节点资源紧张时最先被牺牲的对象。适用于临时任务、批处理作业或CI/CD的Runner。 | 最高(最先被驱逐) |
Kubelet的驱逐策略:当节点内存不足时,Kubelet会根据Pod的QoS等级和内存使用情况来选择牺牲品。
首先驱逐BestEffort Pod。
如果内存依然不足,开始驱逐Burstable Pod。它会优先驱逐那些内存使用量远超其requests的Burstable Pod。
Guaranteed Pod只有在系统内核需要内存才能继续运行时,才会被OOM Killer杀死,这是最后的手段。
2.3 实践示例与架构师决策
# QoS: Burstable
# 保证了基本性能,同时具备弹性。这是最常见的配置。
apiVersion: v1
kind: Pod
metadata:
name: web-app
spec:
containers:
- name: nginx
image: nginx
resources:
requests:
memory: "256Mi" # Kubelet会为这个Pod预留256MiB内存
cpu: "250m" # 相当于0.25个vCPU,Kubelet会设置cpu.shares为256
limits:
memory: "512Mi" # 如果Pod内存使用超过512MiB,会被OOMKilled
cpu: "500m" # Pod的CPU使用率被严格限制在50%以内
---
# QoS: Guaranteed
# 性能和稳定性最高,但资源利用率可能较低,成本高。
apiVersion: v1
kind: Pod
metadata:
name: database
spec:
containers:
- name: postgres
image: postgres
resources:
requests:
memory: "2Gi"
cpu: "1000m"
limits:
memory: "2Gi" # requests和limits完全一致
cpu: "1000m"
---
# QoS: BestEffort
# 资源利用率最高,但最不稳定。适用于可中断的任务。
apiVersion: v1
kind: Pod
metadata:
name: batch-job
spec:
containers:
- name: data-processor
image: my-batch-processor:latest
# 完全没有resources字段
架构师视角:
容量规划:你的集群总容量(所有节点的allocatable资源之和)必须大于等于所有核心和重要Pod的requests总和。这是保证服务可用的底线。
成本与稳定性:Guaranteed Pod提供了最好的SLA,但成本也最高,因为资源被独占,即使空闲也不能被他人使用。Burstable是性价比和稳定性的最佳平衡点。BestEffort则用于最大化利用碎片化资源。
性能调优:对于CPU密集型应用,可以设置较高的requests来获得更多的cpu.shares,在争抢时获得优势。对于内存密集型且有波峰波谷的应用,可以设置requests接近平均值,limits接近峰值,以实现成本和性能的平衡。
第三部分:亲和性与反亲和性调度——Pod的“社交”智慧
有时,我们需要的不仅仅是“有资源就行”的调度。我们可能希望将某些Pod部署在一起以减少网络延迟,或者将某些Pod分散部署以实现高可用。这就是亲和性与反亲和性策略发挥作用的地方,它们让Pod的调度变得“智能化”和“策略化”。
3.1 节点亲和性
节点亲和性允许你根据节点上的标签来约束Pod可以调度到哪些节点。它比nodeName或nodeSelector更强大、更灵活。
requiredDuringSchedulingIgnoredDuringExecution:硬性要求。Pod必须被调度到满足条件的节点上,否则会一直Pending。这相当于过滤规则。
preferredDuringSchedulingIgnoredDuringExecution:软性偏好。调度器会优先尝试将Pod调度到满足条件的节点上,但如果无法满足,Pod也会被调度到其他节点。这相当于打分规则。
IgnoredDuringExecution 的含义是,如果节点的标签在Pod运行后发生变化,不再满足亲和性规则,Kubernetes不会将Pod重新调度到其他节点。
示例:将Pod调度到拥有SSD硬盘且位于特定可用区的节点上
# 首先,给节点打上标签
# kubectl label nodes node-1 disktype=ssd zone=us-west-2a performance=high
# kubectl label nodes node-2 disktype=hdd zone=us-west-2b
apiVersion: v1
kind: Pod
metadata:
name: with-node-affinity
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values:
- ssd
- nvme
- key: zone
operator: In
values:
- us-west-2a
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100 # 权重,1-100
preference:
matchExpressions:
- key: performance
operator: In
values:
- high
containers:
- name: app
image: nginx
解读:这个Pod必须调度到标签为disktype=ssd或nvme并且zone=us-west-2a的节点上(node-1)。在满足这个条件的节点中,如果某个节点还有performance=high的标签,它会获得100分的额外加分,从而更有可能被选中。
3.2 Pod亲和性与反亲和性
Pod亲和/反亲和性是基于已运行的Pod的标签来进行调度决策,而不是节点标签。这允许你表达“和XX Pod在一起”或“远离XX Pod”的意图。
核心概念:topologyKey
topologyKey定义了亲和/反亲和作用的“范围”或“域”。它必须是一个节点标签,决定了调度器在哪个维度上判断“在一起”或“分开”。
kubernetes.io/hostname:作用域是单个节点。Pods在同一台物理机上。
topology.kubernetes.io/zone:作用域是单个可用区。Pods在同一个可用区内,但可能在不同物理机上。
topology.kubernetes.io/region:作用域是单个地理区域。Pods在同一个区域内,但可能在不同的可用区。
Pod亲和性示例:将Web服务部署在与其缓存服务相同的节点上
# 假设已经有一个缓存服务Pod运行在node-1上
# apiVersion: v1
# kind: Pod
# metadata:
# name: cache-pod
# labels:
# app: cache
# spec:
# nodeName: node-1
# ...
apiVersion: v1
kind: Pod
metadata:
name: web-server
labels:
app: web
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- cache
topologyKey: "kubernetes.io/hostname" # 必须和cache Pod在同一个Node上
containers:
- name: web
image: nginx
解读:这个web-server Pod只会被调度到已经运行了至少一个带有app=cache标签的Pod的节点上(即node-1)。这可以最大化本地网络通信,减少延迟,适用于对网络性能要求极高的场景。
Pod反亲和性示例:将高可用的API服务分散到不同节点上
这是一个实现高可用的经典用例。我们希望API服务的多个副本尽量不要运行在同一个节点上,以防单点故障。
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-server-ha
spec:
replicas: 3
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution: # 使用软性要求,增加弹性
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- api
topologyKey: "kubernetes.io/hostname" # 尽量不和同标签的Pod在同一个Node
containers:
- name: api
image: my-api:1.0
解读:当调度这个Deployment的第二个Pod时,调度器会查看第一个Pod所在的节点,并给该节点打一个低分(因为违反了反亲和性)。它会更倾向于选择一个不同的节点。这里使用preferred而不是required,是为了增加弹性:如果你的集群只有2个节点,但你设置了3个副本,使用required会导致第三个Pod永远无法调度。使用preferred则允许它和其中一个Pod部署在同一节点,保证了服务的可用性。
跨可用区反亲和性:为了实现更高的容灾能力,可以将topologyKey设置为topology.kubernetes.io/zone,确保Pod副本分散在不同的可用区。
架构师视角:
性能优化:使用Pod亲和性将紧密耦合的服务(如Web+缓存,日志收集代理+业务应用)部署在一起,可以显著降低网络延迟,提升性能。
高可用设计:使用Pod反亲和性是构建无单点故障架构的必备手段。将关键服务的副本分散到不同的故障域(节点、可用区)是保障业务连续性的基础。
成本与性能的权衡:Pod亲和/反亲和性需要大量的计算(因为要遍历所有Pod及其所在节点),在超大规模集群中可能对调度器性能产生影响。同时,强制性的反亲和性(required)可能导致资源利用率下降(例如,每个节点只运行一个副本)。架构师需要在高可用性、性能和成本之间做出权衡。
组合使用:可以将节点亲和性和Pod亲和/反亲和性组合使用,实现非常复杂的调度策略。例如,先将一组Pod调度到特定的可用区(节点亲和性),然后再在该可用区内将它们分散到不同节点(Pod反亲和性)。
总结:从调度器到集群资源策略的升华
掌握了调度器,你就掌握了Kubernetes集群资源分配的命脉。在下一篇文章中,我们将继续深入,探讨更高级的调度主题,如自定义调度器、调度框架的实际应用以及Descheduler的作用,敬请期待!
