欢迎光临
我们一直在努力

在k8s中部署Kafka高可用集群超详细讲解

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */
#content_views .toc,
/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */
#content_views.markdown_views > p:empty:has(+ .toc),
#content_views.markdown_views > .toc + p:empty,
/* 富文本旧版目录标记 */
#content_views.htmledit_views #main-toc,
#content_views.htmledit_views #hr-toc,
#content_views.htmledit_views p[id*=\”-toc\”] {
display: none !important;
}
/* 目录去掉后,紧跟的首个标题不再多出一块上边距 */
#content_views.markdown_views > .toc + h1,
#content_views.markdown_views > .toc + h2,
#content_views.markdown_views > .toc + h3,
#content_views.markdown_views > .toc + h4,
#content_views.markdown_views > .toc + p:empty + h1,
#content_views.markdown_views > .toc + p:empty + h2,
#content_views.markdown_views > .toc + p:empty + h3,
#content_views.markdown_views > .toc + p:empty + h4 {
margin-top: 0 !important;
}

第一部分:理论基础与架构设计

1.1 Kafka 高可用核心原理

Kafka 的高可用性基于其原生的分布式架构:

  • 分区与副本机制:每个 Topic 的 Partition 可以有多个 Replica,分布在不同的 Broker 上。Leader 负责读写,Follower 负责同步。当 Leader 故障时,会在 ISR(In-Sync Replicas)中选举新的 Leader。

  • ISR 机制:只有与 Leader 保持同步的 Follower 才在 ISR 集合中。这是 Kafka 保证数据一致性和可用性的关键。

  • Ack 模式:acks=all 确保消息被所有 ISR 副本确认后才返回成功,这是实现不丢数据的高可用基础。

  • Broker 故障转移:Kafka 集群能自动检测 Broker 失效并重新分配 Leader。

在 Kubernetes 环境中,我们依赖 StatefulSet 来管理 Broker Pod 的稳定标识(如 kafka-0、kafka-1),并通过 PersistentVolumeClaim (PVC) 保证每个 Broker 的数据持久化。

1.2 Kubernetes 环境下的挑战

将 Kafka 部署在 Kubernetes 上,需要解决以下关键问题:

挑战解决方案
状态管理 使用 StatefulSet 和 PVC,确保每个 Broker 拥有唯一的网络标识和持久化存储
网络通信 需要区分内部通信(Broker 间)和外部访问(Producer/Consumer),通常使用 Headless Service 和 LoadBalancer/NodePort
存储性能 Kafka 对磁盘 IO 要求极高,必须使用 SSD 或高性能块存储,并考虑本地存储(Local PV)或高吞吐的云存储
集群配置一致性 配置复杂且易错,使用 Operator 模式自动化管理配置、滚动升级、扩缩容
故障自愈 Operator 需要监听 Kafka 资源状态,自动处理 Pod 重启、重新平衡、恢复等操作

1.3 为什么选择 Strimzi Operator

Strimzi 是 CNCF 孵化项目,是目前 Kubernetes 上部署 Kafka 的事实标准。它提供:

  • 声明式配置:通过 YAML 定义 Kafka、KafkaTopic、KafkaUser 等 CRD,实现 GitOps 管理。

  • 自动化运维:支持滚动升级、Pod 中断预算、自动 rebalance、证书管理(TLS 自动轮换)。

  • KRaft 支持:从 Strimzi 0.39+ 开始,原生支持 KRaft 模式(Kafka Raft Metadata),彻底替代 ZooKeeper,简化架构。

  • 监控集成:内置 Prometheus 指标导出和 Grafana 仪表盘支持。

1.4 KRaft 模式详解

传统的 Kafka 依赖 ZooKeeper 存储元数据(Broker 列表、Topic 配置、分区信息等),这带来了运维复杂性。KRaft(Kafka Raft)是 Kafka 2.8 引入的元数据管理新模式,在 3.3+ 版本中已生产可用。

KRaft 优势:

  • 架构简化,无需维护独立的 ZooKeeper 集群

  • 元数据存储更高效,支持百万级分区

  • 更快的 Controller 故障转移

KRaft 角色:

  • Controller:负责管理集群元数据,进行 Leader 选举。在 KRaft 中,Broker 可以同时扮演 Controller 角色(合并模式)。

  • Broker:处理生产者和消费者的数据请求。

