Docker部署Kafka单机或者集群指南

前不久,Apache官方推出了Kafka的Docker镜像,这也使得我们可以容器化地部署Kafka消息中间件了。

那么今天我们就以KRaft模式部署Kafka的单机和集群为例,梳理一下如何使用Docker完成Kafka部署。

在学习本章节之前,建议大家先要弄清楚Kafka集群节点中的角色类型、常见的配置项意义等等 ,如果还不太熟悉建议先通过该博客进行学习:传送门

1,拉取镜像

通过下列命令即可:

bash 复制代码
docker pull apache/kafka

2,配置方式说明

在使用Docker部署Kafka时,我们可以通过下列方式来修改Kafka的配置:

  • 使用数据卷暴露配置目录,然后修改其中的文件
  • 使用环境变量指定

在使用Docker部署时,更加推荐使用环境变量的方式,这样我们一键就可以完成部署。

不过,配置文件中的配置名称和环境变量的名称格式是不一样的,因此在将配置文件中对应配置项转换成环境变量时,名称上需要进行一些转换:

  • 配置文件中名称的.要替换成_
  • 配置文件中名称的_要替换成__(双下划线)
  • 配置文件中名称的-要替换成___(三下划线)
  • 环境变量还需要在最前面加上KAFKA_前缀

下面举几个例子:

配置文件 环境变量
node.id KAFKA_NODE_ID
process.roles KAFKA_PROCESS_ROLES
listeners KAFKA_LISTENERS

3,开始部署

本次在一台服务器上进行实验,该服务器的地址是gitdoc.swsk33-mcs.top,我们下面都会使用这个地址代表外网地址。

(1) 单节点部署

在进行单节点部署并以KRaft模式运行时,该节点通常是混合节点的类型,通过下列命令:

bash 复制代码
docker run -id --name=kafka \
	-p 9092:9092 \
	-v kafka-config:/mnt/shared/config \
	-v kafka-data:/var/lib/kafka/data \
	-v kafka-secret:/etc/kafka/secrets \
	-e LANG=C.UTF-8 \
	-e KAFKA_INTER_BROKER_LISTENER_NAME=PLAINTEXT \
	-e KAFKA_CONTROLLER_LISTENER_NAMES=CONTROLLER \
	-e CLUSTER_ID=the-custom-id \
	-e KAFKA_NODE_ID=1 \
	-e KAFKA_PROCESS_ROLES=broker,controller \
	-e KAFKA_CONTROLLER_QUORUM_VOTERS="1@127.0.0.1:9093" \
	-e KAFKA_LISTENERS="PLAINTEXT://:9092,CONTROLLER://:9093" \
	-e KAFKA_ADVERTISED_LISTENERS="PLAINTEXT://gitdoc.swsk33-mcs.top:9092" \
	apache/kafka

可见我们挂载了下列数据卷:

  • kafka-config 持久化配置文件目录
  • kafka-data 持久化数据文件夹,如果运行出现问题可以清空该数据卷文件重启再试
  • kafka-secret 持久化秘钥相关文件夹

然后我们通过环境变量进行了许多了配置,除了指定容器环境为UTF-8之外,还有下列关于Kafka的配置:

  • KAFKA_INTER_BROKER_LISTENER_NAME Kafka的Broker地址前缀名称,固定为PLAINTEXT即可
  • KAFKA_CONTROLLER_LISTENER_NAMES Kafka的Controller地址前缀名称,固定为CONTROLLER即可
  • CLUSTER_ID 集群ID,可以自定义任何字符串作为集群ID,同一个集群中所有节点的集群ID必须配置为一样
  • KAFKA_NODE_ID 节点ID,用于标识每个集群中的节点,需要是不小于1的整数,同一个集群中的节点ID不可重复
  • KAFKA_PROCESS_ROLES 节点类型,broker,controller表示该节点是混合节点,通常单机部署时需要配置为混合节点
  • KAFKA_CONTROLLER_QUORUM_VOTERS 投票节点列表,通常配置为集群中所有的Controller节点,格式为节点id@节点外网地址:节点Controller端口,多个节点使用逗号,隔开,由于是混合节点,因此配置自己就行了
  • KAFKA_LISTENERS 表示Kafka要监听哪些端口,PLAINTEXT://:9092,CONTROLLER://:9093表示本节点作为混合节点,监听本机所有可用网卡90929093端口,其中9092作为客户端通信端口9093作为控制器端口
  • KAFKA_ADVERTISED_LISTENERS 配置Kafka的外网地址,需要是PLAINTEXT://外网地址:端口的形式,当客户端连接Kafka服务端时,Kafka会将这个外网地址广播给客户端,然后客户端再通过这个外网地址连接,除此之外集群之间交换数据时也是通过这个配置项得到集群中每个节点的地址的,这样集群中节点才能进行交互

