背景
Apache Kafka 是一款开源的分布式流处理平台,最初由 LinkedIn 开发,现由 Apache 基金会维护。它的核心目标是高吞吐、可扩展、持久化的消息发布与订阅系统,常用于实时数据传输与处理。
Kafka 的核心特点如下:
- 高吞吐量、低延迟(性能测试)
- 消息有序
- 消息持久化存储,以便进行回溯/重放
- 消息压缩以移除键值日志中过时的记录
- 支持水平扩展
- 数据支持存储多份副本
KubeBlocks Addon
下面介绍 Addon 的具体实现,所有内容都基于 KubeBlocks 1.0 的 API。KubeBlocks API 的解释可以参考官网的介绍。
base image
自从 3.7 开始,Kafka 提供了官方打包的容器镜像(KIP-975)。在此之前,一些开源社区也基于自己的 Dockerfile 打包了 Kafka 镜像,如 bitnami/kafka、ubuntu/kafka、confluentinc/cp-kafka 等。基于成熟度、文档丰富度、开放程度等考虑,我们选择了 bitnami 作为基础镜像。
然而,bitnami 将在不久后存档并停止维护开源镜像。因此,未来我们也将考虑迁移到官方打包的镜像。
网络
Kafka 要求 client 能够连接每一个 broker。在 Kafka Client 中,我们可以指定任何一个 broker 的地址作为 bootstrap server,而后在读写 topic 时,bootstrap server 会返回 topic 所在的 broker 地址,client 重新连接至该地址进行读写操作。上述过程导致了 Kafka 在向集群外暴露服务时无法直接使用 Kubernetes Service 进行负载均衡。
在 Kafka 中,advertised.listeners 选项用于配置 broker 对外宣告的连接地址。通常我们会根据用途配置多个地址,比如 INTERNAL 作为内部通信地址,CLIENT 作为客户端通信地址(更多配置细节可参考这篇 Confluent 的文章)。而 Kafka 的连接问题主要是客户端连接 broker 的时候。因此,Kafka Addon 统一使用 Pod FQDN 作为内部通信地址。在客户端通信地址上,Kafka Addon 采取了以下几种方案:
- HeadlessService 模式,这是默认的模式。此时每个 broker 使用 Pod FQDN 作为 CLIENT listener 配置。这一方案只能够在集群内访问 Kafka。
- FixedPodIP 模式。该模式下每个 Pod 的 IP 地址通过 CNI 网络插件固定,Pod 重启不会改变 IP 地址,并且 Pod IP 能够在集群外访问。此时每个 broker 使用 Pod IP 作为 CLIENT listener 配置。这一方案能够在集群内和集群外访问 Kafka。
- NodePort 模式。该模式下 KubeBlocks 为每个 broker pod 建立一个 NodePort Service。此时每个 broker 使用 Host IP+NodePort 作为 CLIENT listener 配置。这一方案能够在集群内和集群外访问 Kafka。
除了上述方案中的 Service 之外,KubeBlocks 还能够通过 Expose OpsRequest 创建一个能够内网或公网访问的 Service,该 Service 的 Selector 为所有 brokers,作为 bootstrap server 使用。
集群模式
Kafka Addon 支持了以下三种集群模式:
- 组合模式,兼容 3.x 版本,controller 使用 KRaft 协议,broker 同时承担 controller 的角色。组合模式比较轻量,适合在开发、测试环境使用,不推荐在生产环境中使用。

- 分离模式,兼容 3.x 版本,controller 使用 KRaft 协议,broker 和 controller 分别位于不同的 Pod。broker 能够水平拓展,适合生产环境使用。

- ZooKeeper 模式,兼容 2.x 版本,broker 使用外部 ZooKeeper 集群存储元数据。

