最近在学习 kafka 的时候在部署这一步遇到了些困难,没有采用 kafka+zookeeper 的部署方式,采用了 kafka3 新的部署方式。
记录一下部署过程中踩的坑。
一下的部署都使用 docker 进行部署
1. 部署方式
1.1. kafka+zookeeper 的部署方式
在 kafka3 版本之前需要用到 zookeeper 来管理 kafka 的元数据,调节 Broker 节点以实现分布式一致性,类似于 rocketMQ 的 nameServer。
同时还要负责 kafka 集群中 leader 和 controller 的选举。
1.2. kafka3 (Raft) 部署方式
在 kafka3 之后引入了 Raft 算法,通过 Raft 算法就可以实现自己集群内部的 leader 和 controller 的选举工作,然后由内部的 Controller Quorum 管理元数据,有原本的维护两个服务到现在只需要维护一个服务,工作量大大降低,稳定性也进一步提高。
但是使用新的部署方式会有一个问题,部署过 etcd 的朋友可能会知道启动时的配置十分麻烦,有些配置是 raft 算法必须的,因此 docker-compose可能会比较复杂。
2. 使用 kafka3(Raft)部署方式的 docker-compose
networks:
kafka:
driver: bridge
services:
kafka:
image: docker.io/bitnami/kafka:3.6.2
hostname: kafka
container_name: kafka
volumes:
- "kafka_data:/bitnami"
ports:
- "9092:9092" # 宿主机访问
- "19092:19092" # 容器网络内访问
- "9093:9093" # 控制器通信端口
environment:
# KRaft 模式核心配置
- KAFKA_CFG_NODE_ID=0
- KAFKA_CFG_PROCESS_ROLES=controller,broker
- KAFKA_CFG_CONTROLLER_QUORUM_VOTERS=0@kafka:9093
- KAFKA_AUTO_CREATE_TOPICS_ENABLE=true
# 多监听器配置
- KAFKA_CFG_LISTENERS=PLAINTEXT_HOST://:9092,PLAINTEXT://:19092,CONTROLLER://:9093
- KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT_HOST://kafka:9092
- KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
- KAFKA_CFG_CONTROLLER_LISTENER_NAMES=CONTROLLER
- KAFKA_CFG_INTER_BROKER_LISTENER_NAME=PLAINTEXT_HOST
networks:
- kafka
kafka-ui:
container_name: kafka-ui
image: provectuslabs/kafka-ui:latest
ports:
- 8080:8080
depends_on:
- kafka
environment:
DYNAMIC_CONFIG_ENABLED: "TRUE"
# 指定 Kafka broker 地址为容器网络内可访问的服务名
KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS: kafka:9092
networks:
- kafka
volumes:
kafka_data:
driver: local
以上就是部署的docker-compose。
在我部署的过程并没有部署kafka集群,因为是学习,单节点kafka已经够用,以后如果有需要还会部署kafka集群。
此文件中一共部署了两个服务,一个是kafka,一个是kafka-ui用来后台管理 kafka
在此文件中最重要的就是environment如何写,这也是本文章的重点
3. kafka部署environment详解
1. KRaft模式设置
environment:
- KAFKA_CFG_NODE_ID=0
- KAFKA_CFG_PROCESS_ROLES=controller,broker
- KAFKA_CFG_CONTROLLER_QUORUM_VOTERS=0@kafka:9093
- KAFKA_AUTO_CREATE_TOPICS_ENABLE=true
-
配置说明:
NODE_ID=0:节点唯一标识。PROCESS_ROLES:节点同时担任控制器和 broker 角色(单节点模式)。CONTROLLER_QUORUM_VOTERS:控制器选举配置(单节点只需自身)。AUTO_CREATE_TOPICS_ENABLE:自动创建 Topic(实测不生效)。
2. 监听器配置
- KAFKA_CFG_LISTENERS=PLAINTEXT_HOST://:9092,PLAINTEXT://:19092,CONTROLLER://:9093
- KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT_HOST://localhost:9092,PLAINTEXT://kafka:19092
-
配置说明:
-
LISTENERS:定义监听地址和端口。PLAINTEXT_HOST:供宿主机访问,绑定 9092 端口。PLAINTEXT:供容器网络内访问,绑定 19092 端口。CONTROLLER:控制器通信,绑定 9093 端口。
-
ADVERTISED_LISTENERS:对外通告的地址(客户端连接时使用)。PLAINTEXT_HOST:客户端需使用localhost:9092连接。PLAINTEXT:容器内服务使用kafka:19092连接。
-
-
注意事项:
- 如果是线上部署那么 9092 对应的监听地址一定要是客户端可以访问的地址,比如 go 程序要访问 kafka,那么访问 kafka 之后会先拿到
ADVERTISED_LISTENERS中写好的地址,如果 9092 端口对应的地址是 localhost 那么 go 程序就会访问localhost:9092但是因为是容器部署,或者不在同一台主机上部署,就会访问不到,所以返回的已经是一个外网或者同一内网可访问的地址。
- 如果是线上部署那么 9092 对应的监听地址一定要是客户端可以访问的地址,比如 go 程序要访问 kafka,那么访问 kafka 之后会先拿到
3.协议设置
- KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
- KAFKA_CFG_CONTROLLER_LISTENER_NAMES=CONTROLLER
- KAFKA_CFG_INTER_BROKER_LISTENER_NAME=PLAINTEXT_HOST
-
配置说明:
-
LISTENER_SECURITY_PROTOCOL_MAP:CONTROLLER:对应 PLAINTEXT,控制器之间进行通信使用明文PLAINTEXT:对应 PLAINTEXT,容器网络内部通信使用明文PLAINTEXT_HOST:对应 PLAINTEXT,外部访问使用明文通信,这里可以改为 SSL,kafka 支持多种安全协议
-
CONTROLLER_LISTENER_NAMES:-
指定用于 Controller 与 Broker 之间通信 的监听器名称。在 KRaft 模式(无 ZooKeeper)下,Controller 负责管理集群元数据、执行 Leader 选举等核心协调任务。
-
这表明使用名为
CONTROLLER的监听器处理 Controller 相关的通信。通常需要在listeners中定义该监听器:- KAFKA_CFG_LISTENERS=PLAINTEXT://:9092,CONTROLLER://:9093这里的
CONTROLLER://:9093表示 Controller 通信使用 9093 端口。
-
-
KAFKA_CFG_INTER_BROKER_LISTENER_NAME:-
指定 Broker 之间 内部通信 使用的监听器名称。例如,当一个 Broker 需要与其他 Broker 同步数据或交换元数据时,会使用此监听器。
配置示例
- KAFKA_CFG_INTER_BROKER_LISTENER_NAME=PLAINTEXT_HOST这表明 Broker 间通信使用名为
PLAINTEXT_HOST的监听器。通常需要在advertised.listeners中定义该监听器:- KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT_HOST://kafka:9092这里的
PLAINTEXT_HOST://kafka:9092表示 Broker 间通过kafka主机名和 9092 端口通信。
-
-
以上来看 kafka使用 KRaft 的配置还是比较繁琐的,但是客户端和 kafka 之间使用明文通信不太安全,代表着有人知道了 ip+port,那他就也可以使用我的 kafka。因此 kafka 针对外部访问有多种安全协议
4. kafka 针对外部访问安全协议
Kafka 提供四种主要的安全协议:
- PLAINTEXT:明文传输,不加密(默认)
- SSL/TLS:使用 SSL/TLS 加密通信
- SASL_PLAINTEXT:明文传输,但使用 SASL 进行身份验证
- SASL_SSL:SSL/TLS 加密 + SASL 身份验证
具体实现方式 TODO