大家可以和常用的配置项对应起来看,其实也很好理解,总的来说单机部署较为简单。

(2) 全混合节点集群

我们还可以部署多个混合节点,使它们构成一个集群,通常在开发或者实验环境下可以部署全混合节点,不过在生产环境就不推荐了。

我们本次实验的全混合节点集群信息如下:

容器名 节点id 节点外网地址 节点类型 容器9092端口映射到的宿主机端口 容器9093端口映射到的宿主机端口
kafka-1 1 gitdoc.swsk33-mcs.top broker,controller 9001 10001
kafka-2 2 gitdoc.swsk33-mcs.top broker,controller 9002 10002
kafka-3 3 gitdoc.swsk33-mcs.top broker,controller 9003 10003

在服务器上部署命令如下:

bash 复制代码
# 定义域名
# 这是fish shell的变量定义语法
# 使用bash请替换为:kafka_host="gitdoc.swsk33-mcs.top"
set kafka_host "gitdoc.swsk33-mcs.top"

# 节点1
docker run -id --name=kafka-1 \
	-p 9001:9092 -p 10001:9093 \
	-v kafka-config-1:/mnt/shared/config \
	-v kafka-data-1:/var/lib/kafka/data \
	-v kafka-secret-1:/etc/kafka/secrets \
	-e LANG=C.UTF-8 \
	-e KAFKA_INTER_BROKER_LISTENER_NAME=PLAINTEXT \
	-e KAFKA_CONTROLLER_LISTENER_NAMES=CONTROLLER \
	-e CLUSTER_ID=the-custom-id \
	-e KAFKA_NODE_ID=1 \
	-e KAFKA_PROCESS_ROLES=broker,controller \
	-e KAFKA_CONTROLLER_QUORUM_VOTERS="1@$kafka_host:10001,2@$kafka_host:10002,3@$kafka_host:10003" \
	-e KAFKA_LISTENERS="PLAINTEXT://:9092,CONTROLLER://:9093" \
	-e KAFKA_ADVERTISED_LISTENERS="PLAINTEXT://$kafka_host:9001" \
	apache/kafka

# 节点2
docker run -id --name=kafka-2 \
	-p 9002:9092 -p 10002:9093 \
	-v kafka-config-2:/mnt/shared/config \
	-v kafka-data-2:/var/lib/kafka/data \
	-v kafka-secret-2:/etc/kafka/secrets \
	-e LANG=C.UTF-8 \
	-e KAFKA_INTER_BROKER_LISTENER_NAME=PLAINTEXT \
	-e KAFKA_CONTROLLER_LISTENER_NAMES=CONTROLLER \
	-e CLUSTER_ID=the-custom-id \
	-e KAFKA_NODE_ID=2 \
	-e KAFKA_PROCESS_ROLES=broker,controller \
	-e KAFKA_CONTROLLER_QUORUM_VOTERS="1@$kafka_host:10001,2@$kafka_host:10002,3@$kafka_host:10003" \
	-e KAFKA_LISTENERS="PLAINTEXT://:9092,CONTROLLER://:9093" \
	-e KAFKA_ADVERTISED_LISTENERS="PLAINTEXT://$kafka_host:9002" \
	apache/kafka

# 节点3
docker run -id --name=kafka-3 \
	-p 9003:9092 -p 10003:9093 \
	-v kafka-config-3:/mnt/shared/config \
	-v kafka-data-3:/var/lib/kafka/data \
	-v kafka-secret-3:/etc/kafka/secrets \
	-e LANG=C.UTF-8 \
	-e KAFKA_INTER_BROKER_LISTENER_NAME=PLAINTEXT \
	-e KAFKA_CONTROLLER_LISTENER_NAMES=CONTROLLER \
	-e CLUSTER_ID=the-custom-id \
	-e KAFKA_NODE_ID=3 \
	-e KAFKA_PROCESS_ROLES=broker,controller \
	-e KAFKA_CONTROLLER_QUORUM_VOTERS="1@$kafka_host:10001,2@$kafka_host:10002,3@$kafka_host:10003" \
	-e KAFKA_LISTENERS="PLAINTEXT://:9092,CONTROLLER://:9093" \
	-e KAFKA_ADVERTISED_LISTENERS="PLAINTEXT://$kafka_host:9003" \
	apache/kafka

