
【集群】云原生批调度实战:Volcano 测试流程拆解

本系列《云原生批调度实战:Volcano 监控与性能测试》计划分为以下几篇,点击查看其它内容。
- 云原生批调度实战:调度器测试与监控工具 kube-scheduling-perf
- 云原生批调度实战:调度器测试与监控工具 kube-scheduling-perf 实操注意事项说明
- 云原生批调度实战:调度器测试监控结果
- 云原生批调度实战:本地环境测试结果与视频对比分析
- 监控与测试环境解析:测试流程拆解篇
- 监控与测试环境解析:指标采集与可视化篇
- 监控与测试环境解析:自定义镜像性能回归测试
- 监控与测试环境解析:数据收集方法深度解析与Prometheus Histogram误差问题
- 云原生批调度实战:Volcano调度器enqueue功能禁用与性能测试
- 云原生批调度实战:Volcano Pod创建数量不足问题排查与Webhook超时修复
- 云原生批调度实战:Volcano版本修改与性能测试优化
- 云原生批调度实战:Volcano Webhook禁用与性能瓶颈分析
- 云原生批调度实战:Volcano性能瓶颈猜想验证与实验总结
本文将以 Volcano 为代表,解析kube-scheduler-performance工具一次 调度器性能测试 从集群启动到结果归档的完整链路,搞清楚 每个步骤调用了哪些文件、各自作用是什么,为后续指标剖析与实验扩展打下基础。
阅读完本文,希望能够帮你快速实现:
- 复现最小规模的 Volcano 性能测试;
- 在源码中快速定位某一步骤的入口脚本 / YAML。
1️⃣ 执行链路总览
执行一次最小测试的命令非常简单:
1 | make prepare-volcano start-volcano end-volcano \ |
这背后却触发了 ≥ 10 个 Makefile 目标与 30+ 个 YAML / Shell / Go 文件。整体时序如图所示(流程简化,仅保留关键节点):
graph TD; A[prepare-volcano] --> B[up-volcano]; B --> C[kind 创建测试集群]; C --> D[wait-volcano]; D --> E[test-init-volcano]; A -.->|完成后调用| F[start-volcano]; F --> G[reset-auditlog-volcano]; G --> H[test-batch-job-volcano]; F -.-> |完成后调用| I[end-volcano]; I --> J[down-volcano];
Tips:
prepare-volcano → start-volcano → end-volcano
由根 Makefile 的define test-scheduler
宏在编译期自动展开。
宏展开示例:Volcano
define test-scheduler
是一个带占位符 $(1)
的宏,最后通过 $(foreach sched,$(SCHEDULERS),$(eval $(call test-scheduler,$(sched))))
对 kueue / volcano / yunikorn 进行循环替换。下面以 Volcano 为例简要对比“模板”与“实例”——
模板片段(截自 Makefile:110:140)
1 | define test-scheduler |
展开后(自动生成)的部分规则
1 |
|
借助这种“写一次、生成三份”的做法,大幅减少了针对不同调度器写重复 Make 目标的工作量。
2️⃣ 关键 Makefile 目标拆解
目标 | 所在文件 | 主要命令 | 职责说明 |
---|---|---|---|
prepare-volcano | 根 Makefile | make up-volcano make wait-volcano make test-init-volcano | 集群启动 + 基础就绪检查 + 预热测试二进制 |
up-volcano | clusters/volcano/Makefile | kind create cluster & 部署 Volcano | 创建 Kind 集群并应用 Volcano 相关 Kustomize 资源 |
wait-volcano | 同上 | kubectl wait --for=condition=Ready | 等待所有 Pod Ready,含 controller / scheduler |
test-init-volcano | 根 Makefile | 运行 bin/test-volcano -run ^TestInit | 生成初始队列、扩容节点 |
start-volcano | 根 Makefile | make reset-auditlog-volcano make test-batch-job-volcano | 清空上一轮 audit 日志 & 正式发压 |
reset-auditlog-volcano | clusters/volcano/Makefile | kubectl delete audit-log ConfigMap | 置空历史日志,保证数据窗口准确 |
test-batch-job-volcano | 根 Makefile | bin/test-volcano -run ^TestBatchJob | 按参数批量提交 Job / Pod 并记录时间线 |
end-volcano | 根 Makefile | make down-volcano | 销毁 Kind 集群,释放资源 |
3️⃣ clusters/volcano 目录速览
kind.yaml
:集群版本、节点数量、containerd 本地镜像仓库挂载;deployment.yaml
:Volcano Controller 与 Scheduler 部署模板;kustomization.yaml
:声明所有资源并支持image
覆盖;service.yaml
:暴露 Volcano webhook / metrics(如需)。
这些文件通过 kustomize build
管道被 up-volcano
目标应用到 Kind 集群中。
4️⃣ test/volcano 测试代码剖析
核心 Go 测试位于 test/volcano/
目录,包含两个主要测试函数和一套完整的 Provider 实现。整体思路:通过 Go 语言编写测试用例,调用 Kubernetes API 在真实集群中创建资源,模拟大规模批量调度场景。
TestInit 和 TestBatchJob 流程
1 | func TestInit(t *testing.T) { |
核心逻辑:
TestInit
:集群预热阶段,创建假节点(通过 KWOK)和配置 Volcano 队列层级TestBatchJob
:正式压测阶段,批量提交 Job 并等待调度完成
两个测试函数通过 **全局变量 provider
**(VolcanoProvider 实例)共享状态,测试参数从环境变量或 Makefile 传入。
参数传递机制解析
测试参数的传递遵循 Makefile → 环境变量 → Go Flag → Provider 实例 的四级链路:
1. Makefile 参数定义
1 | CPU_PER_NODE ?= 128 |
2. 环境变量注入
当执行 make test-batch-job-volcano
时,Makefile 会将上述变量作为环境变量传递给测试进程:
1 | TEST_ENVS = \ |
3. Go Flag 解析
test/volcano/main_test.go
中,provider.AddFlags()
调用 test/utils/option.go
的标准 flag 库:
1 | func (o *Options) AddFlags() { |
4. 优先级覆盖机制
参数读取有明确的优先级:命令行参数 > 环境变量 > 默认值
例如:
make test-batch-job-volcano NODES_SIZE=100
:通过 Makefile 变量传递NODES_SIZE=200 ./bin/test-volcano
:直接设置环境变量./bin/test-volcano -nodes-size=300
:命令行参数(最高优先级)
因此,当我们在前面代码中看到 p.CpuPerNode
、p.NodeSize
等字段时,它们的值最终来源于这套参数传递链路,确保了测试规模可以通过 Makefile 灵活调控。
VolcanoProvider 核心实现
1. AddNodes:批量创建假节点
1 | func (p *VolcanoProvider) AddNodes(ctx context.Context) error { |
解析:通过 utils.NewNodeBuilder()
构造器模式批量生成 Node 对象。关键点:
WithFastReady()
:设置节点状态为 Ready,跳过真实硬件检测WithCPU(p.CpuPerNode)
:每个节点的 CPU 容量(如 “128”)WithMemory(p.MemoryPerNode)
:每个节点的内存容量(如 “1024Gi”)
2. InitCase:配置 Volcano 调度器
关键代码片段:
1 | func (p *VolcanoProvider) InitCase(ctx context.Context) error { |
核心逻辑解析:
- 资源计算:根据队列数量计算总容量(
cpuCapabilityTotal
)和单队列配额(cpuCapability
) - 层级调度:如果设置了
CpuLendingLimit
,启用hierarchy=true
,计算deserved
(保证资源)和capability
(借用上限) - 动态配置:通过
unstructured.Unstructured
直接操作 CRD,避免导入 Volcano 依赖 - 热重启:更新 ConfigMap 后重启 Scheduler Pod,确保新配置生效
3. AddJobs:分批提交作业
1 | func (p *VolcanoProvider) AddJobs(ctx context.Context) error { |
策略解析:通过 三阶段提交 模拟真实多租户场景:
- 第一波:
long-term-research
队列,立即提交(delay=0) - 第二波:
business-impacting
队列,5秒后提交(模拟业务高峰) - 第三波:
human-critical
队列,再5秒后提交(模拟紧急任务)
每个阶段都有独立的 queueSize × jobsPerQueue × podsPerJob 三维参数,可灵活调整压测规模。
Volcano Job 模板解析
使用的是 Volcano CRD batch.volcano.sh/v1alpha1/Job
,关键字段:
1 | apiVersion: batch.volcano.sh/v1alpha1 |
模板机制解析:
- 模板语法:
#{{ .variable }}
由utils.YamlWithArgs()
在运行时替换 - Gang 调度:
minAvailable: #{{ .size }}
要求所有 Pod 同时就绪,模拟 MPI/AI 训练场景 - 资源隔离:
queue: #{{ .queue }}
指定队列,schedulerName: volcano
确保由 Volcano 调度 - 假负载:
nodeSelector: "type": kwok
强制调度到假节点,image: hello-world
秒级启动
实际执行过程:addSingleJobs()
调用 utils.YamlWithArgs()
将参数注入模板,再通过 decoder.DecodeEach()
解析 YAML 并调用 Kubernetes API 创建 Job。
技术要点总结:整个测试框架通过 sigs.k8s.io/e2e-framework
与真实 API Server 通信,产生的所有 API 调用都会被 audit-policy.yaml 记录,为后续指标分析提供数据源。
5️⃣ hack 脚本的幕后协同
脚本 | 触发时机 | 作用 |
---|---|---|
hack/kind-with-local-registry.sh | up-volcano 前 | 启动本地 5001 registry + 注入 containerd 配置(**在每个 Kind 节点的 /etc/containerd/certs.d/ 写入 hosts.toml **,指向本地仓库),实现“边拉边推、本地秒级拉取” |
hack/local-registry-with-load-images.sh | up-volcano 期间 | 将远端镜像拉取后重新打 tag 推到本地 registry,Kind 节点下载极快 |
hack/replace-qps.sh | 可选 | 修改 APIServer QPS,一键替换所有带 # <--QPS 注释的 YAML 中的数值,从而把 --kube-api-qps 或 webhook QPS 提到 1000+,缓解 API Server 限流 |
hack/save-result-images.sh | 测试结束后 | 调用 Grafana API 截图面板,写入 output/ 归档 |
containerd 配置注入示例
hack/kind-with-local-registry.sh
的核心逻辑:
1 | # Create kind cluster with containerd registry configuration |
核心原理:脚本为每个 Kind 节点在 /etc/containerd/certs.d/kind-registry:5000/hosts.toml
写入配置,告诉 containerd 优先从本地 registry 拉取镜像,实现离线加速。
修改 APIServer QPS 示例
当测试遇到 API Server QPS 瓶颈时,可以手动调用脚本,批量调整:
1 | # 把所有标记为 "# <--QPS" 的数值统一改为 2000 |
脚本核心逻辑:
1 | find . \ |
工作原理:遍历项目内所有 .yaml
文件,将包含 # <--QPS
标记行的数字替换为指定值。项目中共有 12 个文件、20+ 处配置受影响,包括调度器组件的 --kube-api-qps
/--kube-api-burst
和 Kind 集群的 kube-api-qps
参数。
6️⃣ 结语
至此,我们已经串起了 Volcano 性能测试的最小可运行链路,并定位了关键 Makefile 目标与 YAML / Go 源码。下一篇将深入 指标采集与可视化,详解 audit-exporter 如何把 CREATED / SCHEDULED / RUNNING
三条曲线绘制到同一张 Grafana 面板。
📌 实践练习:如果感兴趣,可以尝试把
JOBS_SIZE_PER_QUEUE
改为 2,再次运行测试,观察logs/
与results/
目录下是否出现新的时间戳文件夹,并查看面板截图差异。
- 希望这篇博客对你有帮助!如果你有任何问题或需要进一步的帮助,请随时提问。
- 如果你喜欢这篇文章,欢迎动动小手给我一个follow或star。
🗺参考文献
- 标题: 【集群】云原生批调度实战:Volcano 测试流程拆解
- 作者: Fre5h1nd
- 创建于 : 2025-07-27 16:21:35
- 更新于 : 2025-08-24 15:22:19
- 链接: https://freshwlnd.github.io/2025/07/27/k8s/k8s-scheduler-performance-volcano-process/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。