节点类型:

  • Combined 模式:一个节点既是 Controller 又是 Broker(适合中小集群)

  • Separate 模式:Controller 节点独立,不承担数据流量(适合大规模生产环境)

在本文中,我们将使用 Combined 模式 部署 3 节点集群,每个节点同时是 Controller 和 Broker,形成 3/3 仲裁。


第二部分:环境准备与依赖安装

2.1 Kubernetes 集群要求

  • 版本:Kubernetes 1.25+(推荐 1.28+)

  • 节点:至少 3 个 worker 节点(用于高可用)

  • 存储类:支持动态卷供应的 StorageClass(如 standard、fast-ssd)

  • 资源预留:每个 Broker 建议 4-8 GB 内存、4-8 核 CPU,根据流量调整

2.2 安装 Strimzi Operator

我们使用 Helm 或直接 YAML 安装 Strimzi Operator。

方式一:Helm 安装

bash

# 添加 Strimzi Helm 仓库
helm repo add strimzi https://strimzi.io/charts/
helm repo update

# 创建命名空间
kubectl create namespace kafka

# 安装 Operator
helm install strimzi-operator strimzi/strimzi-kafka-operator \\
–namespace kafka \\
–set watchAnyNamespace=true

方式二:直接 YAML

bash

kubectl create namespace kafka
kubectl apply -f 'https://strimzi.io/install/latest?namespace=kafka' -n kafka

等待 Operator Pod 就绪:

bash

kubectl wait –for=condition=ready pod -l name=strimzi-cluster-operator -n kafka –timeout=300s

2.3 配置 StorageClass

检查现有 StorageClass:

bash

kubectl get storageclass

如果没有适合的,可以创建本地存储类(示例为基于 hostPath 的测试环境,生产环境推荐使用 CSI 驱动):

yaml

# local-storage.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: local-ssd
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer

生产建议:

  • 云环境:使用云厂商的 SSD 存储类(如 AWS gp3、GCP pd-ssd、Azure managed-premium)

  • 本地存储:使用 Local Persistent Volume + 节点亲和性,或 OpenEBS、Rook 等存储方案


第三部分:部署 Kafka KRaft 集群

3.1 编写 Kafka CR 资源文件

以下是生产级 3 节点 KRaft 模式的 Kafka 集群配置。文件命名为 kafka-kraft.yaml。

yaml

apiVersion: kafka.strimzi.io/v1beta2
kind: Kafka
metadata:
name: kafka-cluster
namespace: kafka
spec:
kafka:
version: 3.7.0
replicas: 3
# KRaft 模式配置
metadataVersion: "3.7-IV0"
storage:
type: persistent-claim
size: 100Gi
class: local-ssd # 替换为你的存储类
deleteClaim: false
listeners:
– name: plain
port: 9092
type: internal
tls: false
– name: tls
port: 9093
type: internal
tls: true
– name: external
port: 9094
type: nodeport
tls: true
authentication:
type: tls
configuration:
bootstrap:
nodePort: 30094
brokers:
– broker: 0
nodePort: 30095
– broker: 1
nodePort: 30096
– broker: 2
nodePort: 30097
config:
# KRaft 特定配置
offsets.topic.replication.factor: 3
transaction.state.log.replication.factor: 3
transaction.state.log.min.isr: 2
default.replication.factor: 3
min.insync.replicas: 2
auto.create.topics.enable: false
# 性能调优
num.network.threads: 8
num.io.threads: 8
socket.send.buffer.bytes: 102400
socket.receive.buffer.bytes: 102400
socket.request.max.bytes: 104857600
num.partitions: 6
# 日志配置
log.retention.hours: 168
log.segment.bytes: 1073741824
log.retention.check.interval.ms: 300000
resources:
requests:
memory: 4Gi
cpu: 2
limits:
memory: 8Gi
cpu: 4
jvmOptions:
-Xmx: 6G
-Xms: 4G
metricsConfig:
type: jmxPrometheusExporter
valueFrom:
configMapKeyRef:
name: kafka-metrics
key: kafka-metrics-config.yml
# 配置滚动更新策略
template:
pod:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
– labelSelector:
matchExpressions:
– key: strimzi.io/cluster
operator: In
values:
– kafka-cluster
– key: strimzi.io/name
operator: In
values:
– kafka-cluster-kafka
topologyKey: kubernetes.io/hostname
podDisruptionBudget:
maxUnavailable: 1
# KRaft 模式下无需 zookeeper 配置块
entityOperator:
topicOperator: {}
userOperator: {}

