Docker 安装 Kafka
Docker 安装 Kafka
简介
Apache Kafka 是一个分布式流处理平台,最初由 LinkedIn 开发,目前由 Apache 软件基金会维护。它被广泛用于消息队列、日志收集、实时数据管道和流式计算等场景。Kafka 以其高吞吐量、低延迟和持久化存储能力著称,是现代微服务架构中不可或缺的中间件。
在生产环境中部署 Kafka 通常比较复杂,涉及到 ZooKeeper 协调服务、Broker 配置、Topic 管理等多个环节。使用 Docker 容器化部署可以大幅简化这个过程,使开发人员和运维人员能够快速搭建和验证 Kafka 环境。
本文将从零开始,详细介绍如何使用 Docker 部署 Kafka,包括 ZooKeeper 的安装、Kafka 的配置、常见问题的排查、生产环境的优化建议,以及 Docker Compose 编排部署方案。
Kafka 核心概念
在开始部署之前,了解 Kafka 的核心概念有助于后续的配置和排障:
- Broker:Kafka 服务节点,每个 Broker 有一个唯一的
broker.id - Topic:消息的逻辑分类,生产者将消息发送到 Topic,消费者从 Topic 订阅消息
- Partition:Topic 的物理分片,每个 Partition 是一个有序的、不可变的日志序列
- Producer:消息生产者,负责将消息发送到 Kafka Broker
- Consumer:消息消费者,负责从 Kafka Broker 拉取消息
- Consumer Group:消费者组,组内每个消费者分担不同的 Partition
- ZooKeeper:协调服务,负责管理 Kafka 集群的元数据、Broker 注册和 Leader 选举
环境准备
系统要求
| 项目 | 最低要求 | 推荐配置 |
|---|---|---|
| 操作系统 | CentOS 7+ / Ubuntu 18.04+ | CentOS 7.9 |
| 内存 | 2GB(含 ZooKeeper) | 4GB+ |
| 磁盘 | 20GB | 50GB+ SSD |
| Docker | 19.03+ | 最新稳定版 |
| 网络 | 宿主机可访问 | 千兆网络 |
检查 Docker 环境
# 检查 Docker 版本
docker --version
# 检查 Docker 服务状态
systemctl status docker
# 检查可用内存
free -h
# 检查磁盘空间
df -h防火墙准备
Kafka 默认使用 9092 端口,ZooKeeper 使用 2181 端口。如果需要外部访问,需要提前开放这些端口:
# 查看防火墙当前的放行端口列表
firewall-cmd --list-ports
# 添加 ZooKeeper 端口(Kafka 依赖 ZooKeeper)
firewall-cmd --add-port=2181/tcp --permanent
# 添加 Kafka 端口
firewall-cmd --add-port=9092/tcp --permanent
# 重新加载防火墙(添加完放行端口一定要重新加载防火墙)
firewall-cmd --reload
# 验证端口是否放行成功
firewall-cmd --list-ports第一步:拉取 ZooKeeper 镜像
Kafka 强依赖 ZooKeeper 来管理集群元数据、Broker 注册和 Controller 选举。因此部署 Kafka 的第一步是先部署 ZooKeeper。
# 搜索可用的 ZooKeeper 镜像
docker search zookeeper
# 拉取 wurstmeister 官方 ZooKeeper 镜像(与 Kafka 镜像配套)
docker pull wurstmeister/zookeeper:latest
# 查看已拉取的镜像
docker images | grep zookeeper镜像选择建议
生产环境建议固定镜像版本标签,避免使用 latest 标签导致不可预期的行为变化。可以通过 Docker Hub 查看可用标签:
docker pull wurstmeister/zookeeper:3.4.14第二步:拉取 Kafka 镜像
# 拉取 wurstmeister 官方 Kafka 镜像
docker pull wurstmeister/kafka:latest
# 建议指定版本
docker pull wurstmeister/kafka:2.13-2.8.1
# 查看已拉取的镜像
docker images | grep kafka其他 Kafka 镜像选择
除了 wurstmeister/kafka,还有以下常用的 Kafka 镜像:
confluentinc/cp-kafka:Confluent 官方镜像,包含更多企业特性bitnami/kafka:Bitnami 维护,配置灵活,支持多种部署模式
第三步:启动 ZooKeeper
# 后台启动 ZooKeeper 容器
docker run -d \
--name zookeeper \
-p 2181:2181 \
-v /etc/localtime:/etc/localtime \
--restart=always \
wurstmeister/zookeeper:latest参数说明
| 参数 | 说明 |
|---|---|
-d | 后台运行容器 |
--name zookeeper | 指定容器名称为 zookeeper |
-p 2181:2181 | 端口映射,宿主机 2181 端口映射到容器 2181 端口 |
-v /etc/localtime:/etc/localtime | 容器时间同步宿主机时间,避免时间偏差导致问题 |
--restart=always | Docker 服务重启后容器自动启动 |
验证 ZooKeeper 启动状态
# 查看容器运行状态
docker ps | grep zookeeper
# 查看 ZooKeeper 启动日志
docker logs zookeeper
# 进入容器检查 ZooKeeper 状态
docker exec -it zookeeper bash
# 在容器内执行
echo ruok | nc localhost 2181
# 如果返回 imok 表示 ZooKeeper 运行正常第四步:启动 Kafka
基础启动命令
docker run -d \
--name kafka \
-p 9092:9092 \
-e KAFKA_BROKER_ID=0 \
-e KAFKA_ZOOKEEPER_CONNECT=192.168.3.249:2181/kafka \
-e KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://192.168.3.249:9092 \
-e KAFKA_LISTENERS=PLAINTEXT://0.0.0.0:9092 \
-v /etc/localtime:/etc/localtime \
--restart=always \
wurstmeister/kafka:latest参数详解
| 环境变量 | 说明 |
|---|---|
KAFKA_BROKER_ID=0 | 在 Kafka 集群中,每个 Broker 都有一个唯一的 broker.id 来区分自己,单机模式通常设为 0 |
KAFKA_ZOOKEEPER_CONNECT=192.168.3.249:2181/kafka | 指定 ZooKeeper 的连接地址和 Kafka 在 ZooKeeper 中的根路径 |
KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://192.168.3.249:9092 | 将 Kafka 的地址端口注册给 ZooKeeper,必须使用外部可访问的 IP 地址,不能使用 localhost 或 127.0.0.1 |
KAFKA_LISTENERS=PLAINTEXT://0.0.0.0:9092 | 配置 Kafka 的监听端口,0.0.0.0 表示监听所有网络接口 |
KAFKA_HEAP_OPTS="-Xmx256m -Xms256m" | 配置 JVM 堆内存大小,默认为 -Xmx1G -Xms1G |
注意
KAFKA_ADVERTISED_LISTENERS 是最容易出错的地方。如果设置为 localhost 或 127.0.0.1,外部客户端将无法连接到 Kafka,因为客户端会从 ZooKeeper 获取这个地址来建立连接。必须使用宿主机的实际 IP 地址或域名。
内存不足问题排查与解决
问题现象
在内存较小的服务器(尤其是 2GB 以下)上启动 Kafka 时,容器可能会不断重启或启动失败:
# 查看容器状态,发现容器不断 Restart
docker ps -a | grep kafka
# 使用 -it 模式交互式启动查看错误信息
docker run -it --name kafka_test \
-p 9092:9092 \
-e KAFKA_BROKER_ID=0 \
-e KAFKA_ZOOKEEPER_CONNECT=192.168.3.249:2181/kafka \
-e KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://192.168.3.249:9092 \
-e KAFKA_LISTENERS=PLAINTEXT://0.0.0.0:9092 \
-v /etc/localtime:/etc/localtime \
wurstmeister/kafka:latest在交互式模式下会看到类似以下错误:
Java HotSpot(TM) 64-Bit Server VM warning: INFO: os::commit_memory(0x00000000c0000000, 1073741824, 0) failed;
Error occurred during initialization of VM
Could not reserve enough space for object heap解决方案
通过 KAFKA_HEAP_OPTS 环境变量限制 JVM 堆内存:
# 限制为 256MB(适用于测试环境)
docker run -d \
--name kafka \
-p 9092:9092 \
-e KAFKA_BROKER_ID=0 \
-e KAFKA_ZOOKEEPER_CONNECT=192.168.3.249:2181/kafka \
-e KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://192.168.3.249:9092 \
-e KAFKA_LISTENERS=PLAINTEXT://0.0.0.0:9092 \
-e KAFKA_HEAP_OPTS="-Xmx256m -Xms256m" \
-v /etc/localtime:/etc/localtime \
--restart=always \
wurstmeister/kafka:latest不同环境下的内存建议
| 环境 | 推荐堆内存 | 命令参数 |
|---|---|---|
| 测试/开发 | 256MB - 512MB | -Xmx256m -Xms256m |
| 小型生产 | 1GB - 2GB | -Xmx1G -Xms1G(默认) |
| 中型生产 | 4GB - 8GB | -Xmx4G -Xms4G |
| 大型生产 | 8GB+ | -Xmx8G -Xms8G |
JVM 内存设置原则
Xms(初始堆内存)和Xmx(最大堆内存)建议设置为相同值,避免运行时动态扩缩容带来的性能开销- Kafka 堆内存不建议超过 8GB,因为 Kafka 大量使用操作系统的页缓存(Page Cache)
- 剩余内存留给操作系统的文件缓存,这对 Kafka 的磁盘读写性能至关重要
数据持久化配置
默认情况下,Kafka 容器删除后数据会丢失。生产环境必须配置数据持久化:
# 创建数据存储目录
mkdir -p /usr/local/docker/kafka/data
mkdir -p /usr/local/docker/kafka/logs
# 启动 Kafka 并挂载数据目录
docker run -d \
--name kafka \
-p 9092:9092 \
-e KAFKA_BROKER_ID=0 \
-e KAFKA_ZOOKEEPER_CONNECT=192.168.3.249:2181/kafka \
-e KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://192.168.3.249:9092 \
-e KAFKA_LISTENERS=PLAINTEXT://0.0.0.0:9092 \
-e KAFKA_LOG_DIRS=/kafka/data \
-e KAFKA_HEAP_OPTS="-Xmx1G -Xms1G" \
-v /usr/local/docker/kafka/data:/kafka/data \
-v /etc/localtime:/etc/localtime \
--restart=always \
wurstmeister/kafka:latestKafka 基本操作
Topic 管理
# 进入 Kafka 容器
docker exec -it kafka bash
# 创建 Topic(1个分区,1个副本)
kafka-topics.sh --create \
--zookeeper zookeeper:2181/kafka \
--topic test-topic \
--partitions 1 \
--replication-factor 1
# 查看 Topic 列表
kafka-topics.sh --list --zookeeper zookeeper:2181/kafka
# 查看 Topic 详细信息
kafka-topics.sh --describe --zookeeper zookeeper:2181/kafka --topic test-topic
# 删除 Topic
kafka-topics.sh --delete --zookeeper zookeeper:2181/kafka --topic test-topic生产与消费消息
# 在容器内启动生产者(交互式输入消息)
kafka-console-producer.sh --broker-list localhost:9092 --topic test-topic
# 在另一个终端启动消费者(实时消费消息)
kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic test-topic --from-beginning
# 从指定 offset 开始消费
kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic test-topic --offset 0 --partition 0消费者组管理
# 查看消费者组列表
kafka-consumer-groups.sh --bootstrap-server localhost:9092 --list
# 查看指定消费者组的详细信息
kafka-consumer-groups.sh --bootstrap-server localhost:9092 --describe --group my-group
# 重置消费者组的 offset
kafka-consumer-groups.sh --bootstrap-server localhost:9092 \
--group my-group --topic test-topic --reset-offsets --to-latest --executeDocker Compose 编排部署
对于需要同时管理 ZooKeeper 和 Kafka 的场景,推荐使用 Docker Compose 编排:
# docker-compose-kafka.yml
version: '3.8'
services:
zookeeper:
image: wurstmeister/zookeeper:3.4.14
container_name: zookeeper
ports:
- "2181:2181"
volumes:
- /etc/localtime:/etc/localtime
- ./zookeeper/data:/data
environment:
ZOO_MY_ID: 1
ZOO_SERVERS: server.1=0.0.0.0:2888:3888
restart: always
networks:
- kafka-net
kafka:
image: wurstmeister/kafka:2.13-2.8.1
container_name: kafka
ports:
- "9092:9092"
volumes:
- /etc/localtime:/etc/localtime
- ./kafka/data:/kafka/data
- /var/run/docker.sock:/var/run/docker.sock
environment:
KAFKA_BROKER_ID: 0
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181/kafka
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://192.168.3.249:9092
KAFKA_LISTENERS: PLAINTEXT://0.0.0.0:9092
KAFKA_LOG_DIRS: /kafka/data
KAFKA_HEAP_OPTS: "-Xmx1G -Xms1G"
KAFKA_CREATE_TOPICS: "test-topic:1:1"
depends_on:
- zookeeper
restart: always
networks:
- kafka-net
networks:
kafka-net:
driver: bridge使用 Compose 启动
# 创建目录结构
mkdir -p /usr/local/docker/kafka-compose
mkdir -p /usr/local/docker/kafka-compose/zookeeper/data
mkdir -p /usr/local/docker/kafka-compose/kafka/data
# 将 docker-compose-kafka.yml 放入目录后启动
cd /usr/local/docker/kafka-compose
docker-compose -f docker-compose-kafka.yml up -d
# 查看服务状态
docker-compose -f docker-compose-kafka.yml ps
# 查看日志
docker-compose -f docker-compose-kafka.yml logs -f kafka
# 停止所有服务
docker-compose -f docker-compose-kafka.yml down
# 停止并删除数据卷
docker-compose -f docker-compose-kafka.yml down -v常见问题排查
容器启动后立即退出
# 查看容器退出日志
docker logs kafka
# 常见原因:
# 1. 内存不足 → 设置 KAFKA_HEAP_OPTS 限制堆内存
# 2. ZooKeeper 未启动 → 先启动 ZooKeeper
# 3. 端口被占用 → 检查 9092 端口
ss -tlnp | grep 9092客户端无法连接 Kafka
# 1. 检查 ADVERTISED_LISTENERS 配置
docker inspect kafka | grep KAFKA_ADVERTISED_LISTENERS
# 2. 检查防火墙
firewall-cmd --list-ports
# 3. 测试端口连通性
telnet 192.168.3.249 9092
# 4. 检查 Kafka Broker 是否正常注册到 ZooKeeper
docker exec -it kafka bash
kafka-broker-api-versions.sh --bootstrap-server localhost:9092ZooKeeper 连接失败
# 检查 ZooKeeper 是否正常运行
docker ps | grep zookeeper
# 从 Kafka 容器内测试 ZooKeeper 连接
docker exec -it kafka bash
echo ruok | nc zookeeper 2181
# 如果使用宿主机 IP,确保网络可达
ping 192.168.3.249性能优化建议
Broker 配置优化
# 通过环境变量配置 Kafka Broker 参数
-e KAFKA_NUM_NETWORK_THREADS=4 \
-e KAFKA_NUM_IO_THREADS=8 \
-e KAFKA_SOCKET_SEND_BUFFER_BYTES=1024000 \
-e KAFKA_SOCKET_RECEIVE_BUFFER_BYTES=1024000 \
-e KAFKA_SOCKET_REQUEST_MAX_BYTES=104857600 \
-e KAFKA_LOG_RETENTION_HOURS=168 \
-e KAFKA_LOG_SEGMENT_BYTES=1073741824 \
-e KAFKA_LOG_RETENTION_CHECK_INTERVAL_MS=300000操作系统参数优化
# 增加文件描述符限制
echo "* soft nofile 65536" >> /etc/security/limits.conf
echo "* hard nofile 65536" >> /etc/security/limits.conf
# 优化网络参数
cat >> /etc/sysctl.d/99-kafka.conf <<EOF
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.ip_local_port_range = 1024 65535
net.ipv4.tcp_tw_reuse = 1
EOF
# 应用参数
sysctl -p /etc/sysctl.d/99-kafka.conf安全加固
配置 SASL 认证
# 创建 JAAS 配置文件
mkdir -p /usr/local/docker/kafka/config
cat > /usr/local/docker/kafka/config/kafka_server_jaas.conf <<EOF
KafkaServer {
org.apache.kafka.common.security.plain.PlainLoginModule required
username="admin"
password="admin-secret"
user_admin="admin-secret"
user_producer="producer-secret"
user_consumer="consumer-secret";
};
EOF
# 启动时挂载 JAAS 配置并启用认证
docker run -d \
--name kafka \
-p 9092:9092 \
-e KAFKA_BROKER_ID=0 \
-e KAFKA_ZOOKEEPER_CONNECT=192.168.3.249:2181/kafka \
-e KAFKA_ADVERTISED_LISTENERS=SASL_PLAINTEXT://192.168.3.249:9092 \
-e KAFKA_LISTENERS=SASL_PLAINTEXT://0.0.0.0:9092 \
-e KAFKA_SECURITY_INTER_BROKER_PROTOCOL=SASL_PLAINTEXT \
-e KAFKA_SASL_MECHANISM_INTER_BROKER_PROTOCOL=PLAIN \
-e KAFKA_SASL_ENABLED_MECHANISMS=PLAIN \
-e KAFKA_OPTS="-Djava.security.auth.login.config=/config/kafka_server_jaas.conf" \
-v /usr/local/docker/kafka/config:/config \
-v /usr/local/docker/kafka/data:/kafka/data \
--restart=always \
wurstmeister/kafka:latest监控与告警
Kafka Manager(可选)
# 使用 docker-compose 部署 Kafka Manager(CMAK)
# 添加到 docker-compose 文件中
kafka-manager:
image: hlebalbau/kafka-manager:stable
container_name: kafka-manager
ports:
- "9000:9000"
environment:
ZK_HOSTS: "zookeeper:2181"
restart: always
networks:
- kafka-net关键监控指标
| 指标 | 说明 | 告警阈值 |
|---|---|---|
BytesInPerSec | 每秒写入字节数 | 根据业务设定 |
BytesOutPerSec | 每秒读取字节数 | 根据业务设定 |
UnderReplicatedPartitions | 副本不足的分区数 | > 0 |
OfflinePartitionsCount | 离线分区数 | > 0 |
ControllerIsActive | Controller 是否活跃 | == 0 |
最佳实践总结
- 固定镜像版本:使用具体的版本标签(如
2.13-2.8.1),避免使用latest - 正确配置 ADVERTISED_LISTENERS:使用宿主机的实际 IP 地址或域名
- 合理设置堆内存:根据服务器总内存和业务负载调整,不要超过物理内存的 50%
- 数据持久化:始终挂载数据目录到宿主机
- 日志管理:配置合理的日志保留策略(保留时间和大小)
- 监控告警:部署监控工具,关注关键指标
- 安全认证:生产环境启用 SASL/SSL 认证
- 定期备份:备份 Kafka 配置文件和 ZooKeeper 数据