由于 3.x 之后 Kafka deprecate 了 ZooKeeper 的支持,并在 4.0 完全移除了 ZooKeeper 模式,ZooKeeper 模式只支持了老版本,新版本的 Kafka 都应该使用 KRaft 模式。
不同模式是通过不同的 ComponentDefition 实现的。在 ClusterDefinition 中,我们对不同的 ComponentDefinition 进行组合,来实现不同的模式。Kafka Exporter 由于需要 Kafka 集群全局的信息,也作为单独的一个 Component 部署。
YAML
apiVersion: apps.kubeblocks.io/v1
kind: ClusterDefinition
metadata:
# 省略
spec:
topologies:
- name: combined_monitor
default: true
components:
- name: kafka-combine
compDef: {{ include "kafka-combine.cmpdRegexpPattern" . }}
- name: kafka-exporter
compDef: {{ include "kafka-exporter.cmpdRegexpPattern" . }}
# orders 省略
- name: separated
components:
- name: kafka-controller
compDef: {{ include "kafka-controller.cmpdRegexpPattern" . }}
- name: kafka-broker
compDef: {{ include "kafka-broker.cmpdRegexpPattern" . }}
- name: kafka2-external-zk
components:
- name: kafka-broker
compDef: {{ include "kafka2-broker.cmpdRegexpPattern" . }}
- name: kafka-exporter
compDef: {{ include "kafka-exporter.cmpdRegexpPattern" . }}
扩缩容
垂直伸缩是 Kubernetes 原生支持的操作。KubeBlocks 同时支持了 Kubernetes 的 InPlacePodVerticalScaling 特性,能够在不重启 Pod 的情况下改变 CPU/内存资源限制。
水平伸缩
扩容 broker 很简单,我们只需要指定一个新的 broker id,broker 就会自动从 controller 中获取元数据并加入集群。然而,新加入的 broker 一开始不存储任何 topic partition。Kafka 提供了 kafka-reassign-partitions.sh 工具来将一部分 partition 迁移到新 broker(rebalance 操作)。Kafka Addon 目前还不支持这一操作。当然,用户可以手动 exec 进入 Kafka Pod 中执行脚本。
Broker 有一个 graceful shutdown 的特性,能够在退出时自动把所持有的 partition leadership 迁移到其他 broker 中。这一特性通过 controlled.shutdown.enable
选项控制,在 Kafka Addon 中,该选项默认为 true。因此在缩容 broker 时,partition leader 会自动迁移。然而,partition 所在的 broker 不会自动改变,所以用户仍然需要在缩容前手动执行 kafka-reassign-partitions.sh 工具迁移 partition。我们计划在未来版本中支持扩缩容时自动执行 rebalance 操作。
扩容 controller 也是直接新建一个节点,新节点会自动加入 KRaft 集群。controller 目前不支持缩容。
加密和认证
Kafka Addon 支持使用 KubeBlocks 提供的 TLS 证书进行 TLS 加密。在 ComponentDefinition 我们需要配置 .spec.tls
字段:
YAML
spec:
tls:
volumeName: tls
mountPath: /etc/pki/tls
caFile: ca.pem
certFile: cert.pem
keyFile: key.pem
而后用户只需将 Cluster CR 的 .spec.componentSpecs[*].tls
字段设置为 true 即可开启 TLS。此时 KubeBlocks 将自动生成 CA 证书、服务端 key,并根据 CA 证书签发服务端证书,这些证书文件将被挂载到 ComponentDefinition 中指定的路径下。
在 Kafka Addon 的启动脚本中,我们相应设置 listener.security.protocol.map
等参数之后即可启用 TLS。
Kafka Addon 还支持配置认证(Authentication),不过目前还不支持和 TLS 搭配使用。由于 Kafka 在 3.5 之后才在 KRaft 模式中支持 SASL/SCRAM 认证,Kafka Addon 的认证只支持 Zookeeper 模式。认证所使用的账号通过 ComponentDefition 中的 .spec.systemAccounts
字段声明:
YAML
spec:
systemAccounts:
- name: admin
initAccount: true
passwordGenerationPolicy:
length: 16
numDigits: 8
letterCase: MixedCases
通过在 vars 中引用这个账号,账号的用户名密码将作为环境变量传递给启动脚本,并由启动脚本进行账号初始化。
YAML
spec:
vars:
- name: KAFKA_ADMIN_USER
valueFrom:
credentialVarRef:
name: admin
optional: false
username: Required
- name: KAFKA_ADMIN_PASSWORD
valueFrom:
credentialVarRef:
name: admin
optional: false
password: Required
是否开启认证由 Cluster CR 中的 KB_KAFKA_ENABLE_SASL_SCRAM 环境变量控制。
监控与日志
Kafka Addon 使用 jmx-exporter 暴露单个 Pod 的 metrics,使用 kafka-exporter 暴露 Kafka 集群整体的 metrics,metrics 遵循 Prometheus 协议。日志输出到 stdout,并同步写入日志文件,用户任选收集容器日志或收集数据盘中的日志文件。Kafka Addon 的监控与日志可以和业界的大部分可观测性方案集成。
使用
您可以参照 Kafka Addon Examples 在本地进行体验,或者试用 KubeBlocks Cloud。