3.2 配置 Kafka Exporter 指标(可选)

创建 ConfigMap 用于 Prometheus 指标导出:

yaml

# kafka-metrics-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: kafka-metrics
namespace: kafka
data:
kafka-metrics-config.yml: |
lowercaseOutputName: true
rules:
– pattern: kafka.controller<type=ControllerStats><>(.*)
name: kafka_controller_$1
type: GAUGE
– pattern: kafka.server<type=BrokerTopicMetrics, name=(.*)><>(.*)
name: kafka_server_brokertopicmetrics_$1_$2
type: COUNTER

3.3 部署集群

bash

# 创建 ConfigMap
kubectl apply -f kafka-metrics-config.yaml -n kafka

# 部署 Kafka 集群
kubectl apply -f kafka-kraft.yaml -n kafka

# 查看状态
kubectl get kafka -n kafka
kubectl get pods -n kafka -l strimzi.io/cluster=kafka-cluster

等待所有 Pod 变为 Running 且 Ready(约 5-10 分钟,取决于存储挂载速度)。

bash

kubectl wait –for=condition=ready pod -l strimzi.io/name=kafka-cluster-kafka -n kafka –timeout=600s

3.4 验证 KRaft 模式运行

进入任意 Broker Pod 验证元数据节点:

bash

kubectl exec -it kafka-cluster-kafka-0 -n kafka — bin/kafka-metadata-quorum.sh –bootstrap-server localhost:9092 describe –status

输出应显示三个节点在仲裁中,并且 Leader 和 Voter 状态正常。


第四部分:配置外部访问与安全

4.1 外部访问方式选择

Strimzi 支持多种外部监听类型:

类型适用场景优缺点
NodePort 测试、小型生产 简单,但端口管理复杂
LoadBalancer 云环境(AWS、GCP、Azure) 自动分配公网 IP,成本较高
Ingress / OpenShift Route 基于 HTTP 路由 Kafka 使用 TCP,需配合 NGINX TCP 代理或 OpenShift
Cluster-IP 仅集群内部访问 默认模式

在生产环境,推荐使用 LoadBalancer 或 NodePort + 外部负载均衡器。

4.2 使用 TLS 加密与认证

在 listeners 中配置 TLS,并通过 KafkaUser 创建客户端证书。

创建 KafkaUser 示例:

yaml

apiVersion: kafka.strimzi.io/v1beta2
kind: KafkaUser
metadata:
name: producer-consumer-user
namespace: kafka
labels:
strimzi.io/cluster: kafka-cluster
spec:
authentication:
type: tls
authorization:
type: simple
acls:
– resource:
type: topic
name: "*"
patternType: literal
operation: All
host: "*"
– resource:
type: group
name: "*"
patternType: literal
operation: All
host: "*"

生成后,Strimzi 会自动创建 Secret 包含客户端证书:

bash

kubectl get secret producer-consumer-user -n kafka -o jsonpath='{.data.user\\.p12}' | base64 -d > user.p12

4.3 外部客户端连接配置

以 TLS 认证的外部监听为例,客户端配置需包含:

properties

bootstrap.servers=<NodeIP>:30094,<NodeIP2>:30094,…
security.protocol=SSL
ssl.truststore.location=/path/to/ca.p12
ssl.truststore.password=<password>
ssl.keystore.location=/path/to/user.p12
ssl.keystore.password=<password>

其中 CA 证书可以从集群 Secret 中提取:

bash

kubectl get secret kafka-cluster-cluster-ca-cert -n kafka -o jsonpath='{.data.ca\\.p12}' | base64 -d > ca.p12


第五部分:高可用与容灾配置

5.1 Pod 反亲和性

在上面的 CR 中,我们通过 podAntiAffinity 强制要求 Kafka Broker Pod 分布在不同节点上,确保单个节点故障不会影响多个副本。

yaml

affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
– labelSelector:
matchExpressions:
– key: strimzi.io/cluster
operator: In
values:
– kafka-cluster
topologyKey: kubernetes.io/hostname

5.2 Pod 中断预算(PDB)

确保在自愿中断(如节点维护、滚动升级)时,至少有两个 Broker 保持可用:

yaml

podDisruptionBudget:
maxUnavailable: 1 # 或 minAvailable: 2

