Apache Kafka 正在进入一个更简洁、更高效的新时代。随着 KRaft(Kafka Raft Metadata mode)协议的成熟,我们终于可以告别繁琐的 ZooKeeper 依赖,实现一个纯粹的 Kafka 集群。本文将为您提供一份终极指南,手把手教您如何使用 Docker Compose,快速、可靠地部署一个符合生产环境最佳实践的 Kafka 3.9 服务。
为什么选择 KRaft?
- 架构简化:不再需要独立部署和维护一套 ZooKeeper 集群,降低了运维复杂性和资源开销。
- 性能提升:元数据管理直接在 Kafka 内部完成,恢复时间更快,可支持更多分区。
- 未来趋势:KRaft 是 Kafka 社区未来的发展方向,现在开始采用是明智之选。
前提条件
在开始之前,请确保您的系统已安装:
- Docker
- Docker Compose
第一步:生成唯一的集群 ID
KRaft 模式下的每个集群都需要一个全局唯一的 ID。这个 ID 用于在首次启动时安全地格式化存储目录。运行以下命令生成一个:
docker run --rm bitnami/kafka:3.9 kafka-storage.sh random-uuid
您会得到一串类似 aBcDeFgHiJkLmNoPqRsTuv
的字符串。请复制并保存好这个 ID,我们马上会用到它。
第二步:编写生产级 docker-compose.yml
这是本次部署的核心。创建一个名为 docker-compose.yml
的文件,并将以下内容粘贴进去。这份配置禁用了主题自动创建,这是生产环境推荐的做法。
请记得将 KAFKA_CLUSTER_ID
的值替换为您在第一步中生成的 ID。
# docker-compose.yml
services:
# 服务名,我们之后所有 docker compose 命令都将使用这个名字
kafka:
image: bitnami/kafka:3.9
container_name: kafka-kraft-node
restart: unless-stopped
ports:
# 将容器的 9092 端口映射到宿主机,供外部客户端连接
- "9092:9092"
volumes:
# 持久化 Kafka 数据,防止容器删除后数据丢失
- "kafka_data:/bitnami/kafka"
environment:
# --- 1. KRaft 模式核心配置 ---
- KAFKA_CFG_NODE_ID=1
- KAFKA_CFG_PROCESS_ROLES=broker,controller
- KAFKA_CFG_CONTROLLER_QUORUM_VOTERS=1@kafka:9093
# --- 2. 监听器 (Listeners) 关键配置 ---
- KAFKA_CFG_LISTENERS=BROKER://:9092,CONTROLLER://:9093
- KAFKA_CFG_ADVERTISED_LISTENERS=BROKER://localhost:9092
- KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,BROKER:PLAINTEXT
- KAFKA_CFG_INTER_BROKER_LISTENER_NAME=BROKER
- KAFKA_CFG_CONTROLLER_LISTENER_NAMES=CONTROLLER
# --- 3. 集群 ID 与生产级配置 ---
- KAFKA_CLUSTER_ID=aBcDeFgHiJkLmNoPqRsTuv # <-- !!!替换为你自己的集群ID !!!
# 生产环境最佳实践:禁用主题自动创建,所有主题都需手动管理
- KAFKA_CFG_AUTO_CREATE_TOPICS_ENABLE=false
- ALLOW_PLAINTEXT_LISTENER=yes
volumes:
kafka_data:
driver: local
第三步:理解关键配置(The “Why”)
- KRaft 模式核心配置
KAFKA_CFG_PROCESS_ROLES=broker,controller
: 这是 KRaft 的魔法所在。它告诉 Kafka 这个节点同时扮演数据代理(broker)和元数据控制器(controller)的角色。
- 监听器 (Listeners) 关键配置
KAFKA_CFG_ADVERTISED_LISTENERS
: 这是 Kafka 广播给外部客户端的地址。如果你的客户端在其他机器上,请将localhost
替换为你的宿主机 IP。KAFKA_CFG_CONTROLLER_LISTENER_NAMES
: 这是一个关键点! 它明确告诉控制器角色:“请使用名为CONTROLLER
的监听器进行内部通信”。
- 生产级配置
KAFKA_CLUSTER_ID
: 我们在第一步生成的 ID。Bitnami 镜像的启动脚本会检测到这个变量,并在数据目录为空时,自动为你执行格式化。KAFKA_CFG_AUTO_CREATE_TOPICS_ENABLE=false
: 核心最佳实践。禁用此项意味着任何生产者或消费者都不能在主题不存在时自动创建它。这强制了对主题的显式管理,避免了因拼写错误等问题导致的“主题泛滥”,让集群更干净、可控。
第四步:启动并验证 Kafka 服务
现在,一切准备就绪,让我们启动服务。
- 启动容器:
在docker-compose.yml
文件所在的目录,运行:docker compose up -d
- 检查状态:
bash docker compose ps
您应该能看到kafka
服务的状态是Up
或running
,这表示它已成功启动。
第五步:实战测试:管理并使用主题
由于我们禁用了主题自动创建,所以必须先创建主题,然后才能收发消息。这是规范的生产流程。
Pro Tip:
docker compose
的所有命令都针对docker-compose.yml
中定义的服务名(在我们的例子中是kafka
),而不是container_name
。
- 创建主题 (在一个终端中运行):
这是现在的必需步骤!docker compose exec kafka kafka-topics.sh --create --topic my.managed.topic --partitions 1 --replication-factor 1 --bootstrap-server localhost:9092
成功后会返回:Created topic "my-managed-topic".
如果尝试向一个不存在的主题发送消息,生产者将会报错或超时,因为无法自动创建它。- 由于 Kafka 内部监控指标(Metrics)的命名机制存在限制,如果你在主题名称中同时使用点号(.)和下划线(_)作为分隔符,可能会导致监控指标的名称发生冲突。为了避免潜在问题,最佳实践是:在你的整个项目中,统一只使用一种分隔符,要么只用点号,要么只用下划线。
- 启动生产者并发送消息 (在同一个或新终端中运行):
docker compose exec kafka kafka-console-producer.sh --topic my-managed-topic --bootstrap-server localhost:9092
现在,您可以输入任何内容,按回车键发送:> Welcome to a production-ready Kafka! > Topics are managed explicitly. >
按Ctrl+C
退出生产者。 - 启动消费者并接收消息 (在另一个新终端中运行):
bash docker compose exec kafka kafka-console-consumer.sh --topic my-managed-topic --from-beginning --bootstrap-server localhost:9092
您将立即看到刚才发送的所有消息被打印出来:Welcome to a production-ready Kafka! Topics are managed explicitly.
清理和停止
当您完成测试后,可以使用以下命令来停止并清理环境:
# 停止并删除容器
docker compose down
# 停止、删除容器,并删除数据卷
docker compose down -v
结语
恭喜你!你已经成功部署了一个现代、简洁、且遵循生产环境最佳实践的 Kafka 服务。通过 KRaft 和 Docker Compose 的结合,整个过程变得前所未有的简单和高效。现在,你可以基于这个坚实的基础,开始构建你的实时数据应用了。