Strimzi Kafka Operator 中 Cruise Control 配置管理验证实战:从配置热更新到动态部署/卸载的系统测试剖析
【免费下载链接】strimzi-kafka-operatorApache Kafka® running on Kubernetes项目地址: https://gitcode.com/GitHub_Trending/st/strimzi-kafka-operator
导读
Cruise Control 是 Strimzi 为 Kafka 集群提供的自动化负载均衡与集群优化组件。本文以仓库内系统测试套件 CruiseControlConfigurationST 为核心,深入剖析 Strimzi 如何端到端验证 Cruise Control 的配置管理能力——包括修改性能调优参数后仅滚动 Cruise Control 而不扰动 Kafka Broker,以及在不删除内部 Topic 的前提下动态部署、卸载、重新部署 Cruise Control。读完本文,你将掌握这套测试的设计思路、底层配置参数语义、验证手段,以及如何在自己的 Kubernetes 环境中复现运行。
一、测试套件定位:验证什么、需要什么环境
1.1 套件职责与声明
根据测试套件的@SuiteDoc注解(见 CruiseControlConfigurationST.java),本套件的职责描述为:
Description:This test suite, verify configuration of the Cruise Control component.
即:专门验证 Cruise Control 组件的配置行为。它覆盖两个核心场景:
| 测试方法 | 验证目标 | | - | - | |testConfigurationUpdate| 更新 Cruise Control 配置后,Cruise Control Pod 滚动应用新配置,而 Kafka Pod 不发生不必要的滚动 | |testDeployAndUnDeployCruiseControl| 动态部署、移除、再部署 Cruise Control,验证系统稳定性与配置管理的正确性 |
1.2 前置条件:Cluster Operator
套件声明的唯一前置步骤是安装并运行 Cluster Operator:
| Step | Action | Result | | - | - | - | | 1 | Set up the Cluster Operator | Cluster Operator is installed and running |
这一点在源码中由@BeforeAll阶段的setUp()方法落实——它调用SetupClusterOperator.getInstance().withDefaultConfiguration().install()安装默认配置的 Cluster Operator(源码位置)。
1.3 测试标签与分类
套件类与每个测试方法都声明了@Tag(REGRESSION)和@Tag(CRUISE_CONTROL),并标记@ParallelNamespaceTest(并行命名空间测试),说明它可以与其他测试并行运行,且归属于回归测试类别。在测试文档体系中,它被收录在 cruise-control 标签页 下,与 Cruise Control 的 API、Rebalance、日志、指标等测试共同构成完整的 Cruise Control 验证矩阵。
二、testConfigurationUpdate:配置更新后的精准滚动验证
2.1 测试目标与完整步骤
该测试的目标是:验证 Cruise Control 配置更新后,只有 Cruise Control 自身滚动,Kafka 的 Broker/Controller Pod 不应当滚动。官方文档给出的完整步骤为:
| Step | Action | Result | | - | - | - | | 1 | Create broker and controller KafkaNodePools | Both KafkaNodePools are successfully created | | 2 | Create and wait for Kafka with Cruise Control | Kafka and Cruise Control are deployed successfully | | 3 | Take initial snapshots of Kafka and Cruise Control deployments | Snapshots of current deployments are stored | | 4 | Update Cruise Control configuration with new performance tuning options | Configuration update initiated | | 5 | Verify Cruise Control Pod rolls after configuration change | Cruise Control Pod restarts to apply new configurations | | 6 | Verify Kafka Pods did not roll after configuration change | Kafka Pods remain unchanged | | 7 | Verify new configurations are applied to Cruise Control in Kafka CR | New configurations are correctly applied |
2.2 源码层面的执行细节
在 CruiseControlConfigurationST.java 中,测试的执行路径是:
- 创建 Broker 与 Controller 两类 KafkaNodePool:各 3 副本,通过
KafkaNodePoolTemplates.brokerPool(...)与KafkaNodePoolTemplates.controllerPool(...)创建(对应 KRaft 模式下的 dual-role 分离)。 - 部署带 Cruise Control 的 Kafka 集群:使用
KafkaTemplates.kafkaWithCruiseControl(...)生成 CR。 - 记录基线快照:
PodUtils.podSnapshot记录 broker Pod 的 UID 快照,DeploymentUtils.depSnapshot记录 Cruise Control Deployment 的副本快照,作为后续滚动对比的基准。 - 更新性能调优配置:通过
KafkaUtils.replace对 Kafka CR 执行原子替换,写入如下 4 项参数(见 CruiseControlConfigurationParameters.java):
Map<String, Object> performanceTuningOpts = new HashMap<>() {{ put(CruiseControlConfigurationParameters.CONCURRENT_INTRA_PARTITION_MOVEMENTS.getValue(), 2); put(CruiseControlConfigurationParameters.CONCURRENT_PARTITION_MOVEMENTS.getValue(), 5); put(CruiseControlConfigurationParameters.CONCURRENT_LEADER_MOVEMENTS.getValue(), 1000); put(CruiseControlConfigurationParameters.REPLICATION_THROTTLE.getValue(), -1); }};这四项参数对应的 Cruise Control 原生配置键为:
| 枚举 | 配置键 | 测试中写入的值 | 语义 | | - | - | - | - | |CONCURRENT_INTRA_PARTITION_MOVEMENTS|num.concurrent.intra.broker.partition.movements| 2 | 每个 Broker 上并发执行的 intra-broker 分区迁移数上限 | |CONCURRENT_PARTITION_MOVEMENTS|num.concurrent.partition.movements.per.broker| 5 | 每个 Broker 上并发执行的跨 Broker 分区迁移数上限 | |CONCURRENT_LEADER_MOVEMENTS|num.concurrent.leader.movements| 1000 | 并发 Leader 迁移数上限 | |REPLICATION_THROTTLE|default.replication.throttle| -1 | 默认复制限流值(-1 表示不限流) |
- 断言 Cruise Control Deployment 发生滚动:
DeploymentUtils.waitTillDepHasRolled等待 CC Deployment 的副本滚动完成。 - 断言 Kafka 未发生滚动:
RollingUpdateUtils.waitForNoRollingUpdate校验 broker 快照未变化——这是整个测试最关键的断言,证明 Cruise Control 的配置变更被隔离在 CC 组件内部,不会触发 Kafka 集群无意义的全量滚动。 - 在 ConfigMap 层面验证配置落盘:读取 Cruise Control 的
cruisecontrol.properties(取自名为<cluster>-cruise-control-config的 ConfigMap),将其加载为Properties,再用 HamcresthasEntry逐一断言四项参数均已写入且值正确。
2.3 底层原理:为什么只滚动 Cruise Control
从实现上看,这一行为由 CruiseControl.java 与 CruiseControlConfiguration.java 共同保证:
- 默认属性使用有序 Map 生成:
DEFAULT_PROPERTIES_MAP被包装为Collections.unmodifiableSortedMap(new TreeMap<>(...)),源码注释明确说明“map 必须排序,使 Cruise Control 配置项顺序确定,避免引起不必要的滚动更新”(CruiseControlConfiguration.java)。 - 用户配置与默认值合并生成最终配置:只有真正变化的配置才会导致 CC Deployment 的 ConfigMap 内容变化,从而触发 CC 滚动;Kafka Broker 的配置(如 metrics reporter 配置)只有在 CC 启停时才会变化,因此本例中 Kafka Pod 完全不受影响。
三、testDeployAndUnDeployCruiseControl:动态部署与卸载的生命周期管理
3.1 测试目标与完整步骤
该测试验证的是:在不停机、不删除 Cruise Control 内部 Topic 的前提下,将 Cruise Control 从 Kafka 集群中移除,再重新加回,整个过程中集群配置被正确清理与恢复。官方文档步骤:
| Step | Action | Result | | - | - | - | | 1 | Create broker and controller KafkaNodePools | Both KafkaNodePools are successfully created | | 2 | Deploy Kafka with Cruise Control | Kafka cluster with Cruise Control is deployed | | 3 | Take a snapshot of broker pods | Snapshot of the current broker pods is taken | | 4 | Remove Cruise Control from Kafka | Cruise Control is removed from Kafka and configuration is updated | | 5 | Verify Cruise Control is removed | No Cruise Control related pods or configurations are found | | 6 | Create Admin client to verify Cruise Control topics | Admin client is created and Cruise Control topics are verified to exist | | 7 | Re-add Cruise Control to Kafka | Cruise Control is added back to Kafka | | 8 | Verify Cruise Control and related configurations | Cruise Control and its configurations are verified to be present |
3.2 源码层面的执行细节
见 CruiseControlConfigurationST.java。测试先创建 3 副本的 Broker/Controller NodePool,并通过kafkaWithCruiseControl部署集群(同时设置default.replication.factor=3,使后续创建的 CC Topic 也获得 3 副本)。
移除阶段通过KafkaUtils.replace将kafka.getSpec().setCruiseControl(null),随后依次断言:
- Kafka CR 中 Cruise Control 已被清除:
getSpec().getCruiseControl()为null; - CC Pod 消失:
waitUntilPodStabilityReplicasCount(..., 0)等待 CC Pod 副本归零; - Broker 配置中的 metric reporter 被移除:
assertThrows(WaitException.class, () -> CruiseControlUtils.verifyCruiseControlMetricReporterConfigurationInKafkaConfigMapIsPresent(...))——即 Kafka ConfigMap 中不再包含cruise.control.metrics.*前缀的配置项,读取时必然抛异常。
验证 Topic 保留:测试用KafkaAdminClientBuilder部署 Admin 客户端,通过CruiseControlUtils.verifyThatCruiseControlTopicsArePresent确认三个 Cruise Control 内部 Topic 在卸载后依然存在于 Kafka 中(关于这三个 Topic 见下文第四部分)。
重新部署阶段执行kafka.getSpec().setCruiseControl(new CruiseControlSpec())将 CC 加回,等 broker 滚动完成后再次断言:
- metric reporter 配置重新出现在 Kafka ConfigMap 中;
- 三个 Cruise Control Topic 仍存在。
3.3 设计意图:Topic 的生命周期策略
这一测试揭示了一个重要的产品决策:Cruise Control 卸载时,其内部 Topic(metrics、model trainings、partition metrics samples)不会被删除。从源码注释可以直接看到测试预期——“Cruise Control Topics will not be deleted and will stay in the Kafka cluster”(源码)。这样设计的好处是:历史负载采样数据得以保留,重新启用 Cruise Control 后可以无缝恢复其负载监控能力,无需冷启动积累数据。
四、配套验证工具 CruiseControlUtils 与内部 Topic 语义
测试中大量复用 CruiseControlUtils.java,它封装了 Cruise Control 的 API 调用与配置断言,是理解该套件验证深度的钥匙。
4.1 三个内部 Topic
工具类中定义了 Cruise Control 的默认内部 Topic(源码):
| 常量 | Topic 名称 | 分区数 | 副本数 | | - | - | - | - | |CRUISE_CONTROL_METRICS_TOPIC|strimzi.cruisecontrol.metrics| 1 | 跟随集群default.replication.factor(测试中为 3) | |CRUISE_CONTROL_MODEL_TRAINING_SAMPLES_TOPIC|strimzi.cruisecontrol.modeltrainingsamples| 32 | 3 | |CRUISE_CONTROL_PARTITION_METRICS_SAMPLES_TOPIC|strimzi.cruisecontrol.partitionmetricsamples| 32 | 3 |
对应的默认名称常量定义于 CruiseControlConfigurationParameters.java,分别是DEFAULT_METRIC_REPORTER_TOPIC_NAME、DEFAULT_BROKER_METRIC_TOPIC_NAME、DEFAULT_PARTITION_METRIC_TOPIC_NAME。verifyThatCruiseControlTopicsArePresent不仅检查 Topic 存在,还逐一校验分区数与副本数(源码),确保 CC 按预期规格创建了内部存储结构。
4.2 metric reporter 配置断言
verifyCruiseControlMetricReporterConfigurationInKafkaConfigMapIsPresent从 broker 的server.config(Kafka ConfigMap)中筛选所有cruise.control.metrics前缀的配置项,断言其满足:
cruise.control.metrics.topic=strimzi.cruisecontrol.metrics;cruise.control.metrics.topic.auto.create=true;cruise.control.metrics.reporter.bootstrap.servers指向<cluster>-kafka-brokers:9091(broker 内部通信端口);- 安全协议、TLS 信任库(
${strimzisecrets:<ns>/<cluster>-trustbundle:cluster-ca.crt})、认证方式(mTLS keystore 或 Service Account 的 SASL OAUTHBEARER)与测试环境配置一致。
这正是“卸载时清除、重装时恢复”断言的具体落点:metric reporter 是 Cruise Control 与 Kafka 之间唯一的 broker 侧耦合点,它的增删直接体现了配置管理的正确性。
4.3 端口约定
工具类还记录了 Cruise Control 的默认端口:REST API 端口9090、指标端口9404,并通过callApi在 CC Pod 内执行 curl 调用 API(支持 HTTP/HTTPS、带/不带 admin 凭据),为 API 类测试提供了基础能力。
五、配置模型的源码级解析:参数、默认值与目标过滤
5.1 参数枚举全景
operator-common/src/main/java/io/strimzi/operator/common/model/cruisecontrol/CruiseControlConfigurationParameters.java 是一个贯穿 operator-common、cluster-operator 与 systemtest 三个模块的核心枚举,它把 Cruise Control 的原生配置键统一为类型安全常量。除性能调优参数外,还包括:
| 类别 | 配置键示例 | 说明 | | - | - | - | | 采样窗口 |partition.metrics.window.ms、num.partition.metrics.windows、broker.metrics.window.ms、num.broker.metrics.windows| 负载监控器的指标聚合窗口大小与数量 | | 任务保留 |completed.user.task.retention.time.ms| 已完成用户任务的保留时长 | | Web 安全 |webserver.security.enable、webserver.auth.credentials.file、webserver.ssl.enable| API 鉴权与 TLS | | 采样 Topic |partition.metric.sample.store.topic、broker.metric.sample.store.topic、sample.store.topic.replication.factor| CC 内部存储结构 | | Goals |goals、default.goals、hard.goals、self.healing.goals、anomaly.detection.goals| 优化目标配置 | | Metrics reporter |cruise.control.metrics.reporter.*| broker 侧指标上报配置 |
5.2 默认配置的生成逻辑
CruiseControlConfiguration.java 的generateDefaultPropertiesMap在默认属性之上补充default.goals与hard.goals,且会调用filterResourceGoalsWithoutCapacityConfig依据用户在 Kafka CR 中配置的容量(capacity)信息过滤目标——例如未配置入站网络容量时,会移除NetworkInboundUsageDistributionGoal、NetworkInboundCapacityGoal与LeaderBytesInDistributionGoal(源码)。这一逻辑保证了默认 goals 始终与用户声明的容量配置自洽,避免生成无法满足的优化目标。
5.3 用户如何启用 Cruise Control
生产中最常见的用法是在 Kafka CR 中声明cruiseControl段。仓库示例 kafka-cruise-control.yaml 展示了最简用法:
apiVersion: kafka.strimzi.io/v1 kind: Kafka metadata: name: my-cluster spec: # ... kafka 段、entityOperator 段等 cruiseControl: {}空对象即启用带全部默认值的 Cruise Control;若需自定义,则按测试中的写法在cruiseControl.config下提供键值对,例如:
cruiseControl: config: num.concurrent.partition.movements.per.broker: 5 num.concurrent.intra.broker.partition.movements: 2 num.concurrent.leader.movements: 1000 default.replication.throttle: -1六、如何复现运行这套测试
6.1 环境要求
- 一个可用的 Kubernetes 集群(本套件可并行运行于多个测试命名空间);
- 集群中已存在或可由测试安装的 Cluster Operator(
@BeforeAll会自动安装); - 构建工具链:Maven 与 JDK(参考仓库根目录 Makefile.maven 中的
mvn verify/mvn install流程)。
6.2 运行方式
官方推荐的系统测试入口是 systemtest/scripts/run_tests.sh:
./systemtest/scripts/run_tests.sh 'io.strimzi.systemtest.cruisecontrol.CruiseControlConfigurationST' systemtests脚本会以-pl systemtest -am构建 systemtest 模块及其依赖,并注入-Dit.test=<TESTCASE>指定测试类(详见 run_tests.sh)。也可以直接通过 Maven failsafe 运行:
mvn -B verify -pl systemtest -am -Psystemtests \ -DfailIfNoTests=false \ -Dit.test=io.strimzi.systemtest.cruisecontrol.CruiseControlConfigurationST测试运行的整体规范(集群准备、构建参数、报告收集)可进一步参考 TESTING.md 与 DEV_GUIDE.md。
七、相关测试与经验总结
7.1 与 Cruise Control 测试矩阵的关系
本套件是 Cruise Control 验证矩阵中的“配置管理”一环。从 cruise-control 标签页 可以看到,围绕 Cruise Control 还覆盖了:API 用户与基础请求(CruiseControlApiST)、Rebalance 状态流转与自动审批(CruiseControlST)、Broker 扩缩容期间行为、日志变更(LogSettingST)、指标暴露(MetricsST)等场景。CruiseControlConfigurationST与其互补:前者关注“行为正确”,本套件关注“配置正确”。
7.2 可复用的工程实践
从这套测试中可以提炼出三类可借鉴的验证模式:
- 变更影响面隔离断言:
testConfigurationUpdate同时断言“目标组件已滚动”与“非目标组件未滚动”,用快照 diff 方式杜绝回归,是配置类测试的标准范式; - 动态启停的配置双向验证:
testDeployAndUnDeployCruiseControl对同一断言分别验证“存在”与“不存在”两种形态,覆盖了清理逻辑(移除后无残留配置)与恢复逻辑(重装后配置完整回归); - 配置落盘级验证:测试不止于 CR 层面的字段断言,而是下沉到 ConfigMap 中实际生成的
cruisecontrol.properties/server.config,确保用户意图真正传递到了运行时配置。
对于在生产环境中管理 Cruise Control 的开发者而言,这套测试直观地回答了三个关键问题:修改性能调优参数是否安全(只会滚动 CC,不影响 broker)、能否在不删数据的前提下临时摘除 CC(可以,内部 Topic 会保留)、重新启用后配置能否完整恢复(能,metric reporter 与内部 Topic 均回归)。
参考阅读
- 测试实现:CruiseControlConfigurationST.java
- 验证工具:CruiseControlUtils.java
- 参数枚举:CruiseControlConfigurationParameters.java
- 配置默认值与目标过滤:CruiseControlConfiguration.java
- 组件模型:CruiseControl.java
- 部署示例:kafka-cruise-control.yaml
- 测试标签索引:cruise-control.md
【免费下载链接】strimzi-kafka-operatorApache Kafka® running on Kubernetes项目地址: https://gitcode.com/GitHub_Trending/st/strimzi-kafka-operator
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考