5.3 滚动升级策略

Strimzi Operator 在升级 Kafka 版本或修改配置时会自动执行滚动更新,遵循以下顺序:

  • 先更新 Controller 节点

  • 等待 Pod 就绪

  • 逐个更新 Broker

  • 确保 ISR 始终保持

  • 可以通过 spec.kafka.config 中的 role 配置影响升级顺序,但 KRaft 模式下无需特殊配置。

    5.4 数据持久化与备份

    • PV 回收策略:设置 deleteClaim: false,防止误删 PVC。

    • 定期快照:如果使用云存储,定期对 PV 做快照。

    • 跨集群镜像:使用 MirrorMaker 2 实现跨数据中心容灾。

    5.5 灾难恢复演练

    模拟一个 Broker 故障:

    bash

    # 删除一个 Pod
    kubectl delete pod kafka-cluster-kafka-1 -n kafka

    # 观察 Operator 自动重建
    kubectl get pod -w -n kafka

    验证在 Pod 重建期间,集群的可用性和数据完整性(可使用生产消费者压测)。


    第六部分:监控与告警

    6.1 部署 Prometheus 与 Grafana

    Strimzi 提供了详细的监控集成。首先,部署 Prometheus Operator 或直接部署 Prometheus。

    快速部署 Prometheus(使用 kube-prometheus-stack):

    bash

    helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
    helm install prometheus prometheus-community/kube-prometheus-stack -n monitoring –create-namespace

    6.2 配置 ServiceMonitor

    Strimzi Operator 会自动创建 ServiceMonitor 资源(如果 spec.kafka.metricsConfig 已配置)。检查 ServiceMonitor:

    bash

    kubectl get servicemonitor -n kafka

    如果有缺失,可以手动创建:

    yaml

    apiVersion: monitoring.coreos.com/v1
    kind: ServiceMonitor
    metadata:
    name: kafka-cluster
    namespace: kafka
    spec:
    selector:
    matchLabels:
    app.kubernetes.io/component: kafka
    app.kubernetes.io/instance: kafka-cluster
    app.kubernetes.io/name: kafka
    endpoints:
    – port: tcp-prometheus
    interval: 30s

    6.3 关键监控指标

    以下指标应重点监控:

    指标类别具体指标告警阈值
    集群状态 UnderReplicatedPartitions > 0
    Broker 健康 kafka_brokers 少于期望数量
    磁盘使用 kafka_log_log_size > 80%
    请求延迟 kafka_server_brokertopicmetrics_OneMinuteRate 根据业务设置
    ISR 收缩 kafka_controller_ShrinkingISRCount > 0

    6.4 Grafana 仪表盘

    导入 Strimzi 官方提供的 Grafana 仪表盘(ID:14077 或 14521),可直观展示集群状态、Topic 吞吐量、Broker 资源使用等。

    bash

    # 访问 Grafana(如果使用 kube-prometheus-stack,默认密码获取)
    kubectl get secret prometheus-grafana -n monitoring -o jsonpath='{.data.admin-password}' | base64 -d
    kubectl port-forward svc/prometheus-grafana 3000:80 -n monitoring


    第七部分:生产环境最佳实践

    7.1 资源配置与调优

    • 内存:JVM 堆内存建议 4-8GB,预留系统内存用于页缓存(Kafka 严重依赖 OS 缓存)。

    • CPU:根据吞吐量调整 num.network.threads 和 num.io.threads,一般设置为 CPU 核数。

    • 磁盘:挂载独立的数据盘,使用 SSD,并配置 log.dirs 为多路径(如果有多块盘)。

    • 网络:为 Kafka Pod 预留足够的带宽,避免网络限流。

    7.2 存储规划

    • PV 大小:根据数据保留时间计算,例如 1TB/天 * 7 天 = 7TB,并考虑副本因子(3 副本则总存储 21TB)。

    • 本地存储方案:若对 IO 延迟极度敏感,使用 Local PV 并绑定节点,但牺牲了自动漂移能力。Strimzi 支持 storage: type: persistent-claim 和 overrides 来为每个节点指定存储类。

    7.3 滚动升级与版本管理

    在升级 Kafka 版本时,遵循 Strimzi 官方支持的版本路线。修改 spec.kafka.version 后,Operator 会自动执行滚动升级。确保先备份元数据,并在升级前进行负载验证。

    7.4 安全加固

    • 网络隔离:使用 NetworkPolicy 限制只有指定的应用可以访问 Kafka。

    • RBAC:严格控制对 Kafka CR 的访问权限。

    • 证书轮换:Strimzi 支持自动轮换集群和客户端证书,在 Kafka 资源中设置 clusterCaCert 和 clientsCaCert 的 renewalDays。

    yaml

    spec:
    clusterCa:
    renewalDays: 30
    validityDays: 365
    clientsCa:
    renewalDays: 30
    validityDays: 365

    7.5 备份与恢复策略

    • 元数据备份:定期导出 Topic 配置(kafka-topics –describe)和 ACL 规则。

    • 数据备份:使用 Kafka MirrorMaker 2 同步数据到灾备集群。

    • 全量恢复:从云存储快照恢复 PV,重新挂载到新 Pod。


    第八部分:常见问题排查

    8.1 Pod 启动失败:PVC 无法绑定

    • 现象:Pod 处于 Pending,事件显示 waiting for a volume to be created

    • 原因:StorageClass 配置不正确或 volumeBindingMode 为 WaitForFirstConsumer 时调度器未选择节点

    • 解决:检查 StorageClass 是否支持动态供应,或手动创建 PV。

    8.2 Broker 无法加入集群

    • 现象:Pod 日志显示 Fenced broker 或 Metadata mismatch

    • 原因:KRaft 模式下,metadataVersion 与版本不匹配,或节点 ID 冲突

    • 解决:确认 spec.kafka.metadataVersion 与 Kafka 版本兼容,并清理旧的 PVC 数据(生产环境需谨慎)。

    8.3 外部连接失败

    • 现象:客户端超时或 SSL 握手失败

    • 原因:NodePort 未开放防火墙规则,或 TLS 证书配置不正确

    • 解决:检查安全组规则,确认客户端信任的 CA 与集群 CA 一致。

    8.4 ISR 收缩报警

    • 现象:kafka_controller_ShrinkingISRCount 大于 0

    • 原因:某个 Broker 负载过高或网络延迟导致副本同步落后

    • 解决:检查该 Broker 的资源使用情况,考虑增加 CPU/内存,或调整 replica.lag.time.max.ms。


    第九部分:总结与展望

    通过本文的讲解,我们系统性地完成了在 Kubernetes 上部署 Kafka 高可用集群的整个过程:

  • 理论基础:理解了 Kafka 高可用原理和 KRaft 模式的演进。

  • Operator 选择:使用 Strimzi 实现声明式管理。

  • 生产级配置:完成了 3 节点 KRaft 集群部署,配置了存储、网络、资源限制和反亲和性。

  • 安全与访问:实现了 TLS 加密认证和外部访问。

  • 监控运维:集成了 Prometheus/Grafana,设定了关键告警。

  • 最佳实践:涵盖了资源调优、存储规划、备份恢复等生产要点。

  • 未来演进方向:

    • 多集群联邦:使用 MirrorMaker 2 实现跨云或跨地域数据同步。

    • Serverless Kafka:关注 Kubernetes 上的 Serverless 消息队列(如 Knative + Kafka)。

    • 智能化运维:利用 AI 对 Kafka 指标进行异常检测和容量预测。

    生产环境部署 Kafka 是一项系统工程,需要结合业务流量、SLA 要求和基础设施环境不断优化。建议在投入生产前,进行充分的压力测试和故障演练,确保集群在各种故障场景下都能保持高可用性。


    附录:参考资源

    • Strimzi 官方文档

    • Kafka KRaft 官方指南

    • Kafka 性能调优指南

    • Kubernetes 本地持久化存储

    命令速查

    bash

    # 查看集群状态
    kubectl get kafka -n kafka
    # 查看 Broker 日志
    kubectl logs -f kafka-cluster-kafka-0 -n kafka
    # 创建 Topic
    kubectl apply -f topic.yaml
    # 列出 Topics
    kubectl exec -it kafka-cluster-kafka-0 -n kafka — bin/kafka-topics.sh –list –bootstrap-server localhost:9092
    # 查看消费者组
    kubectl exec -it kafka-cluster-kafka-0 -n kafka — bin/kafka-consumer-groups.sh –list –bootstrap-server localhost:9092

    赞(0)
    未经允许不得转载:171主机测评 » 在k8s中部署Kafka高可用集群超详细讲解
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址