目录
在Kafka2.8版本之前,Kafka是强依赖于Zookeeper中间件的,这本身就很不合理,中间件依赖另一个中间件,搭建起来实在麻烦。所幸Kafka2.8之后推出了KRaft模式,即抛弃Zookeeper,由Kafka节点自己做Controller来选举Leader。本篇文章内容就是介绍如何在Docker中搭建Kafka KRaft环境。
一、安装Docker及可视化工具
Docker及可视化工具的安装可参考:Ubuntu上安装 Docker及可视化管理工具
二、单节点部署
在进行单节点部署并以KRaft模式运行时,该节点通常是混合节点的类型
1、创建挂载目录
# 创建宿主机kafka挂载目录
sudo mkdir -p /data/docker/kafka-kraft
2、命令运行容器
# 拉取镜像
sudo docker pull apache/kafka:3.9.0
# 运行容器
sudo docker run --privileged=true \
--net=bridge \
-d --name=kafka-kraft \
-v /data/docker/kafka-kraft/data:/var/lib/kafka/data \
-v /data/docker/kafka-kraft/config:/mnt/shared/config \
-v /data/docker/kafka-kraft/secrets:/etc/kafka/secrets \
-p 9092:9092 -p 9093:9093 \
-e TZ=Asia/Shanghai \
-e LANG=C.UTF-8 \
-e KAFKA_NODE_ID=1 \
-e CLUSTER_ID=kafka-cluster \
-e KAFKA_PROCESS_ROLES=broker,controller \
-e KAFKA_INTER_BROKER_LISTENER_NAME=PLAINTEXT \
-e KAFKA_CONTROLLER_LISTENER_NAMES=CONTROLLER \
-e KAFKA_LISTENERS=PLAINTEXT://:9092,CONTROLLER://:9093 \
-e KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://192.168.3.9:9092 \
-e KAFKA_CONTROLLER_QUORUM_VOTERS=1@localhost:9093 \
apache/kafka:3.9.0
注:
1、192.168.3.9 要替换为对外暴露的外网地址
参数解析如下:
参数 | 参数说明 |
docker run | 运行 Docker 容器 |
-d | 容器将在后台运行,而不是占用当前的终端会话 |
--privileged=true | Docker会赋予容器几乎与宿主机相同的权限 |
--net=bridge | 网络模式配置,默认是bridge,bridge表示使用容器内部配置网络 |
--name kafka-kraft | 给容器命名为 kafka-kraft,以便于管理和引用该容器 |
-p 9092:9092 -p 9093:9093 | 映射 kafka 的客户端通信端口和控制器端口 |
-e KAFKA_NODE_ID=1 | 节点ID,用于标识每个集群中的节点,需要是不小于1的整数,同一个集群中的节点ID不可重复 |
-e CLUSTER_ID=kafka-cluster | 集群ID,可以自定义任何字符串作为集群ID,同一个集群中所有节点的集群ID必须配置为一样 |
-e KAFKA_PROCESS_ROLES=broker,controller | 节点类型,broker,controller表示该节点是混合节点,通常单机部署时需要配置为混合节点 |
-e KAFKA_INTER_BROKER_LISTENER_NAME= PLAINTEXT | Kafka的Broker地址前缀名称,固定为PLAINTEXT即可 |
-e KAFKA_CONTROLLER_LISTENER_NAMES= CONTROLLER | Kafka的Controller地址前缀名称,固定为CONTROLLER即可 |
-e KAFKA_LISTENERS= PLAINTEXT://:9092,CONTROLLER://:9093 | 表示Kafka要监听哪些端口,PLAINTEXT://:9092,CONTROLLER://:9093表示本节点作为混合节点,监听本机所有可用网卡的9092和9093端口,其中9092作为客户端通信端口,9093作为控制器端口 |
-e KAFKA_ADVERTISED_LISTENERS= PLAINTEXT://192.168.3.9:9092 | 配置Kafka的外网地址,需要是PLAINTEXT://外网地址:端口的形式,当客户端连接Kafka服务端时,Kafka会将这个外网地址广播给客户端,然后客户端再通过这个外网地址连接,除此之外集群之间交换数据时也是通过这个配置项得到集群中每个节点的地址的,这样集群中节点才能进行交互。需要修改为对应的Kafka的外网地址。 |
-e KAFKA_CONTROLLER_QUORUM_VOTERS= 1@localhost:9093 | 投票节点列表,通常配置为集群中所有的Controller节点,格式为节点id@节点外网地址:节点Controller端口,多个节点使用逗号,隔开,由于是混合节点,因此配置自己就行了 |
-v /data/docker/kafka-kraft/data: /var/lib/kafka/data | 持久化数据文件夹,如果运行出现问题可以清空该数据卷文件重启再试 |
-v /data/docker/kafka-kraft/config: /mnt/shared/config | 持久化配置文件目录 |
-v /data/docker/kafka-kraft/secrets: /etc/kafka/secrets | 持久化秘钥相关文件夹 |
容器运行参数详解参考:Docker容器运行常用参数详解-CSDN博客
3、Compose运行容器
创建docker-compose.yml文件
sudo touch /data/docker/kafka-kraft/docker-compose.yml
文件内容如下:
version: '3'
services:
kafka:
image: apache/kafka:3.9.0
container_name: kafka-kraft
ports:
- "9092:9092"
- "9093:9093"
environment:
- TZ=Asia/Shanghai
- LANG=C.UTF-8
- KAFKA_NODE_ID=1
- CLUSTER_ID=kafka-cluster
- KAFKA_PROCESS_ROLES=broker,controller
- KAFKA_INTER_BROKER_LISTENER_NAME=PLAINTEXT
- KAFKA_CONTROLLER_LISTENER_NAMES=CONTROLLER
- KAFKA_LISTENERS=PLAINTEXT://:9092,CONTROLLER://:9093
- KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://192.168.3.9:9092
- KAFKA_CONTROLLER_QUORUM_VOTERS=1@localhost:9093
volumes:
- /data/docker/kafka-kraft/data:/var/lib/kafka/data
- /data/docker/kafka-kraft/config:/mnt/shared/config
- /data/docker/kafka-kraft/secrets:/etc/kafka/secrets
privileged: true
network_mode: "bridge"
运行容器
#-f:调用文件,-d:开启守护进程
sudo docker compose -f /data/docker/kafka-kraft/docker-compose.yml up -d
4、查看运行状态
5、验证生产消费
验证步骤如下,分别创建一个生产者和一个消费者,查看消费者是否能够收到生产者生产的消息
# 1.进入kafka容器内
sudo docker exec -it kafka-kraft /bin/bash
# 2.进入kafka安装目录
cd /opt/kafka/bin
# 3.生产消息
./kafka-console-producer.sh --topic test01 --bootstrap-server localhost:9092
# 3.消费消息
./kafka-console-consumer.sh --topic test01 --from-beginning --bootstrap-server localhost:9092 --partition 0
# 查询主题列表
./kafka-topics.sh --bootstrap-server localhost:9092 --list
# 查询消费组列表
./kafka-consumer-groups.sh --bootstrap-server localhost:9092 --list
生产消息
消费消息
验证结果表明,kafka部署正常,可正常生产和消费消息,但是Kraft模式无法通过指定group(消费组)消费到消息,需要通过指定partition(分区)才能消费到消息,这个问题应是Kafka的bug,后续再观察下。
三、集群部署
采用Broker + Controller集群,这是推荐的生产环境的集群部署方式,集群中不存在混合节点,每个节点要么是Broker类型,要么是Controller类型。
通过下列命令在服务器上部署:
# 定义域名
# 这是fish shell的变量定义语法
# 使用bash请替换为:kafka_host="192.168.3.9"
set kafka_host "192.168.3.9"
# 节点1-Controller
sudo docker run -id --privileged=true \
--net=bridge --name=kafka-1 \
-p 10001:9093 \
-v /data/docker/kafka-1/config:/mnt/shared/config \
-v /data/docker/kafka-1/data:/var/lib/kafka/data \
-v /data/docker/kafka-1/secrets:/etc/kafka/secrets \
-e LANG=C.UTF-8 \
-e KAFKA_INTER_BROKER_LISTENER_NAME=PLAINTEXT \
-e KAFKA_CONTROLLER_LISTENER_NAMES=CONTROLLER \
-e CLUSTER_ID=kafka-cluster \
-e KAFKA_NODE_ID=1 \
-e KAFKA_PROCESS_ROLES=controller \
-e KAFKA_CONTROLLER_QUORUM_VOTERS="1@$kafka_host:10001" \
-e KAFKA_LISTENERS="CONTROLLER://:9093" \
apache/kafka:3.9.0
# 节点2-Broker
sudo docker run -id --privileged=true \
--net=bridge --name=kafka-2 \
-p 9002:9092 \
-v /data/docker/kafka-2/config:/mnt/shared/config \
-v /data/docker/kafka-2/data:/var/lib/kafka/data \
-v /data/docker/kafka-2/secrets:/etc/kafka/secrets \
-e LANG=C.UTF-8 \
-e KAFKA_INTER_BROKER_LISTENER_NAME=PLAINTEXT \
-e KAFKA_CONTROLLER_LISTENER_NAMES=CONTROLLER \
-e CLUSTER_ID=kafka-cluster \
-e KAFKA_NODE_ID=2 \
-e KAFKA_PROCESS_ROLES=broker \
-e KAFKA_CONTROLLER_QUORUM_VOTERS="1@$kafka_host:10001" \
-e KAFKA_LISTENERS="PLAINTEXT://:9092" \
-e KAFKA_ADVERTISED_LISTENERS="PLAINTEXT://$kafka_host:9002" \
apache/kafka:3.9.0
# 节点3-Broker
sudo docker run -id --privileged=true \
--net=bridge --name=kafka-3 \
-p 9003:9092 \
-v /data/docker/kafka-3/config:/mnt/shared/config \
-v /data/docker/kafka-3/data:/var/lib/kafka/data \
-v /data/docker/kafka-3/secrets:/etc/kafka/secrets \
-e LANG=C.UTF-8 \
-e KAFKA_INTER_BROKER_LISTENER_NAME=PLAINTEXT \
-e KAFKA_CONTROLLER_LISTENER_NAMES=CONTROLLER \
-e CLUSTER_ID=kafka-cluster \
-e KAFKA_NODE_ID=3 \
-e KAFKA_PROCESS_ROLES=broker \
-e KAFKA_CONTROLLER_QUORUM_VOTERS="1@$kafka_host:10001" \
-e KAFKA_LISTENERS="PLAINTEXT://:9092" \
-e KAFKA_ADVERTISED_LISTENERS="PLAINTEXT://$kafka_host:9003" \
apache/kafka:3.9.0
这样,我们就部署了一个由1
个Controller节点和2
个Broker节点构成的集群,需要注意的是:
- Broker节点无需暴露9093端口,Controller节点无需暴露9092端口
- Broker节点需指定KAFKA_PROCESS_ROLES为broker,同样的Controller需要指定为controller
- KAFKA_CONTROLLER_QUORUM_VOTERS配置只需要写集群中所有的Controller节点的地址端口列表
- 对于KAFKA_LISTENERS配置项:Broker节点需要配置为PLAINTEXT://:9092,表示本节点作为Broker节点;Controller节点需要配置为CONTROLLER://:9093,表示本节点作为Controller节点
- 对于KAFKA_ADVERTISED_LISTENERS配置项:Controller节点不能指定该配置;Broker节点需要指定为自己的外网地址和端口
四、部署可视化工具
在早期使用Kafka时,通常会选择Kafka Tool或Kafka Eagle进行管理。Kafka Tool是一款桌面应用程序,而Kafka Eagle则基于浏览器运行。尽管这两款工具在用户体验上表现平平,但它们基本能满足日常需求。
然而,自Kafka 3.3.1版本起,Kafka正式弃用了Zookeeper,转而采用自有的仲裁机制,即kraft模式。遗憾的是,上述两款工具似乎未能及时跟进这一更新,仍然要求用户输入Zookeeper地址才能连接,导致它们在新版本Kafka中无法正常使用。为了解决这一问题,我发现了一款轻量且易于使用的替代工具——kafka-ui,它能够更好地适配新版Kafka。
1、创建挂载目录
# 创建宿主机kafka-ui挂载目录
sudo mkdir -p /data/docker/kafka-ui/config
# 创建挂载的配置文件
sudo touch /data/docker/kafka-ui/config/dynamic_config.yaml
2、命令运行容器
# 拉取镜像
sudo docker pull provectuslabs/kafka-ui:v0.7.2
# 运行容器
sudo docker run --privileged=true \
--net=bridge \
-d --name=kafka-ui \
-p 18080:8080 \
-v /data/docker/kafka-ui/config/dynamic_config.yaml:/etc/kafkaui/dynamic_config.yaml
-e KAFKA_CLUSTERS_0_NAME=kafka-cluster \
-e KAFKA_CLUSTERS_0_BOOTSTRAP_SERVERS=192.168.3.9:9092 \
-e SERVER_SERVLET_CONTEXT_PATH=/ \
-e AUTH_TYPE=LOGIN_FORM \
-e SPRING_SECURITY_USER_NAME=admin \
-e SPRING_SECURITY_USER_PASSWORD=admin \
-e TZ=Asia/Shanghai \
-e LANG=C.UTF-8 \
provectuslabs/kafka-ui:v0.7.2
参数解析如下:
参数 | 参数说明 |
docker run | 运行 Docker 容器 |
-d | 容器将在后台运行,而不是占用当前的终端会话 |
--privileged=true | Docker会赋予容器几乎与宿主机相同的权限 |
--net=bridge | 网络模式配置,默认是bridge,bridge表示使用容器内部配置网络 |
--name kafka-ui | 给容器命名为 kafka-ui,以便于管理和引用该容器 |
-p 18080:8080 | 映射 kafka-ui 的web端口 |
-v /data/docker/kafka-ui/config/dynamic_config.yaml: /etc/kafkaui/dynamic_config.yaml | 挂载配置文件,确保config/dynamic_config.yaml文件存在 |
-e SERVER_SERVLET_CONTEXT_PATH=/ | 默认kafka-ui是免登录的,为了防止所有人都可以登录产生误操作问题,在docker部署的时候可以添加如下四个环境变量配置用户的登录密码。 |
-e AUTH_TYPE=LOGIN_FORM | |
-e SPRING_SECURITY_USER_NAME=admin | |
-e SPRING_SECURITY_USER_PASSWORD=admin | |
-e KAFKA_CLUSTERS_0_NAME=kafka-cluster | 自定义集群名称 |
-e KAFKA_CLUSTERS_0_BOOTSTRAP_SERVERS= 192.168.3.9:9092 | 集群地址,如有多个地址逗号分隔;需要修改为对应的Kafka的外网地址。 |
3、Compose运行容器
创建docker-compose.yml文件
sudo touch /data/docker/kafka-ui/docker-compose.yml
文件内容如下:
version: '3'
services:
kafka:
image: provectuslabs/kafka-ui:v0.7.2
container_name: kafka-ui
ports:
- "18080:8080"
environment:
- TZ=Asia/Shanghai
- LANG=C.UTF-8
- DYNAMIC_CONFIG_ENABLED=true
- KAFKA_CLUSTERS_0_NAME=kafka-cluster
- KAFKA_CLUSTERS_0_BOOTSTRAP_SERVERS=192.168.3.9:9092
- SERVER_SERVLET_CONTEXT_PATH=/
- AUTH_TYPE=LOGIN_FORM
- SPRING_SECURITY_USER_NAME=admin
- SPRING_SECURITY_USER_PASSWORD=admin
volumes:
- /data/docker/kafka-ui/config/dynamic_config.yaml:/etc/kafkaui/dynamic_config.yaml
privileged: true
network_mode: "bridge"
运行容器
#-f:调用文件,-d:开启守护进程
sudo docker compose -f /data/docker/kafka-ui/docker-compose.yml up -d
4、查看运行状态
http://192.168.3.9:18080/auth
账号和密码 都是admin
五、Zookeeper模式和KRaft模式
Zookeeper 模式和 KRaft 模式各有其独特的优势和局限性,适用于不同的场景。
Zookeeper 模式:
- 成熟稳定的解决方案:对于那些需要高度可靠性和稳定性的企业级应用,Zookeeper 模式是一个成熟的选择。它已经在多个大型项目中得到了验证,能够有效管理复杂的集群环境。
- 易于管理和扩展:Zookeeper 模式下的 Kafka 集群管理相对简单,管理员可以轻松地添加或删除节点,调整集群配置。这对于需要频繁扩展和调整的业务场景非常有利。
- 强大的故障恢复能力:Zookeeper 能够快速检测和恢复节点故障,确保集群的高可用性。这对于需要持续运行的关键业务系统尤为重要。
KRaft 模式:
- 减少依赖:对于希望简化系统架构、降低维护成本的团队,KRaft 模式是一个理想的选择。它不再依赖于外部的 Zookeeper 服务,减少了系统的复杂性。
- 性能提升:KRaft 模式通过使用 Raft 共识算法,能够更高效地管理元数据,提高系统的整体性能。这对于需要处理大量数据和高并发请求的应用非常有益。
- 简化部署:KRaft 模式使得 Kafka 的部署和维护更加简单,用户无需额外安装和配置 Zookeeper 服务,降低了入门门槛。这对于初创公司和小型团队尤为适用。