目录
1. 创建目录结构
目录结构如下:
# 个人开发环境 目录
~/dev/
└── docker/ # docker-compose.yml 相关配置
# 挂载目录
/data
├── zookeeper/
│ ├── data/ # /var/lib/zookeeper/data 的挂载目录
│ ├── conf/ # /etc/zookeeper/conf 的挂载目录
│ └── datalog/ # 数据日志
├── kafka/
│ ├── data/ # /var/lib/kafka/data 的挂载目录
│ └── conf/ # /etc/kafka 的挂载目录
└── kafka-ui/
├── conf/ # /kafka-ui/conf 的挂载目录
└── logs/ # /kafka-ui/logs 的挂载目录
命令如下:
# 以app用户登录执行
mkdir -p ~/dev/docker
# 以root用户登录执行
sudo mkdir -p /data/zookeeper/{data,conf,datalog} /data/kafka/{data,conf} /data/kafka-ui/{conf,logs}
sudo chown -R 1000:1000 /data/zookeeper /data/kafka /data/kafka-ui
# 权限 700 表示:所有者(app):可读、可写、可执行;用户组和其他人:无权限
sudo chmod -R 700 /data/zookeeper /data/kafka /data/kafka-ui
# 创建配置文件
cat > /data/zookeeper/conf/zoo.cfg << EOF
# 基础配置
dataDir=/var/lib/zookeeper/data
clientPort=2181
tickTime=2000
initLimit=5
syncLimit=5
maxClientCnxns=100
# 自动清理快照和事务日志
autopurge.snapRetainCount=3
autopurge.purgeInterval=1
# 如果是集群模式,添加以下配置
# server.1=zk1:2888:3888
# server.2=zk2:2888:3888
# server.3=zk3:2888:3888
EOF
# 创建配置文件
cat > /data/kafka/conf/server.properties << EOF
# 消息大小相关配置
message.max.bytes=268435456
replica.fetch.max.bytes=268435456
max.request.size=268435456
# 网络相关配置
socket.send.buffer.bytes=102400
socket.receive.buffer.bytes=102400
socket.request.max.bytes=268435456
EOF
注意:Confluent的Zookeeper镜像(confluentinc/cp-zookeeper)是预先配置为使用名为appuser的非root用户(UID 1000),在许多Linux发行版中,第一个创建的常规用户通常被分配UID 1000,这种数值上的巧合并不意味着它们是"同一个用户"
效果图如下,图中“app:app”后续已用“1000:1000”替换执行:
2. 创建 Docker Compose 配置
在目录 /dev/docker 下创建自定义名称文件 kafka-docker-compose.yml,内容如下:
version: '3'
networks:
kafka_net:
driver: bridge
services:
zookeeper:
image: zookeeper:3.8.1
container_name: zookeeper
networks:
- kafka_net
ports:
- "2181:2181"
environment:
TZ: "Asia/Shanghai"
ZOOKEEPER_CLIENT_PORT: 2181
ZOOKEEPER_TICK_TIME: 2000
ZOOKEEPER_SERVER_ID: 1
ZOOKEEPER_CLIENT_PORT_ADDRESS: 0.0.0.0 # 可选,确保监听所有接口
ZOOKEEPER_MAX_CLIENT_CNXNS: 100
ZOOKEEPER_SYNC_LIMIT: 5 # 同步超时 10 秒(5 * 2000ms)
ZOO_DATA_DIR: /data
ZOO_DATA_LOG_DIR: /datalog
ulimits:
nofile: 65535
deploy:
resources:
limits:
memory: 4G
volumes:
- /data/zookeeper/data:/var/lib/zookeeper/data # 目录挂载到 /data/zookeeper/data
- /data/zookeeper/conf:/etc/zookeeper/conf # 目录挂载到 /data/zookeeper/conf
- /data/zookeeper/conf/zoo.cfg:/conf/zoo.cfg # 替换原有配置挂载
- /data/zookeeper/data:/data
- /data/zookeeper/datalog:/datalog
restart: unless-stopped
kafka:
image: bitnami/kafka:3.7.0
container_name: kafka
networks:
- kafka_net
depends_on:
- zookeeper
ports:
- "9092:9092"
- "9093:9093"
- "29092:29092"
environment:
TZ: "Asia/Shanghai"
KAFKA_BROKER_ID: 1
KAFKA_LISTENERS: INTERNAL://0.0.0.0:29092,EXTERNAL://0.0.0.0:9092,EXTERNAL_DOMAIN://0.0.0.0:9093
KAFKA_ADVERTISED_LISTENERS: INTERNAL://kafka:29092,EXTERNAL://<公网IP>:9092,EXTERNAL_DOMAIN://<域名>:9093
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: INTERNAL:PLAINTEXT,EXTERNAL:PLAINTEXT,EXTERNAL_DOMAIN:PLAINTEXT
KAFKA_INTER_BROKER_LISTENER_NAME: INTERNAL
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
KAFKA_LOG_RETENTION_HOURS: 168
KAFKA_NUM_PARTITIONS: 3
KAFKA_JMX_PORT: 9999 # 或者设置为 0 禁用 JMX
KAFKA_MESSAGE_MAX_BYTES: 268435456 # 256MB
KAFKA_REPLICA_FETCH_MAX_BYTES: 268435456
KAFKA_MAX_REQUEST_SIZE: 268435456
deploy:
resources:
limits:
cpus: '2'
memory: 4G
volumes:
- /data/kafka/data:/var/lib/kafka/data # 目录挂载到 /data/kafka/data
- /data/kafka/conf:/etc/kafka # 目录挂载到 /data/kafka/conf
restart: unless-stopped
# 监控与管理:Kafka-UI (CMAK)
kafka-ui:
image: provectuslabs/kafka-ui:latest
container_name: kafka-ui
networks:
- kafka_net
ports:
- "9000:8080"
environment:
TZ: "Asia/Shanghai"
KAFKA_CLUSTERS_0_NAME: local
KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS: kafka:29092
KAFKA_CLUSTERS_0_ZOOKEEPER: zookeeper:2181
SERVER_SERVLET_CONTEXT_PATH: /
AUTH_TYPE: LOGIN_FORM
SPRING_SECURITY_USER_NAME: admin
SPRING_SECURITY_USER_PASSWORD: admin
depends_on:
- kafka
- zookeeper
volumes:
- /data/kafka-ui/conf:/etc/kafka-ui
- /data/kafka-ui/logs:/app/logs
restart: unless-stopped
文件中公网IP可通过命令获取,命令如下:
curl ifconfig.me
# 或
curl icanhazip.com
# 或
curl ipecho.net/plain
# 或
curl ipinfo.io/ip
3. 启动服务
使用自定义名称的 Docker Compose 文件启动服务(笔者Docker版本 26.1.4),命令如下:
docker compose -f kafka-docker-compose.yml up -d
注意:从 Docker 20.10.13 开始,Docker Compose 已被集成为 Docker CLI 的一部分,作为docker compose 子命令提供,所以这里是 docker compose 而不是 docker-compose。
执行效果图如下:
4. 简化命令(可选)
如果您不想每次都输入完整的文件名,可以创建一个别名或简单的 shell 脚本:
4.1 方式一:创建永久别名
将上述别名添加到 ~/.bashrc 或 ~/.bash_aliases 文件:
echo 'alias kafka-compose="sudo docker compose -f /home/app/dev/docker/kafka-docker-compose.yml"' >> ~/.bashrc
source ~/.bashrc
4.2 方式二:创建 shell 脚本
在目录 /home/app/bin 目录下添加文件 kafka-compose,文件内容如下:
#!/bin/bash
docker compose -f /home/app/dev/docker/kafka-docker-compose.yml "$@"
设置权限,命令如下:
chmod +x /home/app/bin/kafka-compose
使用示例,命令如下:
kafka-compose up -d
kafka-compose ps
初次执行失败,效果图如下:
笔者是在 Windows 系统下创建文件后放入 Debian 系统中,文件格式有误导致,解决命令如下:
# 检查文件格式:如果输出中显示包含"CRLF"或"Windows"等词语,说明文件仍然是Windows格式
file /home/app/bin/kafka-compose
# 使用以下任一命令修复文件格式:应该显示为没有CRLF行终止符的纯Unix文本文件
# 方法1:使用dos2unix工具转换
dos2unix /home/app/bin/kafka-compose
# 方法2:如果没有dos2unix,可以使用sed命令
sed -i 's/\r$//' /home/app/bin/kafka-compose
# 再次检查文件格式
file /home/app/bin/kafka-compose
# 确认文件有执行权限
chmod +x /home/app/bin/kafka-compose
解决后再次执行成功,效果图如下:
5. 性能优化配置(可选)
笔者服务器配置(4核CPU、32GB内存、256GB SSD、4TB HDD),可以优化 Kafka 配置以提高性能。
5.1 更新配置文件
在目录 /data/kafka/conf 下更新配置文件 server.properties,内容如下:
# 基本配置
num.network.threads=8
num.io.threads=16
socket.send.buffer.bytes=102400
socket.receive.buffer.bytes=102400
socket.request.max.bytes=104857600
# 内存相关配置 (适合32GB内存)
replica.fetch.max.bytes=1048576
message.max.bytes=1000000
log.segment.bytes=1073741824
# 日志相关配置
num.partitions=8
default.replication.factor=1
log.retention.hours=168
log.retention.check.interval.ms=300000
# 性能优化
compression.type=producer
5.2 重启服务应用新配置
命令如下:
kafka-compose down
kafka-compose up -d
# 查看容器状态
docker ps
执行效果图如下:
查看容器状态,如果出现上图红框所示,可执行命令查看日志,命令如下:
docker logs kafka
部分效果图如下:
如果日志出现如上图所示,删除文件 /data/kafka/data/meta.properties,重启命令即可,效果图如下:
6. 创建测试主题
命令如下:
# 进入容器
docker exec -it kafka bash
# 查看 ZooKeeper 中的 Broker 注册信息
zookeeper-shell zookeeper:2181 ls /brokers/ids
# 创建主题
kafka-topics --create --topic test-topic --bootstrap-server kafka:29092 --partitions 3 --replication-factor 1
# 列出主题
kafka-topics --list --bootstrap-server kafka:29092
效果图如下:
注:Kafka Broker 已经成功注册到 ZooKeeper,输出 [1]
表示 Broker ID 为 1 的节点已注册,这是正常现象。最后的 ERROR Exiting JVM with code 0
是 zookeeper-shell
客户端退出时的日志,并非错误(退出码 0 表示正常退出)。因此,ZooKeeper 和 Kafka 的连接是正常的。
可视化界面效果图如下:
7. 安装常用工具(可选)
在 Docker 容器中,官方镜像通常出于安全性和精简体积的考虑,默认不安装 sudo 或其他非必要工具。以 sudo 为例,以下是针对不同场景的解决方案:
7.1 方式一:临时进入容器修改(适用于已运行的容器)
1. 以 root 用户进入容器,命令如下:
docker exec -u root -it kafka /bin/bash
2. 安装sudo(如果未安装):
yum install -y sudo
上述步骤 1、2 效果图如下:
3. 将用户添加到wheel组:
usermod -aG wheel appuser
4. 配置sudoers文件:
echo '%wheel ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/wheel-nopasswd
5. 退出并重新进入容器测试:
exit
docker exec -it kafka /bin/bash -l
sudo whoami # 应输出root
sudo su - root # 切换root
上述步骤 3~5 效果图如下:
验证与注意事项
- 组名确认:RHEL/UBI默认使用 wheel 组,可通过 grep wheel /etc/sudoers 确认。
- 安全性:无密码sudo(NOPASSWD)适用于测试环境,生产环境建议移除 NOPASSWD 并设置密码。
- 持久性:在 Dockerfile 中配置可确保设置持久化,临时修改在容器重建后失效。
7.2 方式二:通过Dockerfile构建镜像时配置
Dockerfile 文件参考内容如下:
FROM redhat/ubi8:8.6
# 安装sudo
RUN yum install -y sudo
# 创建用户并加入wheel组(RHEL/UBI中sudo组通常为wheel)
RUN useradd -G wheel myuser
# 配置sudoers允许wheel组无密码使用sudo
RUN echo '%wheel ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/wheel-nopasswd
# 切换到用户
USER myuser