4、CRD版本迁移测试类型:功能测试、兼容性测试、回滚测试、性能测试、压力测试
CRD 版本迁移是 Operator 生命周期中最关键的风险操作之一。一次不完整的迁移可能导致集群中已有 CR 对象数据损坏、控制器循环崩溃、甚至 API Server 响应超时。因此,必须建立覆盖 功能、兼容性、回滚、性能 和 压力 五个维度的测试体系,才能保障迁移过程安全可控。
4.1 测试类型总览
下表从测试目标、执行时机、关键指标三个维度对比五种测试类型,便于团队在制定测试计划时快速对齐。
| 测试类型 | 测试目标 | 执行时机 | 关键指标 |
|---|---|---|---|
| 功能测试 | 验证 CRD 各版本下 CR 的 CRUD、校验、默认值、子资源行为正确 | 每次版本变更后 | 用例通过率 100%,无预期外错误 |
| 兼容性测试 | 保证新旧版本 CR 对象可互读、互写,存储版本切换后数据不丢失 | 版本发布前 | 数据无损、字段映射正确、无转换错误 |
| 回滚测试 | 验证从新版本回退到旧版本时,CR 对象和控制器状态可恢复 | 版本发布前 + 演练 | 回滚后集群状态与回滚前一致 |
| 性能测试 | 评估迁移过程中 API Server 响应延迟、存储写入吞吐、控制器 Reconcile 耗时 | 版本发布前 | P99 延迟 < 2s,吞吐不下降超过 10% |
| 压力测试 | 验证大规模 CR 对象下迁移的稳定性,发现资源泄漏或 OOM 风险 | 版本发布前 + 定期 | 无 OOM、无 goroutine 泄漏、CR 数量 10k+ |
4.2 功能测试
功能测试是版本迁移的基线。每个 CRD 版本(served: true)都必须独立通过完整的 CRUD 验证。
- 创建测试:使用每个 served 版本创建 CR,验证 spec 字段默认值注入、校验准入、metadata 自动填充。
- 读取测试:分别通过 kubectl get、kubectl get <crd> -o yaml、以及 Operator 内部 Informer 读取,确认字段完整。
- 更新测试:修改 spec 和 status 字段,验证 subresource 路由正确(/status 更新不触发 spec 校验)。
- 删除测试:验证 foreground / background 级联删除行为,以及 finalizer 处理逻辑。
⚠ 常见陷阱:如果新版本增加了 required 字段,但旧版本 CR 没有该字段,转换 Webhook 必须提供合理的默认值,否则读取旧 CR 时会报校验错误。
4.3 兼容性测试
兼容性测试的核心是验证 存储版本切换 和 多版本读写一致性。Kubernetes 只会将 CR 以 storage 版本写入 etcd,其他 served 版本通过转换 Webhook 实时转换。
💡 关键原则:所有 served 版本必须能无损转换为 storage 版本,且转换后再转回原版本时字段不丢失、语义不改变。
兼容性测试用例清单:
- 正向兼容:用旧版本创建 CR,用新版本读取,验证字段映射正确。
- 反向兼容:用新版本创建 CR,用旧版本读取,验证降级后字段不丢失。
- 存储版本切换:修改 CRD 的 storage 版本,触发 etcd 中所有 CR 的存储迁移,验证迁移后数据完整。
- 转换 Webhook 容错:模拟 Webhook 返回 500 或超时,验证 API Server 是否降级为拒绝请求(不应静默跳过转换)。
- 字段弃用测试:标记某字段为 deprecated,验证旧版本仍可读写该字段,新版本写入时被忽略或告警。
4.4 回滚测试
回滚测试是版本迁移的“安全气囊”。一旦生产环境发现严重问题,必须能快速恢复到上一个稳定版本。回滚测试应覆盖以下场景:
- CRD 回滚:将 CRD 的 spec.versions 列表恢复到旧版本配置,验证 API Server 重新加载后旧版本可正常服务。
- 存储版本回滚:如果存储版本已切换,回滚时需要再次切换存储版本,并触发全量 CR 重新写入 etcd。
- 控制器回滚:将 Operator Deployment 回退到旧版本镜像,验证控制器能正确处理新旧混合的 CR 对象。
- 数据完整性校验:回滚后对全量 CR 做快照对比,确保没有字段被静默丢弃或篡改。
🚨 回滚失败常见原因:
1. 新版本删除了旧版本中的字段,回滚后该字段永久丢失。
2. 转换 Webhook 在新版本中引入了副作用(如修改 status),回滚后旧版本无法处理已变更的 status。
3. CRD 的 spec.preserveUnknownFields 设置不当,导致未知字段被裁剪。
1. 新版本删除了旧版本中的字段,回滚后该字段永久丢失。
2. 转换 Webhook 在新版本中引入了副作用(如修改 status),回滚后旧版本无法处理已变更的 status。
3. CRD 的 spec.preserveUnknownFields 设置不当,导致未知字段被裁剪。
4.5 性能测试
性能测试关注迁移过程中控制平面的负载变化。重点测量以下指标:
| 指标 | 测量方法 | 基准值(参考) | 告警阈值 |
|---|---|---|---|
| API Server 响应延迟 | 使用 kubectl 批量创建/更新 CR,记录 P50/P99 延迟 | P99 < 500ms | P99 > 2s |
| 转换 Webhook 耗时 | 在 Webhook 日志中输出处理时间,聚合 P99 | P99 < 100ms | P99 > 500ms |
| etcd 写入吞吐 | 监控 etcd 的 db 大小和写入 QPS | QPS > 1000 | QPS 下降 > 30% |
| 控制器 Reconcile 队列深度 | 暴露 Operator metrics,观察 work_queue_depth | 平均 < 10 | 持续 > 100 |
📊 性能测试工具推荐:
kubectl-stress 用于批量 CR 操作;vegeta 或 wrk 用于 API Server 压测;Operator 自身暴露的 Prometheus metrics 用于控制器性能监控。
4.6 压力测试
压力测试模拟极端规模下的版本迁移行为,暴露资源泄漏、OOM、etcd 存储爆炸等隐患。
典型压力场景:
- 大规模 CR 存储迁移:预先创建 10,000+ 个 CR 对象,然后修改 CRD 的 storage 版本,观察 etcd 写入压力和迁移完成时间。
- 并发读写混合:在迁移过程中持续执行 CR 的创建、更新、删除操作,验证 API Server 和 Webhook 不会因并发导致死锁。
- Webhook 背压测试:模拟 Webhook 响应缓慢(人为增加 1s 延迟),验证 API Server 的客户端限流和超时重试机制是否正常工作。
- 控制器 Reconcile 风暴:迁移完成后,所有 CR 的 resourceVersion 发生变化,触发大量 Reconcile 请求,验证 Operator 的限速和批量处理能力。
4.7 测试执行策略建议
在实际项目中,建议按以下优先级和频率执行五类测试:
- 每次代码提交:功能测试(CI 流水线中运行,覆盖所有 served 版本)。
- 每次版本发布前:兼容性测试 + 性能测试(在预发环境执行,数据量不低于生产 10%)。
- 每季度或大版本变更:回滚测试 + 压力测试(需要独立的高负载测试集群)。
- 生产变更前:至少执行一次完整的回滚演练,确保回滚剧本可执行。
📌 最终建议:将五类测试用例编写为 端到端(E2E)测试套件,集成到 CI/CD 流水线中。使用
ginkgo + kind 或 envtest 搭建隔离测试环境,确保每次 CRD 版本变更都能自动触发全量验证。