可以使用docker logs -f命令查看日志,输出Kafka Server started字样说明该节点启动成功,并已连结到其它集群节点:

我们可以在节点1中创建一个话题测试一下(调用容器中/opt/kafka/bin/路径下脚本进行操作):

bash 复制代码
docker exec -it kafka-1 /opt/kafka/bin/kafka-topics.sh --create --topic wocaoop --bootstrap-server localhost:9092

然后通过节点3获取话题:

bash 复制代码
docker exec -it kafka-3 /opt/kafka/bin/kafka-topics.sh --list --bootstrap-server localhost:9092

这说明我们的集群之间是可以正常进行数据交换的:

可见部署混合节点时,每个节点的部署方式和单机部署时几乎类似,不过需要注意的是:

  • 每个节点都需要暴露90929093端口,这两个端口作用如下:
    • 9092端口:用于客户端(生产者或者消费者)投递消息至Kafka消息队列或者从中取出消息,通常Java集成Kafka客户端时访问该端口,也就是客户端通信端口
    • 9093端口:KRaft模式下节点直接投票选举通信或者是从Controller节点获取元数据的端口,由于KRaft模式下没有了Zookeeper,因此集群中所有Kafka节点会相互投票选择出存放和管理元数据的Controller节点,这个端口就是用于投票选举时的相互通信或者从Controller节点获取元数据,也就是控制器端口
  • 由于都是混合节点,因此每个节点都有Controller属性,所以KAFKA_CONTROLLER_QUORUM_VOTERS都要配置为所有节点的外网地址和端口,端口需要是控制器端口
  • KAFKA_ADVERTISED_LISTENERS配置为每个节点的外网地址 及其客户端通信端口,需要保证客户端或者其它Kafka节点能够通过该地址端口在外网访问到

(3) Broker + Controller集群

这是推荐的生产环境的集群部署方式,集群中不存在混合节点,每个节点要么是Broker类型,要么是Controller类型,而不是像上面一样"身兼多职",这里我们的实验集群信息如下:

容器名 节点id 节点外网地址 节点类型 容器9092端口映射到的宿主机端口 容器9093端口映射到的宿主机端口
kafka-1 1 gitdoc.swsk33-mcs.top controller / 10001
kafka-2 2 gitdoc.swsk33-mcs.top broker 9002 /
kafka-3 3 gitdoc.swsk33-mcs.top broker 9003 /

通过下列命令在服务器上部署:

bash 复制代码
# 定义域名
# 这是fish shell的变量定义语法
# 使用bash请替换为:kafka_host="gitdoc.swsk33-mcs.top"
set kafka_host "gitdoc.swsk33-mcs.top"

# 节点1-Controller
docker run -id --name=kafka-1 \
	-p 10001:9093 \
	-v kafka-config-1:/mnt/shared/config \
	-v kafka-data-1:/var/lib/kafka/data \
	-v kafka-secret-1:/etc/kafka/secrets \
	-e LANG=C.UTF-8 \
	-e KAFKA_INTER_BROKER_LISTENER_NAME=PLAINTEXT \
	-e KAFKA_CONTROLLER_LISTENER_NAMES=CONTROLLER \
	-e CLUSTER_ID=the-custom-id \
	-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

# 节点2-Broker
docker run -id --name=kafka-2 \
	-p 9002:9092 \
	-v kafka-config-2:/mnt/shared/config \
	-v kafka-data-2:/var/lib/kafka/data \
	-v kafka-secret-2:/etc/kafka/secrets \
	-e LANG=C.UTF-8 \
	-e KAFKA_INTER_BROKER_LISTENER_NAME=PLAINTEXT \
	-e KAFKA_CONTROLLER_LISTENER_NAMES=CONTROLLER \
	-e CLUSTER_ID=the-custom-id \
	-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-Broker
docker run -id --name=kafka-3 \
	-p 9003:9092 \
	-v kafka-config-3:/mnt/shared/config \
	-v kafka-data-3:/var/lib/kafka/data \
	-v kafka-secret-3:/etc/kafka/secrets \
	-e LANG=C.UTF-8 \
	-e KAFKA_INTER_BROKER_LISTENER_NAME=PLAINTEXT \
	-e KAFKA_CONTROLLER_LISTENER_NAMES=CONTROLLER \
	-e CLUSTER_ID=the-custom-id \
	-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

