SchedSim 是一个面向云原生调度团队的仿真测试平台,用于对 Kubernetes 调度器生态组件(kube-scheduler、crane-scheduler、descheduler、pooling-scheduler)进行全方位测试验证,包括功能正确性、算法有效性、性能基准和组件协调。
| 目标 | 描述 |
|---|---|
| 易用性 | 通过 WebUI 可视化编排测试场景,降低测试门槛 |
| 可扩展性 | 插件化架构,支持新增调度组件和测试类型 |
| 灵活部署 | 支持二进制、Docker、Kubernetes 三种部署方式 |
| 仿真能力 | Kind + KWOK 模拟大规模集群,也可对接真实集群 |
| 集群镜像 | 将线上集群状态镜像到本地/新集群,用于生产评估和新算法验证 |
| 报告体系 | 自动生成、持久化、下载测试报告 |
| 日志管理 | 统一日志收集、查看、可配置保留策略 |
| 混沌测试 | 内置 Chaos 故障注入能力,验证调度器容错和恢复 |
| 热加载 | 运行时动态调整集群配置、调度器参数 |
| 组件 | 类型 | 说明 |
|---|---|---|
| kube-scheduler | 调度器 | Kubernetes 默认调度器,基于 Scheduler Framework 插件体系 |
| crane-scheduler | 调度器插件 | 负载感知动态调度插件(Filter + Score),基于 Prometheus 指标 |
| descheduler | 重调度器 | 基于策略的 Pod 驱逐和重平衡(LowNodeUtilization、LoadBalance 等) |
| pooling-scheduler | 调度器 | 分片池化调度器,kube-scheduler 的高性能替代方案(与 kube-scheduler 互斥,二选一) |
重要约束:pooling-scheduler 和 kube-scheduler 是互斥关系,同一集群中只能部署其中之一。系统在组件部署时需做互斥校验。
┌─────────────────────────────────────────────────────────────────┐
│ WebUI (React + Ant Design) │
│ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌──────────────┐ │
│ │场景/模板│ │环境管理 │ │报告中心 │ │日志中心 │ │系统设置/权限 │ │
│ └────────┘ └────────┘ └────────┘ └────────┘ └──────────────┘ │
└────────────────────────┬────────────────────────────────────────┘
│ REST API / WebSocket
┌────────────────────────┴────────────────────────────────────────┐
│ API Gateway Layer │
│ ┌──────┐ ┌──────┐ ┌──────────┐ ┌────────┐ ┌────────────────┐ │
│ │ Auth │ │ CORS │ │ RateLimit │ │ Logger │ │ RequestTracing │ │
│ └──────┘ └──────┘ └──────────┘ └────────┘ └────────────────┘ │
└────────────────────────┬────────────────────────────────────────┘
│
┌────────────────────────┴────────────────────────────────────────┐
│ Core Service Layer │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────────┐ │
│ │ EnvTmpl Svc │ │ Environ Svc │ │ Test Execution Svc │ │
│ │ (环境模板) │ │ (环境管理·独立)│ │ (测试执行引擎) │ │
│ └──────────────┘ └──────────────┘ └──────────────────────┘ │
│ │
│ ┌──────────────┐ │
│ │ScenarioTmpl │ │
│ │Svc (场景模板) │ │
│ └──────────────┘ │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────────┐ │
│ │ Report Svc │ │ Plugin Svc │ │ Config Svc │ │
│ │ (报告管理) │ │ (插件管理) │ │ (配置热加载) │ │
│ └──────────────┘ └──────────────┘ └──────────────────────┘ │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────────┐ │
│ │ Log Svc │ │ Mirror Svc │ │ Chaos Svc │ │
│ │ (日志管理) │ │ (集群镜像) │ │ (混沌测试) │ │
│ └──────────────┘ └──────────────┘ └──────────────────────┘ │
│ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ User Svc │ │ Audit Svc │ │
│ │ (用户/权限) │ │ (审计日志) │ │
│ └──────────────┘ └──────────────┘ │
└────────────────────────┬────────────────────────────────────────┘
│
┌────────────────────────┴────────────────────────────────────────┐
│ Infrastructure Layer │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Cluster Provisioner │ │
│ │ ┌──────────┐ ┌──────────┐ ┌────────────────────────┐ │ │
│ │ │ Kind Mgr │ │ KWOK Mgr │ │ External Cluster Conn │ │ │
│ │ └──────────┘ └──────────┘ └────────────────────────┘ │ │
│ │ ┌──────────────────────────────────────────────────────┐ │ │
│ │ │ Cluster Mirror Engine │ │ │
│ │ │ (线上集群 → 本地/新集群 状态镜像) │ │ │
│ │ └──────────────────────────────────────────────────────┘ │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Component Deployer │ │
│ │ ┌────────────┐ ┌───────────┐ ┌────────────┐ ┌────────┐ │ │
│ │ │ KubeSched │ │ CraneSched│ │ Descheduler│ │Pooling │ │ │
│ │ │ Deployer │ │ Deployer │ │ Deployer │ │Deployer│ │ │
│ │ └────────────┘ └───────────┘ └────────────┘ └────────┘ │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────────┐ │
│ │ SQLite/PG │ │ File Store │ │ Metrics Collector │ │
│ │ (元数据) │ │ (报告/制品) │ │ (Prometheus) │ │
│ └──────────────┘ └──────────────┘ └──────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Log Collector & Storage │ │
│ │ (组件日志、执行日志、集群事件日志的收集和持久化) │ │
│ └──────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
| 层级 | 技术 | 理由 |
|---|---|---|
| 前端框架 | React 18 + TypeScript | 生态丰富,适合复杂交互式编辑器 |
| UI 组件库 | Ant Design 5 | 企业级组件库,表单/表格/布局完善 |
| 可视化编排 | React Flow | 节点式流程编辑器,适合测试场景DAG编排 |
| 图表 | ECharts / Ant Design Charts | 集群指标和测试报告可视化 |
| 后端框架 | Gin (Go) | 高性能、中间件生态丰富、WebSocket 支持好 |
| 认证 | JWT + 可插拔 OAuth Provider | 先实现用户名密码,预留 OAuth 接口 |
| 数据库 | SQLite (单机) / PostgreSQL (集群) | SQLite 零依赖易部署,PG 适合生产环境 |
| ORM | GORM | Go 生态最成熟的 ORM |
| 环境管理 | Kind Go API + KWOK CRD | 编程式集群创建和节点模拟 |
| K8s 客户端 | client-go | 官方 Go 客户端 |
| 配置管理 | Viper | 支持热加载、多格式配置 |
| 日志 | zap | 高性能结构化日志 |
| 前端嵌入 | Go embed | 编译时嵌入前端静态文件,单二进制部署 |
| 容器构建 | Docker multi-stage | 前端构建 + Go 编译,最终 distroless 镜像 |
| K8s 部署 | Helm Chart | 标准 K8s 部署方式 |
sched-sim/
├── cmd/ # 应用入口
│ └── schedsim/
│ └── main.go # 主程序入口
├── internal/ # 内部包(不对外暴露)
│ ├── api/ # API 层
│ │ ├── handler/ # HTTP Handler
│ │ │ ├── auth.go
│ │ │ ├── env_template.go
│ │ │ ├── scenario_template.go
│ │ │ ├── cluster.go
│ │ │ ├── execution.go
│ │ │ ├── report.go
│ │ │ ├── config.go
│ │ │ ├── plugin.go
│ │ │ ├── log.go
│ │ │ └── mirror.go
│ │ ├── middleware/ # 中间件
│ │ │ ├── auth.go
│ │ │ ├── cors.go
│ │ │ ├── logger.go
│ │ │ └── ratelimit.go
│ │ ├── router/ # 路由定义
│ │ │ └── router.go
│ │ └── ws/ # WebSocket 处理
│ │ └── hub.go
│ ├── service/ # 业务逻辑层
│ │ ├── env_template.go # 环境模板管理
│ │ ├── scenario_template.go # 场景模板管理
│ │ ├── environment.go # 环境管理
│ │ ├── execution.go # 测试执行
│ │ ├── report.go # 报告管理
│ │ ├── user.go # 用户管理
│ │ ├── config.go # 配置管理
│ │ ├── plugin.go # 插件管理
│ │ ├── log.go # 日志管理
│ │ └── mirror.go # 集群镜像
│ ├── model/ # 数据模型
│ │ ├── env_template.go
│ │ ├── scenario_template.go
│ │ ├── cluster.go
│ │ ├── execution.go
│ │ ├── report.go
│ │ ├── user.go
│ │ ├── plugin.go
│ │ ├── log.go
│ │ └── mirror.go
│ ├── store/ # 数据存储层
│ │ ├── db.go # 数据库初始化
│ │ ├── env_template_repo.go
│ │ ├── scenario_template_repo.go
│ │ ├── cluster_repo.go
│ │ ├── execution_repo.go
│ │ ├── report_repo.go
│ │ └── user_repo.go
│ ├── engine/ # 测试执行引擎
│ │ ├── runner.go # 测试运行器
│ │ ├── validator.go # 结果验证器
│ │ ├── collector.go # 指标收集器
│ │ └── reporter.go # 报告生成器
│ ├── cluster/ # 集群管理引擎
│ │ ├── provisioner.go # 集群供应接口
│ │ ├── kind.go # Kind 集群管理
│ │ ├── kwok.go # KWOK 节点模拟
│ │ ├── external.go # 外部集群连接
│ │ ├── mirror/ # 集群镜像引擎
│ │ │ ├── snapshot.go # 快照采集
│ │ │ ├── transform.go # 快照转换(脱敏、KWOK化)
│ │ │ └── apply.go # 快照应用
│ │ ├── chaos/ # Chaos 引擎
│ │ │ ├── engine.go # Chaos 执行引擎
│ │ │ ├── actions.go # 内置 Chaos 动作
│ │ │ └── recovery.go # 故障恢复
│ │ └── deployer/ # 组件部署器
│ │ ├── deployer.go # 部署器接口
│ │ ├── kube_scheduler.go
│ │ ├── crane_scheduler.go
│ │ ├── descheduler.go
│ │ └── pooling_scheduler.go
│ ├── plugin/ # 插件系统
│ │ ├── registry.go # 插件注册中心
│ │ ├── loader.go # 插件加载器
│ │ └── types.go # 插件接口定义
│ └── auth/ # 认证授权
│ ├── jwt.go # JWT 实现
│ ├── provider.go # 认证 Provider 接口
│ ├── local.go # 本地用户名密码认证
│ └── oauth.go # OAuth Provider (预留)
├── pkg/ # 可导出的公共包
│ ├── types/ # 公共类型定义
│ │ ├── env_template.go
│ │ ├── scenario_template.go
│ │ ├── cluster.go
│ │ └── report.go
│ └── utils/ # 工具函数
│ ├── k8s.go
│ └── file.go
├── web/ # 前端项目
│ ├── src/
│ │ ├── pages/ # 页面组件
│ │ │ ├── Login/
│ │ │ ├── Dashboard/
│ │ │ ├── EnvTemplates/ # 环境模板管理
│ │ │ ├── ScenarioEditor/ # 场景模板编排器
│ │ │ ├── TemplateMarket/ # 模板市场(环境+场景两个Tab)
│ │ │ ├── EnvironmentManager/ # 环境管理
│ │ │ ├── Execution/ # 测试执行
│ │ │ ├── Reports/ # 报告中心
│ │ │ └── Settings/ # 系统设置
│ │ ├── components/ # 通用组件
│ │ ├── services/ # API 调用
│ │ ├── stores/ # 状态管理
│ │ ├── hooks/ # 自定义 Hooks
│ │ └── utils/ # 工具函数
│ ├── package.json
│ ├── tsconfig.json
│ └── vite.config.ts
├── deploy/ # 部署配置
│ ├── docker/
│ │ └── Dockerfile
│ ├── helm/
│ │ └── schedsim/
│ │ ├── Chart.yaml
│ │ ├── values.yaml
│ │ └── templates/
│ └── scripts/
│ └── install.sh
├── configs/ # 配置文件模板
│ ├── schedsim.yaml # 主配置文件
│ └── examples/ # 示例配置
│ ├── kube-scheduler-config.yaml
│ ├── crane-scheduler-policy.yaml
│ ├── descheduler-policy.yaml
│ └── pooling-scheduler-config.yaml
├── design/ # 设计文档
├── rules/ # AI 开发规则
├── commands/ # AI 命令
├── skills/ # AI 技能
├── hooks/ # AI 钩子
├── refPrj/ # 参考项目(已有)
├── test/ # 测试目录
├── go.mod
├── go.sum
├── Makefile
└── README.md
┌─────────────────────────────────────────┐
│ Auth Module │
│ │
│ ┌─────────────────────────────────┐ │
│ │ AuthProvider Interface │ │
│ │ + Authenticate(cred) → Token │ │
│ │ + ValidateToken(token) → Claims │ │
│ │ + RefreshToken(token) → Token │ │
│ └──────────┬──────────────────────┘ │
│ │ │
│ ┌────────┴────────┐ │
│ │ │ │
│ ┌─┴──────────┐ ┌──┴───────────┐ │
│ │ LocalAuth │ │ OAuthAuth │ │
│ │ (用户名密码) │ │ (OAuth2/OIDC)│ │
│ └─────────────┘ └──────────────┘ │
│ │
│ RBAC: │
│ - admin: 全部权限 │
│ - operator: 执行测试、查看报告 │
│ - viewer: 只读 │
└─────────────────────────────────────────┘
认证流程:
- 用户通过
/api/v1/auth/login提交凭证 - AuthProvider 验证凭证,返回 JWT Token(access_token + refresh_token)
- 后续请求通过
Authorization: Bearer <token>头携带 token - Auth 中间件验证 token 并注入用户信息到 context
- OAuth 对接时只需实现
OAuthAuthProvider,注册到 Provider 链即可
预留 OAuth 接口:
type AuthProvider interface {
Name() string
Authenticate(ctx context.Context, credential Credential) (*TokenPair, error)
ValidateToken(ctx context.Context, token string) (*Claims, error)
RefreshToken(ctx context.Context, refreshToken string) (*TokenPair, error)
// OAuth 扩展
GetAuthURL(state string) string // 获取 OAuth 授权 URL
HandleCallback(ctx context.Context, code string) (*TokenPair, error) // 处理 OAuth 回调
}模板分为两类,彻底解耦:
| 模板类型 | 描述 | 回答的问题 |
|---|---|---|
| 环境模板 | 集群类型、节点规模、调度组件及镜像 | "在什么环境上测" |
| 场景模板 | 测试步骤 DAG、断言、指标采集、成功条件 | "测什么" |
解耦的价值:
- 同一环境验证不同场景(如同一个 100 节点环境,分别跑负载感知测试和 Chaos 测试)
- 同一场景在不同环境对比(如同一个负载感知测试,分别在 50 节点和 500 节点环境跑,对比性能)
- 环境模板和场景模板独立导入导出、独立版本管理
执行时组合:
┌──────────────┐ ┌──────────────┐
│ 环境模板 │ │ 场景模板 │
│ (或已有环境) │ │ (测试步骤) │
│ │ │ │
│ · 集群类型 │ │ · Deploy │
│ · 节点规模 │ + │ · Assert │ → 执行测试 → 报告
│ · 调度组件 │ │ · Validate │
│ · 组件镜像 │ │ · Metrics │
│ · 组件配置 │ │ · 成功条件 │
└──────────────┘ └──────────────┘
# 环境模板定义示例
apiVersion: schedsim.io/v1
kind: EnvironmentTemplate
metadata:
name: "100-node-crane-env"
description: "100 节点 KWOK 仿真环境,部署 crane-scheduler"
labels:
scale: "100"
components: "crane-scheduler"
spec:
cluster:
provider: kind+kwok
kindConfig:
kubernetesVersion: "v1.28.0"
controlPlane: 1
workers: 3
kwokConfig:
simulatedNodes: 100
nodeTemplates:
- count: 80
cpu: "8"
memory: "32Gi"
labels: { "node-type": "general" }
- count: 20
cpu: "16"
memory: "64Gi"
labels: { "node-type": "high-mem" }
components:
- name: kube-scheduler
enabled: true
image: "registry.k8s.io/kube-scheduler:v1.28.0"
- name: crane-scheduler
enabled: true
image: "my-registry/crane-scheduler:dev-abc123"
config: |
apiVersion: scheduler.policy.crane.io/v1alpha1
kind: DynamicSchedulerPolicy
spec:
syncPolicy:
- name: cpu_usage_avg_5m
period: 3m
predicate:
- name: cpu_usage_avg_5m
maxLimitPecent: 0.65
extraConfig:
prometheusAddr: "http://prometheus:9090"
lifecycle:
defaultExpiry: 24h
expiryAction: notify测试场景采用 DAG(有向无环图)方式编排,不包含任何环境信息。
# 场景模板定义示例
apiVersion: schedsim.io/v1
kind: ScenarioTemplate
metadata:
name: "crane-loadaware-test"
description: "测试 crane-scheduler 负载感知调度在高负载场景下的表现"
labels:
testType: e2e
category: load-aware
spec:
# 对环境的最低要求(非强制,仅作为提示)
envRequirements:
minNodes: 10
requiredComponents: ["crane-scheduler"]
# 测试步骤(DAG)
steps:
- id: setup-workload
name: "部署测试工作负载"
type: deploy
spec:
resources:
- apiVersion: apps/v1
kind: Deployment
metadata:
name: stress-test
spec:
replicas: 50
template:
spec:
schedulerName: crane-scheduler
containers:
- name: stress
image: progrium/stress
resources:
requests:
cpu: "500m"
memory: "256Mi"
dependsOn: []
- id: wait-scheduled
name: "等待 Pod 调度完成"
type: assertion
spec:
condition: "all_pods_scheduled"
timeout: 300s
selector:
labelSelector: "app=stress-test"
dependsOn: [setup-workload]
- id: validate-distribution
name: "验证负载均衡分布"
type: validation
spec:
validator: load-distribution
params:
maxSkewPercent: 20
metric: cpu_usage
dependsOn: [wait-scheduled]
- id: collect-metrics
name: "采集调度指标"
type: metrics-collection
spec:
metrics:
- scheduling_latency_p99
- scheduling_throughput
- node_utilization_variance
duration: 60s
dependsOn: [wait-scheduled]
# 通过/失败判定
successCriteria:
- step: validate-distribution
status: passed
- step: collect-metrics
condition: "scheduling_latency_p99 < 500ms"步骤类型:
| 类型 | 说明 | 用途 |
|---|---|---|
deploy |
部署 K8s 资源 | 创建 Deployment、Pod、Service 等 |
assertion |
断言检查 | 等待条件满足(Pod Ready、调度完成等) |
validation |
结果验证 | 验证调度质量(负载均衡、亲和性等) |
metrics-collection |
指标采集 | 收集 Prometheus 指标 |
config-update |
配置更新 | 热更新调度器参数 |
scale |
扩缩容 | 调整节点数/Pod数 |
chaos |
故障注入 | 节点故障、Pod 驱逐、网络分区、资源压力等 |
custom |
自定义脚本 | 运行自定义验证脚本 |
核心设计原则:环境管理是独立于测试执行的一等公民。用户可以只用平台管理环境(创建集群、部署组件、导出 kubeconfig),而不使用平台的测试引擎。
┌───────────────────────────────────────────────────────────┐
│ Environment Manager (独立能力) │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ ClusterProvisioner Interface │ │
│ │ + Create(config) → ClusterHandle │ │
│ │ + Delete(id) error │ │
│ │ + GetKubeConfig(id) → *rest.Config │ │
│ │ + ExportKubeConfig(id) → string ← 导出供外部使用 │ │
│ │ + GetStatus(id) → ClusterStatus │ │
│ └──────────┬────────────────────────────────────────────┘ │
│ │ │
│ ┌────────┼────────────┐ │
│ ┌─┴──────┐ ┌┴─────────┐ ┌┴──────────────┐ │
│ │ Kind │ │ Kind+KWOK│ │ External │ │
│ │Provider│ │ Provider │ │ Provider │ │
│ └────────┘ └──────────┘ └───────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ ComponentDeployer Interface │ │
│ │ + Deploy(cluster, component, config) │ │
│ │ + Undeploy(cluster, component) │ │
│ │ + UpdateConfig(cluster, component, cfg) │ │
│ │ + SwapImage(cluster, component, newImage) ← 换镜像 │ │
│ │ + GetStatus(cluster, component) │ │
│ └──────────┬────────────────────────────────────────────┘ │
│ │ │
│ ┌────────┼──────┬──────────┬──────────┐ │
│ ┌─┴──────┐┌┴─────┐┌┴────────┐┌┴────────┐ │
│ │KubeSch ││Crane ││Desched ││Pooling │ │
│ │Deployer││Deploy││Deployer ││Deployer │ │
│ └────────┘└──────┘└─────────┘└─────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Lifecycle Manager │ │
│ │ + SetExpiry(id, duration) ← 设置自动过期 │ │
│ │ + ExtendExpiry(id, duration) ← 延长过期时间 │ │
│ │ + CleanupResources(id, scope) ← 清理测试资源 │ │
│ │ + ResetEnvironment(id) ← 重置到初始状态 │ │
│ │ + Destroy(id) ← 完全销毁 │ │
│ │ + CheckExpiry() → []Expired ← 定时检查过期环境 │ │
│ └──────────────────────────────────────────────────────┘ │
└───────────────────────────────────────────────────────────┘
环境生命周期状态:
创建中 → 就绪 → [使用中] → 已过期 → 已销毁
Creating Ready InUse Expired Destroyed
│
├─ 平台执行测试(可选)
├─ 外部使用(kubectl / CI)
└─ 空闲(仅保留环境)
Kind + KWOK 集群创建流程:
- 调用 Kind Go API 创建基础集群(控制面 + 可选真实 worker)
- 等待集群就绪
- 安装 KWOK Controller(通过 kubectl apply 或 Helm)
- 创建 KWOK Stage CRD(定义模拟 Pod 生命周期)
- 创建 KWOK 模拟节点(通过 Node 对象 + kwok.x-k8s.io/node annotation)
- 部署目标调度组件(如果用户选择了)
- 返回集群句柄 + 导出 kubeconfig
外部集群连接:
- 用户提供 kubeconfig 或 ServiceAccount Token
- 系统验证连接和权限
- 可选:创建独立 namespace 进行测试隔离
- 环境保持连接状态,用户自行决定何时断开
环境清理策略:
| 策略 | 操作 | 环境状态 |
|---|---|---|
| 保留 | 不做任何清理 | Ready(继续可用) |
| 清理测试资源 | 删除测试 namespace 中的 Pod/Deployment 等 | Ready(可继续使用) |
| 重置 | 清除所有用户创建的资源,保留集群和组件 | Ready(干净状态) |
| 销毁 | Kind: 删除集群;外部: 断开连接并清理 namespace | Destroyed |
热加载配置:
- 调度器参数:通过更新 ConfigMap + 触发 Pod 滚动更新(或信号重载)
- KWOK 节点数量:动态创建/删除 Node 对象
- 节点配置:更新 Node 的 status.capacity/allocatable
- Pod 配置:通过 Deployment 的 spec 更新
┌─────────────────────────────────────────────────────┐
│ Test Execution Engine │
│ │
│ ┌────────────┐ ┌────────────┐ ┌───────────┐ │
│ │ DAG Parser │───>│ Step Queue │───>│ Executor │ │
│ └────────────┘ └────────────┘ └─────┬─────┘ │
│ │ │
│ ┌───────────────────────┼──────┐ │
│ │ Step Runners │ │ │
│ │ ┌────────┐ ┌────────┐│ │ │
│ │ │Deploy │ │Assert ││ │ │
│ │ │Runner │ │Runner ││ │ │
│ │ └────────┘ └────────┘│ │ │
│ │ ┌────────┐ ┌────────┐│ │ │
│ │ │Validate│ │Metrics ││ │ │
│ │ │Runner │ │Runner ││ │ │
│ │ └────────┘ └────────┘│ │ │
│ │ ┌────────┐ ┌────────┐│ │ │
│ │ │Config │ │Scale ││ │ │
│ │ │Runner │ │Runner ││ │ │
│ │ └────────┘ └────────┘│ │ │
│ │ ┌────────┐ ┌────────┐│ │ │
│ │ │Chaos │ │Custom ││ │ │
│ │ │Runner │ │Runner ││ │ │
│ │ └────────┘ └────────┘│ │ │
│ └───────────────────────┘ │ │
│ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ Result Store │ │ Event Stream │──> WebSocket │
│ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────┘
执行流程:
- 解析场景 YAML,构建 DAG
- 拓扑排序确定执行顺序
- 并行执行无依赖的步骤
- 每个步骤通过对应的 Runner 执行
- 实时通过 WebSocket 推送执行状态
- 收集每步结果,判定整体通过/失败
- 生成测试报告
测试类型映射:
| 测试类型 | 场景特征 | 验证重点 |
|---|---|---|
| 单元测试 | 单组件、单策略、小规模 | 功能正确性 |
| E2E 测试 | 完整流程、真实/模拟集群 | 端到端功能 |
| 集成测试 | 多组件协调、复杂场景 | 组件配合 |
| 性能测试 | 大规模节点/Pod、压力场景 | 延迟、吞吐、资源消耗 |
┌─────────────────────────────────────────┐
│ Report System │
│ │
│ ┌──────────────────────────────────┐ │
│ │ Report Generator │ │
│ │ + GenerateJSON(result) → Report │ │
│ │ + GenerateHTML(result) → []byte │ │
│ │ + GeneratePDF(result) → []byte │ │
│ └──────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────┐ │
│ │ Report Storage │ │
│ │ + Save(report) → id │ │
│ │ + Get(id) → Report │ │
│ │ + List(filter) → []Report │ │
│ │ + Download(id, format) → io.Reader │
│ └──────────────────────────────────┘ │
│ │
│ 存储后端: │
│ - 本地文件系统 (默认) │
│ - S3/MinIO (可选) │
└─────────────────────────────────────────┘
报告内容:
- 测试概要(场景名、时间、耗时、结果)
- 各步骤详细结果(通过/失败、耗时、日志)
- 调度指标(延迟分布、吞吐量、队列深度)
- 集群状态快照(节点利用率、Pod 分布)
- 可视化图表(ECharts 渲染的 HTML 报告)
// 插件接口定义
type SchedulerPlugin interface {
// 基本信息
Name() string
Version() string
Description() string
// 生命周期
Init(config map[string]interface{}) error
Shutdown() error
// 部署能力
Deploy(ctx context.Context, cluster ClusterHandle, config ComponentConfig) error
Undeploy(ctx context.Context, cluster ClusterHandle) error
UpdateConfig(ctx context.Context, cluster ClusterHandle, config ComponentConfig) error
// 状态和指标
GetStatus(ctx context.Context, cluster ClusterHandle) (ComponentStatus, error)
GetMetrics(ctx context.Context, cluster ClusterHandle) (map[string]interface{}, error)
// 验证能力
GetValidators() []Validator
}
// 插件注册
type PluginRegistry struct {
plugins map[string]SchedulerPlugin
}
func (r *PluginRegistry) Register(plugin SchedulerPlugin) error
func (r *PluginRegistry) Get(name string) (SchedulerPlugin, bool)
func (r *PluginRegistry) List() []PluginInfo内置插件:kube-scheduler、crane-scheduler、descheduler、pooling-scheduler
扩展方式:实现 SchedulerPlugin 接口,编译时注册或通过 Go plugin 动态加载
组件互斥规则:
// 插件注册中心维护互斥关系
type MutualExclusion struct {
GroupName string // 如 "primary-scheduler"
Components []string // ["kube-scheduler", "pooling-scheduler"]
}
// 部署时校验
func (r *PluginRegistry) ValidateDeployment(cluster ClusterHandle, newComponent string) error {
for _, rule := range r.mutualExclusions {
if contains(rule.Components, newComponent) {
for _, existing := range cluster.DeployedComponents() {
if contains(rule.Components, existing) && existing != newComponent {
return fmt.Errorf("component %q conflicts with deployed %q (group: %s)",
newComponent, existing, rule.GroupName)
}
}
}
}
return nil
}┌─────────────────────────────────────────────────────┐
│ Log Management System │
│ │
│ ┌──────────────────────────────────────────────┐ │
│ │ Log Collector │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │ │
│ │ │Component │ │Execution │ │ K8s Events │ │ │
│ │ │ Logs │ │ Logs │ │ Collector │ │ │
│ │ └──────────┘ └──────────┘ └──────────────┘ │ │
│ └──────────────────┬───────────────────────────┘ │
│ │ │
│ ┌──────────────────┴───────────────────────────┐ │
│ │ Log Storage │ │
│ │ + Write(entry) error │ │
│ │ + Query(filter) → []LogEntry │ │
│ │ + Cleanup(retentionPolicy) error │ │
│ │ + Export(filter, format) → io.Reader │ │
│ └──────────────────────────────────────────────┘ │
│ │
│ 存储后端: │
│ - 本地文件 (默认,按日期轮转) │
│ - SQLite/PG (结构化查询) │
│ - 外部对接预留 (Loki, Elasticsearch) │
│ │
│ 保留策略 (可配置): │
│ - 按时间: 保留最近 N 天 │
│ - 按大小: 总量不超过 N GB │
│ - 按类型: 不同日志类型不同策略 │
│ - 定时清理: Cron 任务自动执行 │
└─────────────────────────────────────────────────────┘
日志类型:
| 日志类型 | 来源 | 说明 | 默认保留 |
|---|---|---|---|
| 组件日志 | kube-scheduler, crane-scheduler 等 Pod 日志 | 调度器运行日志 | 7 天 |
| 执行日志 | 测试执行引擎 | 每次测试执行的步骤日志 | 30 天 |
| 集群事件 | K8s Events | Pod 调度事件、节点事件 | 3 天 |
| 系统日志 | SchedSim 自身 | 平台运行日志 | 14 天 |
| 审计日志 | 用户操作 | 操作审计记录 | 90 天 |
保留策略配置:
log:
retention:
component:
maxDays: 7
maxSizeGB: 5
execution:
maxDays: 30
maxSizeGB: 10
clusterEvent:
maxDays: 3
maxSizeGB: 2
system:
maxDays: 14
maxSizeGB: 3
audit:
maxDays: 90
maxSizeGB: 1
cleanup:
schedule: "0 2 * * *" # 每天凌晨 2 点执行清理集群镜像功能允许将线上生产集群的状态快照到本地 Kind 集群或新建的干净集群中,用于:
- 生产环境评估:在镜像集群上评估调度策略变更的影响
- 新算法验证:在真实拓扑和工作负载分布上验证新调度算法
- 问题复现:复现线上调度问题
┌─────────────────────────────────────────────────────────────┐
│ Cluster Mirror Engine │
│ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ Snapshot Collector │ │
│ │ 从源集群(线上集群 B)采集: │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │ Nodes │ │ Pods │ │Workloads │ │Configs │ │ │
│ │ │(拓扑/资源)│ │(分布/资源)│ │(Deploy等)│ │(调度配置) │ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │Namespaces│ │PV/PVC │ │Services │ │ │
│ │ │(命名空间) │ │(存储声明) │ │(服务) │ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ │ │
│ └────────────────────┬───────────────────────────────────┘ │
│ │ │
│ ┌────────────────────┴───────────────────────────────────┐ │
│ │ Snapshot Transformer │ │
│ │ ┌──────────────────────────────────────────────────┐ │ │
│ │ │ - 真实节点 → KWOK 模拟节点 (保留拓扑/资源/标签) │ │ │
│ │ │ - Pod status 清除 (让调度器重新调度) │ │ │
│ │ │ - 敏感信息脱敏 (Secret, ConfigMap 中的密钥) │ │ │
│ │ │ - 镜像引用替换 (可选,替换为轻量 pause 镜像) │ │ │
│ │ │ - 资源配额保留 (ResourceQuota, LimitRange) │ │ │
│ │ │ - 可选过滤: 按 namespace/label 选择性镜像 │ │ │
│ │ └──────────────────────────────────────────────────┘ │ │
│ └────────────────────┬───────────────────────────────────┘ │
│ │ │
│ ┌────────────────────┴───────────────────────────────────┐ │
│ │ Snapshot Applier │ │
│ │ 应用到目标集群(本地 Kind 集群 A): │ │
│ │ 1. 创建 KWOK 节点 (镜像源集群节点拓扑) │ │
│ │ 2. 创建 Namespace 和资源配额 │ │
│ │ 3. 创建工作负载定义 (Deployment/StatefulSet/DaemonSet) │ │
│ │ 4. 应用调度相关配置 (PDB, PriorityClass, etc.) │ │
│ │ 5. 可选: 重放 Pod 创建让调度器重新调度 │ │
│ └────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
镜像模式:
| 模式 | 说明 | 适用场景 |
|---|---|---|
| 全量镜像 | 镜像所有 namespace 的节点、工作负载、配置 | 全面评估 |
| 选择性镜像 | 按 namespace/label 过滤,只镜像部分资源 | 针对特定业务评估 |
| 拓扑镜像 | 只镜像节点拓扑和资源容量,不含工作负载 | 新调度算法验证 |
| 增量更新 | 基于已有镜像,同步源集群的变更 | 持续跟踪生产状态 |
镜像工作流:
1. 用户选择源集群 (通过 kubeconfig 连接线上集群 B)
↓
2. 配置镜像选项 (模式、namespace 过滤、脱敏规则)
↓
3. Snapshot Collector 采集源集群状态
↓
4. Snapshot Transformer 转换数据 (节点→KWOK、脱敏、过滤)
↓
5. 用户选择或创建目标集群 A (Kind/Kind+KWOK)
↓
6. Snapshot Applier 将快照应用到目标集群
↓
7. 部署目标调度组件 (新算法/新配置)
↓
8. 运行测试场景,对比镜像前后的调度效果
快照数据结构:
type ClusterSnapshot struct {
ID uint `json:"id"`
Name string `json:"name"`
SourceCluster string `json:"sourceCluster"` // 源集群标识
Mode string `json:"mode"` // full, selective, topology, incremental
Filter SnapshotFilter `json:"filter"`
Nodes []NodeSnapshot `json:"nodes"`
Workloads []WorkloadSnapshot `json:"workloads"`
Configs []ConfigSnapshot `json:"configs"`
CreatedAt time.Time `json:"createdAt"`
Size int64 `json:"size"` // 快照大小(bytes)
}
type SnapshotFilter struct {
Namespaces []string `json:"namespaces,omitempty"` // 包含的 namespace
ExcludeNS []string `json:"excludeNs,omitempty"` // 排除的 namespace
LabelSelector string `json:"labelSelector,omitempty"` // 标签选择器
ResourceTypes []string `json:"resourceTypes,omitempty"` // 资源类型过滤
}内置的混沌测试能力,无需外部 Chaos Mesh / LitmusChaos 依赖。
┌─────────────────────────────────────────────────────┐
│ Chaos Engine │
│ │
│ ┌──────────────────────────────────────────────┐ │
│ │ ChaosAction Interface │ │
│ │ + Inject(ctx, cluster, params) error │ │
│ │ + Recover(ctx, cluster) error │ │
│ │ + Status(ctx, cluster) ChaosStatus │ │
│ └──────────┬───────────────────────────────────┘ │
│ │ │
│ ┌────────┼──────────┬──────────┬──────────┐ │
│ ┌─┴──────┐┌┴────────┐┌┴────────┐┌┴────────┐ │
│ │NodeFail││PodKill ││Network ││Resource │ │
│ │Action ││Action ││Chaos ││Pressure │ │
│ └────────┘└─────────┘└─────────┘└─────────┘ │
│ ┌────────┐┌─────────┐┌─────────┐ │
│ │NodeDrain│ │LabelMut││Schedule │ │
│ │Action ││ Action ││Disrupt │ │
│ └────────┘└─────────┘└─────────┘ │
└─────────────────────────────────────────────────────┘
内置 Chaos 动作:
| 动作 | 说明 | 参数 | 恢复方式 |
|---|---|---|---|
node-failure |
将节点标记为 NotReady | 目标节点(名称/标签/数量)、持续时间 | 恢复 Ready 状态 |
node-drain |
驱逐节点上所有 Pod | 目标节点、是否 cordon | uncordon 节点 |
pod-kill |
删除指定 Pod | 选择器、数量、是否随机 | Pod 由控制器重建 |
pod-eviction |
模拟 descheduler 驱逐 | 选择器、驱逐策略 | Pod 由控制器重建 |
network-partition |
模拟网络分区 (通过 NetworkPolicy) | 源/目标 namespace/label | 删除 NetworkPolicy |
resource-pressure |
模拟节点资源压力 (修改 allocatable) | 目标节点、CPU/内存压力比例 | 恢复原始 allocatable |
label-mutation |
修改节点/Pod 标签 | 目标、标签变更 | 恢复原始标签 |
scheduler-disruption |
停止/重启调度器 | 目标组件、停止时长 | 重启组件 |
taint-injection |
给节点添加 taint | 目标节点、taint 定义 | 移除 taint |
scale-spike |
突发大量 Pod 创建 | Pod 模板、数量、速率 | 删除 Pod |
环境管理和测试执行是解耦的。环境可以独立于测试存在。
┌─ 模式 A: 平台托管测试 ──────────────────────────────────────┐
│ │
│ 用户创建场景 → 保存到 DB │
│ ↓ │
│ 用户触发执行 → 选择已有环境 或 自动创建新环境 │
│ ↓ │
│ Execution Engine 读取场景配置 │
│ ↓ │
│ Environment Manager 获取/创建集群 + 部署组件 │
│ ↓ │
│ DAG Executor 按步骤执行测试 │
│ ↓ (WebSocket 实时推送) │
│ Step Runners 执行各步骤 │
│ ↓ │
│ Result Collector 汇总结果 → Report Generator 生成报告 │
│ ↓ │
│ 按清理策略处理环境: 保留 / 清理资源 / 重置 / 销毁 │
│ │
└──────────────────────────────────────────────────────────────┘
┌─ 模式 B: 环境自助模式 ──────────────────────────────────────┐
│ │
│ 用户在平台创建环境 → 配置节点/组件 → 环境就绪 │
│ ↓ │
│ 导出 kubeconfig │
│ ↓ │
│ 外部使用: kubectl / 自定义脚本 / CI pipeline / helm test │
│ ↓ │
│ 用完后回到平台: 保留 / 清理 / 销毁环境 │
│ │
└──────────────────────────────────────────────────────────────┘
用户在 UI 修改配置 → API 接收变更
↓
Config Service 验证配置合法性
↓
Environment Manager 应用配置到目标集群
├─ 调度器参数 → 更新 ConfigMap → 触发 Pod 重载
├─ 节点数量 → 创建/删除 KWOK Node 对象
├─ 节点配置 → Patch Node status
└─ Pod 配置 → 更新 Deployment spec
↓
WebSocket 通知 UI 配置已生效
# 认证
POST /api/v1/auth/login # 登录
POST /api/v1/auth/refresh # 刷新 Token
POST /api/v1/auth/logout # 登出
GET /api/v1/auth/oauth/providers # 获取 OAuth Provider 列表
GET /api/v1/auth/oauth/:provider # OAuth 授权跳转
GET /api/v1/auth/oauth/:provider/callback # OAuth 回调
# 用户管理
GET /api/v1/users # 用户列表
POST /api/v1/users # 创建用户
PUT /api/v1/users/:id # 更新用户
DELETE /api/v1/users/:id # 删除用户
# 场景管理
GET /api/v1/scenarios # 场景列表
POST /api/v1/scenarios # 创建场景
GET /api/v1/scenarios/:id # 获取场景详情
PUT /api/v1/scenarios/:id # 更新场景
DELETE /api/v1/scenarios/:id # 删除场景
POST /api/v1/scenarios/:id/clone # 克隆场景
POST /api/v1/scenarios/:id/validate # 验证场景配置
POST /api/v1/scenarios/import # 导入场景(YAML)
GET /api/v1/scenarios/:id/export # 导出场景(YAML)
# 环境管理(独立能力,不依赖测试执行)
GET /api/v1/environments # 环境列表(支持 ?status=ready&purpose=dev-debug 筛选)
POST /api/v1/environments # 创建环境(含可选组件部署和生命周期配置)
GET /api/v1/environments/:id # 获取环境详情
DELETE /api/v1/environments/:id # 销毁环境
GET /api/v1/environments/:id/status # 获取环境实时状态
POST /api/v1/environments/:id/connect # 连接外部集群为环境
PUT /api/v1/environments/:id/config # 更新环境配置(热加载)
GET /api/v1/environments/:id/kubeconfig # 导出 kubeconfig(供外部使用)
# 环境生命周期
PUT /api/v1/environments/:id/expiry # 设置/修改过期时间和过期动作
POST /api/v1/environments/:id/extend # 延长过期时间
POST /api/v1/environments/:id/cleanup # 清理测试资源(scope: test-resources / reset)
POST /api/v1/environments/:id/stop # 停止环境(保留数据,释放资源)
POST /api/v1/environments/:id/start # 重新启动已停止的环境
# 环境节点管理
GET /api/v1/environments/:id/nodes # 节点列表
POST /api/v1/environments/:id/nodes # 添加节点(KWOK)
PUT /api/v1/environments/:id/nodes/batch # 批量更新节点配置
DELETE /api/v1/environments/:id/nodes/:name # 删除节点
# 环境组件管理
GET /api/v1/environments/:id/components # 已部署组件列表
POST /api/v1/environments/:id/components # 部署组件(含自定义镜像)
PUT /api/v1/environments/:id/components/:name # 更新组件配置
PUT /api/v1/environments/:id/components/:name/image # 切换组件镜像
DELETE /api/v1/environments/:id/components/:name # 卸载组件
GET /api/v1/environments/:id/components/:name/status # 组件状态
GET /api/v1/environments/:id/components/:name/logs # 组件日志
# 测试执行(依赖环境管理提供的环境)
POST /api/v1/executions # 创建并执行测试(指定环境 ID 或自动创建)
GET /api/v1/executions # 执行记录列表
GET /api/v1/executions/:id # 执行详情(含环境信息和清理策略)
POST /api/v1/executions/:id/cancel # 取消执行(按清理策略处理环境)
GET /api/v1/executions/:id/logs # 执行日志
# 报告管理
GET /api/v1/reports # 报告列表
GET /api/v1/reports/:id # 报告详情
GET /api/v1/reports/:id/download # 下载报告(支持 JSON/HTML/PDF)
DELETE /api/v1/reports/:id # 删除报告
POST /api/v1/reports/compare # 报告对比
# 插件管理
GET /api/v1/plugins # 插件列表
GET /api/v1/plugins/:name # 插件详情
POST /api/v1/plugins/:name/enable # 启用插件
POST /api/v1/plugins/:name/disable # 禁用插件
# 日志管理
GET /api/v1/logs # 查询日志(支持类型/时间/关键词筛选)
GET /api/v1/logs/stream # SSE 实时日志流
GET /api/v1/logs/export # 导出日志
GET /api/v1/logs/retention # 获取保留策略
PUT /api/v1/logs/retention # 更新保留策略
DELETE /api/v1/logs/cleanup # 手动触发日志清理
GET /api/v1/environments/:id/logs # 环境组件日志
GET /api/v1/executions/:id/logs # 执行详细日志(含步骤日志)
# 集群镜像
GET /api/v1/snapshots # 快照列表
POST /api/v1/snapshots # 创建快照(从源集群采集)
GET /api/v1/snapshots/:id # 快照详情
DELETE /api/v1/snapshots/:id # 删除快照
POST /api/v1/snapshots/:id/apply # 将快照应用到目标集群
POST /api/v1/snapshots/:id/refresh # 增量更新快照
GET /api/v1/snapshots/:id/diff # 查看快照与源集群的差异
POST /api/v1/environments/:id/mirror # 一键镜像:创建快照 + 创建环境 + 应用
# 系统配置
GET /api/v1/config # 获取系统配置
PUT /api/v1/config # 更新系统配置
WS /api/v1/ws/executions/:id # 测试执行实时状态
WS /api/v1/ws/environments/:id/status # 环境实时状态
WS /api/v1/ws/environments/:id/metrics # 环境实时指标
WebSocket 消息格式:
{
"type": "execution.step.started|completed|failed",
"timestamp": "2024-01-01T00:00:00Z",
"data": {
"executionId": "exec-001",
"stepId": "setup-workload",
"status": "running",
"message": "Deploying 50 stress-test pods..."
}
}# 编译(前端自动嵌入)
make build
# 运行
./bin/schedsim --config=configs/schedsim.yaml
# 配置文件
server:
port: 8080
mode: release
database:
driver: sqlite
dsn: "./data/schedsim.db"
storage:
type: local
path: "./data/reports"
auth:
jwtSecret: "your-secret-key"
tokenExpiry: 24h# Multi-stage build
FROM node:20-alpine AS frontend
WORKDIR /app/web
COPY web/ .
RUN npm ci && npm run build
FROM golang:1.22-alpine AS backend
WORKDIR /app
COPY . .
COPY --from=frontend /app/web/dist web/dist
RUN CGO_ENABLED=0 go build -o schedsim cmd/schedsim/main.go
FROM gcr.io/distroless/static
COPY --from=backend /app/schedsim /schedsim
COPY --from=backend /app/configs /configs
ENTRYPOINT ["/schedsim"]docker run -d \
-p 8080:8080 \
-v $(pwd)/data:/data \
-v /var/run/docker.sock:/var/run/docker.sock \
schedsim:latest注意:Kind 需要访问 Docker socket 来创建集群。
helm install schedsim deploy/helm/schedsim \
--namespace schedsim-system \
--create-namespace \
--set database.driver=postgresql \
--set database.host=postgres.db.svc \
--set storage.type=s3 \
--set storage.s3.endpoint=minio.storage.svc:9000Helm Chart 包含:
- Deployment(SchedSim 主服务)
- Service + Ingress
- ConfigMap(配置文件)
- Secret(JWT Secret、DB 密码)
- PVC(报告存储,如使用本地存储)
- ServiceAccount + RBAC(如需管理 K8s 集群)
- 可选:PostgreSQL、MinIO 子 Chart
| 层面 | 措施 |
|---|---|
| 认证 | JWT Token + 可选 OAuth2/OIDC |
| 授权 | RBAC(admin/operator/viewer) |
| 传输 | HTTPS(TLS) |
| 集群隔离 | 每次测试使用独立 namespace |
| 密钥管理 | kubeconfig 和 token 加密存储 |
| 审计 | 所有操作记录审计日志 |
| 输入校验 | 场景 YAML 严格 schema 验证 |
- 实现
SchedulerPlugin接口 - 在
plugin/registry.go中注册 - 提供默认配置模板
- 实现对应的 Deployer
- 可选:实现自定义 Validator
- 实现
StepRunner接口 - 在 Runner Registry 中注册
- 定义步骤的 spec schema
- 前端添加对应的编辑组件
- 实现
ReportFormatter接口 - 注册到 Report Generator
- 实现
ClusterProvisioner接口 - 注册到 Provisioner Registry