Files
cs-note/hhs/MQ/10-监控与运维/39-MQ-容器化与-K8s-部署.md
T
2026-05-24 20:51:06 +08:00

6.8 KiB
Raw Blame History

tags, create time
tags create time
MQ
Kubernetes
容器化
运维
2026-05-24 19:52

MQ 容器化与 K8s 部署

概述

将消息队列部署到 Kubernetes 上,是有状态服务容器化的核心挑战之一。本文从持久存储、网络标识、有序部署三个维度分析难点,介绍 StatefulSet、Operator 模式、Helm Chart 等主流方案,并以 Strimzi Kafka Operator 为例展示生产级部署实践。

正文

为什么 MQ 上 K8s 是个难题

Kubernetes 天生为无状态服务设计——Pod 可以随时被杀掉重建、IP 随时变化、多个副本之间没有区别。但 MQ 作为有状态服务,恰恰对这三点都很敏感:

  • 持久存储:消息必须落盘,Pod 重建后数据不能丢
  • 网络标识:Broker 之间需要通过固定地址互相发现(如 Kafka 的 broker.id 对应固定端点)
  • 有序部署:集群启动/扩容时需要按顺序进行,不能所有 Pod 同时拉起

[!question] 想象一下 Kafka 的 3 个 Broker 同时启动并互相注册,会发生什么?为什么有序启动很重要?

StatefulSet:有状态应用的基石

StatefulSet 是 K8s 专门为有状态服务设计的控制器,解决了 Deployment 的两个核心问题:

  1. 稳定的网络标识:每个 Pod 拥有固定名称(kafka-0、kafka-1、kafka-2),配合 Headless Service 可以通过 DNS 直接访问
  2. 稳定的持久存储:每个 Pod 绑定独立的 PVC(PersistentVolumeClaim),Pod 重建后自动挂载原来的卷
# StatefulSet 核心配置片段
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: kafka
spec:
  serviceName: kafka-headless  # 关联 Headless Service
  replicas: 3
  template:
    spec:
      containers:
        - name: kafka
          volumeMounts:
            - name: data
              mountPath: /var/lib/kafka/data
  volumeClaimTemplates:         # 每个 Pod 自动创建独立 PVC
    - metadata:
        name: data
      spec:
        accessModes: ["ReadWriteOnce"]
        storageClassName: fast-ssd
        resources:
          requests:
            storage: 100Gi

但 StatefulSet 只解决了基础设施层面的问题。什么时候该扩容、扩容后 Partition 怎么重分配、配置变更怎么滚动生效——这些业务运维知识它一概不管。于是 Operator 登场了。

Operator 模式:把运维知识编码

Operator = Custom Resource Definition(CRD)+ Custom Controller。核心思想是:将人类运维专家的知识编码为程序,让 K8s 自动执行运维操作。

对于 MQ 来说,Operator 能做到:

  • 一键部署完整集群(含 ZooKeeper/KRaft)
  • 滚动升级 Broker 版本(保证零停机)
  • 自动处理 Partition 重分配
  • 证书自动签发和轮转

主流 MQ Operator:

MQ Operator 维护方
Kafka Strimzi CNCF
RocketMQ rocketmq-operator Apache
RabbitMQ cluster-operator VMware
Pulsar pulsar-helm-chart Apache

Strimzi Kafka Operator 实战

Strimzi 是 CNCF 孵化项目,通过 CRD 将 Kafka 集群声明式管理。核心 CRD 有三个:

  • Kafka:定义 Kafka 集群拓扑(Broker 数量、存储、配置)
  • KafkaTopic:声明式管理 Topic
  • KafkaUser:声明式管理用户和 ACL 权限
# Strimzi Kafka CR 示例:3 节点集群
apiVersion: kafka.strimzi.io/v1beta2
kind: Kafka
metadata:
  name: my-cluster
spec:
  kafka:
    version: 3.7.0
    replicas: 3
    listeners:
      - name: plain
        port: 9092
        type: internal
        tls: false
      - name: tls
        port: 9093
        type: internal
        tls: true
    config:
      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
    storage:
      type: jbod
      volumes:
        - id: 0
          type: persistent-claim
          size: 100Gi
          class: fast-ssd
  zookeeper:
    replicas: 3
    storage:
      type: persistent-claim
      size: 20Gi

Kafka 集群的完整部署架构如下:

graph TB
    subgraph K8s["Kubernetes Cluster"]
        subgraph NS["namespace: kafka"]
            Operator["Strimzi Operator"]
            CR["Kafka CR"]
            Operator -->|"watch & reconcile"| CR
            CR -->|"create"| STS["StatefulSet"]
            STS -->|"manage"| Pod0["kafka-0"]
            STS -->|"manage"| Pod1["kafka-1"]
            STS -->|"manage"| Pod2["kafka-2"]
            Pod0 ---|"PVC"| PV0["PV-0 100Gi SSD"]
            Pod1 ---|"PVC"| PV1["PV-1 100Gi SSD"]
            Pod2 ---|"PVC"| PV2["PV-2 100Gi SSD"]
            HS["Headless Service"] -->|"DNS: kafka-0.kafka-headless"| Pod0
            HS -->|"DNS: kafka-1.kafka-headless"| Pod1
            HS -->|"DNS: kafka-2.kafka-headless"| Pod2
            LB["LoadBalancer Service"] -->|"external access"| Pod0
            LB --> Pod1
            LB --> Pod2
        end
    end
    Client["Client App"] -->|"produce/consume"| LB

Helm Chart 部署

对于不想引入 Operator 的轻量场景,Helm Chart 是更简单的选择。Bitnami 提供了完善的 Kafka Helm Chart,核心优势是参数化配置和环境隔离:

# 安装 Kafka 集群
helm install my-kafka bitnami/kafka \
  --namespace kafka --create-namespace \
  --set replicaCount=3 \
  --set persistence.size=100Gi \
  --set persistence.storageClass=fast-ssd \
  --set resources.requests.memory=4Gi \
  --set resources.requests.cpu=2 \
  --set resources.limits.memory=6Gi \
  --set resources.limits.cpu=4

Helm 适合快速搭建和开发/测试环境,但在生产环境中,Operator 的自动化运维能力(升级、扩容、故障恢复)是 Helm 无法替代的。

资源规划建议

MQ 在 K8s 上的资源规划需要特别注意:

  • CPU/Memory:Kafka Broker 建议至少 2C4G,生产环境推荐 4C8G。请求值和限制值都要设置,避免被驱逐或抢占资源
  • 存储:SSD 用于高吞吐场景(低延迟随机读写),HDD 用于大容量归档。通过 StorageClass 区分
  • JVM 堆:Kafka Broker 堆不宜过大(4-6GB 足够),留更多内存给页缓存。推荐 G1GC 或 ZGC
  • 磁盘调度:容器内使用 none(noop)调度算法,避免与宿主机调度冲突

网络方案

方式 适用场景 特点
Headless Service Broker 间内部通信 Pod 直连,无负载均衡
ClusterIP 集群内客户端访问 默认方式
NodePort 开发测试外部访问 端口范围 30000-32767
LoadBalancer 生产外部访问 云厂商 LB,费用较高
Ingress HTTP 协议暴露 MQ 一般不走 HTTP,适用 REST Proxy

关联笔记