MongoDB 高可用集群部署
一、方案概述
1.1 目标
在 K8s 高可用集群上,部署一套 MongoDB 高可用集群,具备:
- 高可用:3 数据节点副本集,容忍 1 个节点故障
- 自动故障转移:主节点故障时,从节点自动提升为主
- 仲裁节点:避免偶数节点脑裂
- 持久化:每个节点独立 PVC,数据落盘
- 外部访问:Ingress + HTTPS(可选)
1.2 技术选型
| 组件 | 用途 |
|---|---|
| Bitnami MongoDB Helm Chart | 部署 MongoDB 副本集 |
| StatefulSet | 管理 MongoDB Pod |
| PersistentVolumeClaim | 每个节点的持久化存储 |
| Longhorn | 分布式存储 |
| MongoDB Replica Set | 副本集高可用 |
1.3 架构
应用 ↓ Service: mongodb.mongodb.svc.cluster.local:27017 ↓ MongoDB Replica Set (3 数据节点 + 1 仲裁) ├── mongodb-0 (PRIMARY) ├── mongodb-1 (SECONDARY) ├── mongodb-2 (SECONDARY) └── mongodb-arbiter-0 (ARBITER) ↓ PersistentVolume (longhorn)二、前置条件
2.1 集群状态
- K8s 集群
kubectl get nodes全部Ready - Longhorn 已部署,
longhornStorageClass 就绪 - 节点数量≥ 3(保证副本集能选举)
2.2 存储要求
MongoDB 需要 PVC 持久化数据。必须提前配好 StorageClass。
kubectl get storageclass这命令看 StorageClass 列表,预期看到longhorn。
2.3 Longhorn 存储设置
这是关键步骤,不改的话,Longhorn 会因为“空间不足”拒绝调度副本。
kubectl patch settings.longhorn.io storage-over-provisioning-percentage -n longhorn-system --type=merge -p '{"value":"200"}'这条命令允许 Longhorn 超配到磁盘总容量的 200%。
kubectl patch settings.longhorn.io storage-minimal-available-percentage -n longhorn-system --type=merge -p '{"value":"10"}'这条命令把最小可用空间从 25% 降到 10%。
2.4 镜像网络要求
MongoDB 的镜像在registry-1.docker.io/bitnami/mongodb上。Bitnami 从 2025 年 8 月 28 日起移除了 Docker Hub 公共目录的免费镜像,直接拉会返回 403。
解决方案:用bitnami/mongodb:latest标签,DaoCloud 代理可用。
ansible k8s_cluster -i inventory.ini -m shell -a "crictl pull docker.m.daocloud.io/bitnami/mongodb:latest" -b这条命令在所有节点上从 DaoCloud 代理拉bitnami/mongodb:latest。
ansible k8s_cluster -i inventory.ini -m shell -a "ctr -n k8s.io images tag docker.m.daocloud.io/bitnami/mongodb:latest registry-1.docker.io/bitnami/mongodb:latest" -b这条命令给镜像打标签,让 containerd 认为本地有registry-1.docker.io/bitnami/mongodb:latest。
三、下载 MongoDB Chart
3.1 从 DaoCloud 拉取
不能用helm repo add bitnami,因为 Bitnami 的 chart 走 Docker Hub OCI,国内不通。
helm pull oci://docker.m.daocloud.io/bitnamicharts/mongodb --version 19.3.0这条命令从 DaoCloud 代理拉 MongoDB chart。
预期输出:
Pulled: docker.m.daocloud.io/bitnamicharts/mongodb:19.3.0 Digest: sha256:fe65e88b838f225d13a1df988e323d47715c7c85f14863f5b05837c12ceed000下载后本地会有:mongodb-19.3.0.tgz
四、部署 MongoDB
4.1 生成密码和密钥
openssl rand -base64 24这条命令生成一个随机密码,执行两次,分别得到 root 密码和副本集密钥。
把两次输出保存下来。
4.2 安装 MongoDB
helm install mongodb ./mongodb-19.3.0.tgz \ --namespace mongodb \ --create-namespace \ --set architecture=replicaset \ --set replicaCount=3 \ --set auth.rootPassword=<root密码> \ --set auth.replicaSetKey=<副本集密钥> \ --set persistence.storageClass=longhorn \ --set persistence.size=10Gi这条命令用本地 chart 安装 MongoDB 副本集。
逐项解析:
| 参数 | 含义 |
|---|---|
mongodb | release 名 |
./mongodb-19.3.0.tgz | 本地 chart 包 |
--namespace mongodb | 装到 mongodb 命名空间 |
--create-namespace | 自动创建命名空间 |
architecture=replicaset | 副本集模式 |
replicaCount=3 | 3 个数据节点 |
auth.rootPassword | root 密码 |
auth.replicaSetKey | 副本集内部认证密钥 |
persistence.storageClass=longhorn | 用 Longhorn 存储 |
persistence.size=10Gi | 每个节点 10Gi |
4.3 观察 Pod 启动
kubectl get pods -n mongodb -w这条命令观察 Pod 启动,按Ctrl+C退出。
预期:
mongodb-0 1/1 Running mongodb-1 1/1 Running mongodb-2 1/1 Running mongodb-arbiter-0 1/1 Running注意:chart 会自动加一个arbiter节点,用于投票,不存数据。
五、验证 MongoDB
5.1 查看 Pod 和 PVC
kubectl get pods -n mongodb kubectl get pvc -n mongodb这两条命令看 Pod 和 PVC 状态。
预期:
- 4 个 Pod 全部
Running。 - PVC 全部
Bound,STORAGECLASS是longhorn。
5.2 查看副本集状态
kubectl exec -it -n mongodb mongodb-0 -- mongosh -u root -p <root密码> --authenticationDatabase admin --eval "rs.status()"这条命令查看副本集状态。
预期:
- 1 个
PRIMARY - 2 个
SECONDARY - 1 个
ARBITER - 所有成员
health: 1
5.3 测试读写
kubectl exec -it -n mongodb mongodb-0 -- mongosh -u root -p <root密码> --authenticationDatabase admin --eval "db.test.insertOne({name: 'hello'})"这条命令插入一条测试数据。
kubectl exec -it -n mongodb mongodb-0 -- mongosh -u root -p <root密码> --authenticationDatabase admin --eval "db.test.find()"这条命令查询数据,预期返回刚才插入的记录。
六、应用接入
6.1 连接信息
在集群内部:
| 用途 | 地址 |
|---|---|
| MongoDB | mongodb.mongodb.svc.cluster.local:27017 |
简写(同命名空间):
mongodb:27017跨命名空间:
mongodb.mongodb.svc.cluster.local:27017用户名:root
密码:从 Secret 取。
6.2 取密码
kubectl get secret -n mongodb mongodb -o jsonpath='{.data.mongodb-root-password}' | base64 -d echo这条命令从 Secret 取 root 密码。
6.3 应用配置示例
Python (pymongo):
from pymongo import MongoClient client = MongoClient( 'mongodb://root:<密码>@mongodb.mongodb.svc.cluster.local:27017/?replicaSet=rs0&authSource=admin' )Node.js (mongodb):
const { MongoClient } = require('mongodb'); const client = new MongoClient( 'mongodb://root:<密码>@mongodb.mongodb.svc.cluster.local:27017/?replicaSet=rs0&authSource=admin' );Java (mongodb-driver):
MongoClient client = MongoClients.create( "mongodb://root:<密码>@mongodb.mongodb.svc.cluster.local:27017/?replicaSet=rs0&authSource=admin" );Go (mongo-go-driver):
client, err := mongo.Connect(context.TODO(), options.Client().ApplyURI( "mongodb://root:<密码>@mongodb.mongodb.svc.cluster.local:27017/?replicaSet=rs0&authSource=admin", ))6.4 部署后端服务到 K8s
apiVersion: apps/v1 kind: Deployment metadata: name: my-backend namespace: default spec: replicas: 2 selector: matchLabels: app: my-backend template: metadata: labels: app: my-backend spec: containers: - name: my-backend image: my-backend:latest ports: - containerPort: 8080 env: - name: MONGODB_HOST value: "mongodb.mongodb.svc.cluster.local" - name: MONGODB_PORT value: "27017" - name: MONGODB_USER value: "root" - name: MONGODB_PASSWORD valueFrom: secretKeyRef: name: mongodb key: mongodb-root-password七、常见问题
7.1 Pod 卡在ImagePullBackOff
原因:MongoDB 镜像在registry-1.docker.io上,国内拉取超时。
解决:
ansible k8s_cluster -i inventory.ini -m shell -a "crictl pull docker.m.daocloud.io/bitnami/mongodb:latest" -b ansible k8s_cluster -i inventory.ini -m shell -a "ctr -n k8s.io images tag docker.m.daocloud.io/bitnami/mongodb:latest registry-1.docker.io/bitnami/mongodb:latest" -b kubectl delete pod -n mongodb --all7.2 Bitnami 镜像 403
原因:Bitnami 从 2025 年 8 月 28 日起移除了 Docker Hub 公共目录的免费镜像。
解决:用bitnami/mongodb:latest标签,DaoCloud 代理可用。
7.3 PVC 绑不上
原因:Longhorn 卷调度失败。
排查:
kubectl get volumes.longhorn.io -n longhorn-system kubectl get volume.longhorn.io <volume-name> -n longhorn-system -o yaml | grep -A5 "type: Scheduled"如果报insufficient storage:
kubectl patch settings.longhorn.io storage-over-provisioning-percentage -n longhorn-system --type=merge -p '{"value":"200"}' kubectl patch settings.longhorn.io storage-minimal-available-percentage -n longhorn-system --type=merge -p '{"value":"10"}'7.4 副本集PRIMARY选举失败
原因:节点不够,或网络不通。
排查:
kubectl logs -n mongodb mongodb-0 --tail=50关注:
election failednot enough healthy nodes
7.5 写操作失败
原因:没有PRIMARY,或多数派不可用。
排查:
kubectl exec -it -n mongodb mongodb-0 -- mongosh -u root -p <密码> --authenticationDatabase admin --eval "rs.status()"如果所有节点都是SECONDARY,说明选举失败。
八、常用操作
8.1 查看 MongoDB 状态
kubectl get pods -n mongodb kubectl get pvc -n mongodb kubectl get svc -n mongodb8.2 查看日志
kubectl logs -n mongodb mongodb-0 --tail=1008.3 连接 MongoDB
kubectl exec -it -n mongodb mongodb-0 -- mongosh -u root -p <密码> --authenticationDatabase admin8.4 扩容
helm upgrade mongodb ./mongodb-19.3.0.tgz \ --namespace mongodb \ --set replicaCount=5这条命令把副本集从 3 节点扩到 5 节点。
8.5 删除 MongoDB
helm uninstall mongodb -n mongodb kubectl delete pvc -n mongodb --all kubectl delete namespace mongodb警告:删除 PVC 会删除所有数据,操作前先备份。
九、架构总结
9.1 组件清单
| 组件 | 数量 | 作用 |
|---|---|---|
| mongodb | 3 | 数据节点,1 主 2 从 |
| mongodb-arbiter | 1 | 仲裁节点,不存数据,只投票 |
| StatefulSet | 1 | 管理 MongoDB Pod |
| PVC | 3 | 每个数据节点一块存储 |
| Service | 2 | 集群内部通信和客户端入口 |
| Secret | 1 | root 密码 |
9.2 端口速查
| 端口 | 用途 |
|---|---|
| 27017 | MongoDB 客户端连接 |
| 27018 | MongoDB 内部通信 |
9.3 高可用机制
| 故障场景 | 影响 | 恢复方式 |
|---|---|---|
| 从节点故障 | 无影响 | 主节点继续服务,从节点重建后重新同步 |
| 主节点故障 | 短暂不可写 | 从节点自动选举为新主,10-30 秒恢复 |
| 仲裁节点故障 | 无影响 | 只影响选举,不影响读写 |
| 多个节点故障 | 可能不可写 | 如果超过半数节点故障,副本集停止服务 |
9.4 已知隐患
| 隐患 | 影响 | 解决方案 |
|---|---|---|
| Longhorn 空间调度保守 | 卷报insufficient storage | 改 over-provisioning 和 minimal-available |
| Bitnami 免费镜像移除 | 无法拉取最新镜像 | 用bitnami/mongodb:latest |
| registry-1.docker.io 超时 | 镜像拉不下来 | 用 DaoCloud 代理拉并打标签 |
| 未配备份 | 数据无法恢复 | 用 mongodump 定期备份 |
十、总结
这套 MongoDB 基于 Bitnami Helm Chart 部署,提供了:
- 高可用:3 数据节点副本集 + 1 仲裁节点,容忍 1 个节点故障
- 自动故障转移:主节点故障时,从节点自动提升
- 持久化:每个数据节点独立 PVC
- 声明式管理:Helm chart 一条命令部署
部署中最容易踩的坑:
- Bitnami 免费镜像移除:必须用
bitnami/mongodb:latest标签。 - registry-1.docker.io 超时:必须配 DaoCloud 代理拉镜像并打标签。
- Longhorn 空间调度保守:改
storage-over-provisioning-percentage=200和storage-minimal-available-percentage=10。 - chart 拉取超时:用 DaoCloud 的 OCI 代理。
解决了这四个问题,MongoDB 就能稳定运行。