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

201 lines
6.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
tags:
- MQ
- Kubernetes
- 容器化
- 运维
create time: 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 重建后自动挂载原来的卷
```yaml
# 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 权限
```yaml
# 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 集群的完整部署架构如下:
```mermaid
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,核心优势是参数化配置和环境隔离:
```bash
# 安装 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 |
## 关联笔记
- [[40-MQ-性能调优]]
- [[42-MQ-认证与授权]]
- [[43-MQ-加密与审计]]