3. 测试环境搭建:Docker Compose部署Kafka集群、Zookeeper配置、网络与端口规划

在集成测试中,环境的一致性与可重复性至关重要。本章将基于 Docker Compose 构建一个多节点 Kafka 集群,并详细说明 Zookeeper 配置、网络隔离策略以及端口映射规划。该环境将作为后续状态回溯与版本适配测试的基准沙箱。

3.1 整体架构与组件角色

测试集群采用 3 个 Zookeeper 节点 + 3 个 Kafka Broker 的标准高可用布局。Zookeeper 负责元数据管理与 Leader 选举,Kafka Broker 负责消息存储与读写。所有容器运行在同一个自定义 Docker 网络中,实现主机名解析与隔离。

Kafka 测试集群部署架构(Docker Compose) 自定义网络:kafka-test-net (bridge, 172.20.0.0/16) Zookeeper Ensemble zk-1 (leader/follower) zk-2 (follower) zk-3 (follower) Kafka Broker 集群 kafka-1 (broker.id=1) kafka-2 (broker.id=2) kafka-3 (broker.id=3) 测试客户端 / 生产者 测试客户端 / 消费者 端口映射:zk-1:2181 → 主机2181;kafka-1:9092 → 主机19092;kafka-2:9092 → 主机29092;kafka-3:9092 → 主机39092 内部通信使用容器名 + 端口,外部测试通过映射端口访问不同 Broker

3.2 Docker Compose 核心配置

以下 docker-compose.yml 定义了完整的服务、网络与卷挂载。每个 Zookeeper 实例通过 ZOO_MY_ID 和 ZOO_SERVERS 环境变量组成法定人数;每个 Kafka Broker 通过 KAFKA_ZOOKEEPER_CONNECT 指向所有 ZK 节点。

version: '3.8'
services:
  zk-1:
    image: confluentinc/cp-zookeeper:7.4.0
    container_name: zk-1
    environment:
      ZOOKEEPER_SERVER_ID: 1
      ZOOKEEPER_CLIENT_PORT: 2181
      ZOOKEEPER_TICK_TIME: 2000
      ZOOKEEPER_INIT_LIMIT: 5
      ZOOKEEPER_SYNC_LIMIT: 2
      ZOOKEEPER_SERVERS: zk-1:2888:3888;zk-2:2888:3888;zk-3:2888:3888
    ports:
      - "2181:2181"
    networks:
      kafka-test-net:
        ipv4_address: 172.20.0.11

  zk-2:
    image: confluentinc/cp-zookeeper:7.4.0
    container_name: zk-2
    environment:
      ZOOKEEPER_SERVER_ID: 2
      ZOOKEEPER_CLIENT_PORT: 2181
      ZOOKEEPER_TICK_TIME: 2000
      ZOOKEEPER_INIT_LIMIT: 5
      ZOOKEEPER_SYNC_LIMIT: 2
      ZOOKEEPER_SERVERS: zk-1:2888:3888;zk-2:2888:3888;zk-3:2888:3888
    ports:
      - "2182:2181"
    networks:
      kafka-test-net:
        ipv4_address: 172.20.0.12

  zk-3:
    image: confluentinc/cp-zookeeper:7.4.0
    container_name: zk-3
    environment:
      ZOOKEEPER_SERVER_ID: 3
      ZOOKEEPER_CLIENT_PORT: 2181
      ZOOKEEPER_TICK_TIME: 2000
      ZOOKEEPER_INIT_LIMIT: 5
      ZOOKEEPER_SYNC_LIMIT: 2
      ZOOKEEPER_SERVERS: zk-1:2888:3888;zk-2:2888:3888;zk-3:2888:3888
    ports:
      - "2183:2181"
    networks:
      kafka-test-net:
        ipv4_address: 172.20.0.13

  kafka-1:
    image: confluentinc/cp-kafka:7.4.0
    container_name: kafka-1
    depends_on:
      - zk-1
      - zk-2
      - zk-3
    environment:
      KAFKA_BROKER_ID: 1
      KAFKA_ZOOKEEPER_CONNECT: zk-1:2181,zk-2:2181,zk-3:2181
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka-1:9092,PLAINTEXT_HOST://localhost:19092
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
      KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 3
      KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 3
      KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 2
    ports:
      - "19092:19092"
    networks:
      kafka-test-net:
        ipv4_address: 172.20.0.21

  kafka-2:
    image: confluentinc/cp-kafka:7.4.0
    container_name: kafka-2
    depends_on:
      - zk-1
      - zk-2
      - zk-3
    environment:
      KAFKA_BROKER_ID: 2
      KAFKA_ZOOKEEPER_CONNECT: zk-1:2181,zk-2:2181,zk-3:2181
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka-2:9092,PLAINTEXT_HOST://localhost:29092
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
      KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 3
      KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 3
      KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 2
    ports:
      - "29092:29092"
    networks:
      kafka-test-net:
        ipv4_address: 172.20.0.22

  kafka-3:
    image: confluentinc/cp-kafka:7.4.0
    container_name: kafka-3
    depends_on:
      - zk-1
      - zk-2
      - zk-3
    environment:
      KAFKA_BROKER_ID: 3
      KAFKA_ZOOKEEPER_CONNECT: zk-1:2181,zk-2:2181,zk-3:2181
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka-3:9092,PLAINTEXT_HOST://localhost:39092
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
      KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 3
      KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 3
      KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 2
    ports:
      - "39092:39092"
    networks:
      kafka-test-net:
        ipv4_address: 172.20.0.23