这样,我们就部署了一个由1个Controller节点和2个Broker节点构成的集群,需要注意的是:

  • Broker节点无需 暴露9093端口,Controller节点无需 暴露9092端口,因为它们只需要使用一个端口,混合节点才是两个端口都需要使用
  • Broker节点需指定KAFKA_PROCESS_ROLESbroker,同样的Controller需要指定为controller
  • KAFKA_CONTROLLER_QUORUM_VOTERS配置只需要 写集群中所有的Controller节点的地址端口列表
  • 对于KAFKA_LISTENERS配置项:
    • Broker节点需要配置为PLAINTEXT://:9092,表示本节点作为Broker节点,监听本机所有可用网卡9092端口,即使用9092端口作为客户端通信端口
    • Controller节点需要配置为CONTROLLER://:9093,表示本节点作为Controller节点,监听本机所有可用网卡9093端口,即使用9093端口作为控制器端口
  • 对于KAFKA_ADVERTISED_LISTENERS配置项:
    • Controller节点不能指定该配置
    • Broker节点需要指定为自己的外网地址和端口,以PLAINTEXT://开头,和前面一样

4,Sping Boot连接到Kafka集群

在使用Spring Boot连接到Kafka集群时,需要先加入下列依赖:

xml 复制代码
<!-- 集成Kafka -->
<dependency>
	<groupId>org.springframework.kafka</groupId>
	<artifactId>spring-kafka</artifactId>
</dependency>

也可以在创建工程时,选择Messaging分类中的Spring for Apache Kafka作为依赖。

然后在application.yml配置文件中加入相关的配置,对于生产者:

yaml 复制代码
# Kafka-生产者配置
spring:
  kafka:
    bootstrap-servers: "127.0.0.1:9092"
    producer:
      key-serializer: "org.apache.kafka.common.serialization.StringSerializer"
      value-serializer: "org.springframework.kafka.support.serializer.JsonSerializer"

对于消费者:

yaml 复制代码
# Kafka-消费者配置
spring:
  kafka:
    bootstrap-servers: "127.0.0.1:9092"
    consumer:
      group-id: topic
      key-deserializer: "org.apache.kafka.common.serialization.StringDeserializer"
      value-deserializer: "org.springframework.kafka.support.serializer.JsonDeserializer"
      properties:
        "[spring.json.trusted.packages]": "*"

对于同时作为生产者和消费者的情况下:

yaml 复制代码
# Kafka-既是生产者也是消费者配置
spring:
  kafka:
    bootstrap-servers: "127.0.0.1:9092"
    producer:
      key-serializer: "org.apache.kafka.common.serialization.StringSerializer"
      value-serializer: "org.springframework.kafka.support.serializer.JsonSerializer"
    consumer:
      group-id: topic
      key-deserializer: "org.apache.kafka.common.serialization.StringDeserializer"
      value-deserializer: "org.springframework.kafka.support.serializer.JsonDeserializer"
      properties:
        "[spring.json.trusted.packages]": "*"

可见无论是哪种配置,都有spring.kafka.bootstrap-servers配置表示配置Kafka的节点地址,上述配置的是本地单机节点,对于集群配置如下:

yaml 复制代码
spring:
  kafka:
    bootstrap-servers: "kafka1地址:kafka1端口,kafka2地址:kafka2端口,kafka3地址:kafka3端口"
    # 省略其它...

可见指定集群每个节点的外网地址和端口即可,每个节点之间使用逗号隔开。

需要注意的是,连接集群时只配置Broker节点和混合节点的地址端口 即可,不要把Controller节点的地址端口配置进去了!

参考文档:

相关推荐
bestcxx37 分钟前
(九)Docker 的网络通信
docker·容器
孤城28641 分钟前
10 docker 安装 mysql详解
mysql·docker·微服务·容器
桂花很香,旭很美1 小时前
Qanything-docker-compose yaml文件(内含GPU 配置,备用学习)
docker
人生匆匆2 小时前
docker安装elasticesarch-head
运维·docker·jenkins
洛阳泰山3 小时前
Docker 镜像国内加速下载教程
docker·容器
盏灯4 小时前
🚢🚢🚢云服务器Docker快速通关——从部署到实战
docker
shark_西瓜甜5 小时前
shark云原生-日志体系-ECK
elasticsearch·docker·云原生
林鸿群6 小时前
Docker运行MSSQL2022
运维·docker·容器
A-刘晨阳6 小时前
ELFK 8.12.2 部署 -- docker部署方式⚽
linux·运维·elk·docker·容器
清华kenny6 小时前
docker部署redis/mongodb/
redis·mongodb·docker