networks:
  kafka-test-net:
    driver: bridge
    ipam:
      config:
        - subnet: 172.20.0.0/16

3.3 Zookeeper 配置详解

Zookeeper 的稳定性直接决定 Kafka 集群的元数据可靠性。以下参数在测试环境中需要重点关注:

参数 值 说明
ZOOKEEPER_SERVER_ID 1 / 2 / 3 每个节点唯一 ID,对应 data/myid 文件
ZOOKEEPER_CLIENT_PORT 2181 客户端连接端口,容器内统一使用 2181
ZOOKEEPER_TICK_TIME 2000 基本时间单元(ms),影响会话超时与心跳间隔
ZOOKEEPER_INIT_LIMIT 5 Leader 初始化连接时允许的最大 tick 数
ZOOKEEPER_SYNC_LIMIT 2 Follower 与 Leader 同步允许的最大 tick 数
ZOOKEEPER_SERVERS zk-1:2888:3888;zk-2:2888:3888;zk-3:2888:3888 2888 为 Leader 选举端口,3888 为集群通信端口
测试建议:在集成测试中,将 ZOOKEEPER_TICK_TIME 设置为 2000ms 而非默认的 3000ms,可以加速 Leader 选举与会话超时检测,帮助测试更快发现集群异常场景。

3.4 Kafka Broker 关键参数与端口规划

每个 Broker 使用 双监听器(Dual Listener) 策略:内部监听器 PLAINTEXT 用于 Broker 间通信与容器内客户端;外部监听器 PLAINTEXT_HOST 用于宿主机或 CI 环境中的测试程序。端口映射遵循“主机端口 = 1 + Broker ID + 9090”的规则,便于记忆与自动化脚本处理。

Broker 内部地址 外部映射端口 Advertised Listener(外部)
kafka-1 kafka-1:9092 19092 localhost:19092
kafka-2 kafka-2:9092 29092 localhost:29092
kafka-3 kafka-3:9092 39092 localhost:39092
版本适配要点:本配置使用 Confluent Platform 7.4.0(对应 Apache Kafka 3.4.0)。若需测试旧版本(如 2.8.x 或 3.0.x),只需修改镜像标签并调整 KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR 等参数。Docker Compose 的版本化配置使得多版本并行测试变得简单。

3.5 网络规划与容器间通信

自定义网络 kafka-test-net 使用 172.20.0.0/16 网段,为每个容器分配固定 IP。这样做的好处是:

  • 确定性寻址:测试脚本可以直接使用 IP 或容器名连接,不受 Docker 动态分配影响。
  • 网络隔离:与宿主机其他容器或服务完全隔离,避免端口冲突。
  • 故障注入:可通过 docker network disconnect 模拟网络分区,测试集群韧性。
网络通信与端口映射细节 宿主机 (Host) 端口 2181 → zk-1:2181 端口 2182 → zk-2:2181 端口 2183 → zk-3:2181 端口 19092 → kafka-1:9092 端口 29092 → kafka-2:9092 端口 39092 → kafka-3:9092 测试程序通过 localhost:19092 连接 Docker 网络:kafka-test-net 172.20.0.0/16 zk-1 .11 zk-2 .12 zk-3 .13 kafka-1 .21 kafka-2 .22 kafka-3 .23

3.6 启动验证与健康检查

环境搭建完成后,执行以下步骤验证集群状态:

  1. 启动所有服务:docker-compose up -d
  2. 检查 Zookeeper 集群状态:进入任意 ZK 容器执行 echo stat | nc localhost 2181,确认 Mode 为 leader 或 follower。
  3. 检查 Kafka Broker 注册:使用 docker exec kafka-1 kafka-broker-api-versions.sh --bootstrap-server kafka-1:9092 查看所有 Broker 的 API 版本。
  4. 创建测试 Topic:docker exec kafka-1 kafka-topics.sh --create --topic test-topic --partitions 3 --replication-factor 3 --bootstrap-server kafka-1:9092
  5. 验证 Topic 分布:docker exec kafka-1 kafka-topics.sh --describe --topic test-topic --bootstrap-server kafka-1:9092,确认每个分区有 3 个副本且 ISR 正常。
常见问题:如果 Broker 无法注册到 Zookeeper,请检查 KAFKA_ZOOKEEPER_CONNECT 中的主机名是否与 ZK 容器名一致,以及 ZK 的 ZOOKEEPER_SERVERS 是否使用了正确的容器名和端口。Docker 网络内必须使用容器名而非 localhost 进行跨容器通信。

3.7 环境清理与数据持久化

测试结束后,使用 docker-compose down -v 可彻底删除容器与卷数据,确保下一次测试从干净状态开始。若需要保留测试数据用于后续分析,可在 Compose 文件中为每个服务添加 volumes 映射:

volumes:
  - ./data/zk-1:/var/lib/zookeeper/data
  - ./data/kafka-1:/var/lib/kafka/data

在集成测试流水线中,建议每次运行前执行 docker-compose down -v && docker-compose up -d,以保证测试环境的绝对一致性。对于状态回溯测试,则需保留特定时间点的数据快照,通过卷挂载实现状态恢复。