使用MicroK8s与Bitnami Helm Chart部署的MongoDB副本集更新主节点时丢失数据库问题
这个问题我之前帮团队排查过,核心是两个关键因素叠加导致的:Bitnami MongoDB Helm Chart的默认优先级配置,加上你使用了节点本地存储导致mongo-0重启后数据为空。咱们一步步拆解:
核心原因分析
1. Bitnami Chart默认的副本集优先级设置
Bitnami的MongoDB Helm Chart为了保证mongo-0始终是主节点,默认给mongo-0设置了远高于其他节点的副本集优先级(通常是100,而mongo-1、mongo-2是50)。
MongoDB副本集的选举逻辑很直接:只要节点健康(能和集群通信),优先级更高的节点会被优先选为Primary,完全不检查节点的数据是否最新。当你的mongo-0在新节点启动后,虽然它的数据是空的,但它处于健康状态,会立刻发起选举。因为它的优先级比当前主节点mongo-1高,其他节点会投票给它,导致它直接成为新的Primary。
2. 节点本地存储导致mongo-0数据丢失
你提到新节点的/mnt/mongo路径为空,这说明你用了hostPath这类节点本地存储。这种存储的特点是数据绑定在单个节点上,当Pod被调度到新节点时,新节点的对应路径没有原有数据,mongo-0启动后就是一个空实例。
3. 初始同步被选举打断
正常情况下,空节点加入副本集后会作为Secondary从Primary同步所有数据,但这个过程需要时间(取决于数据量大小)。但因为mongo-0的优先级太高,在同步完成前就已经成为Primary了——而MongoDB的Primary节点不会从其他节点同步数据,只有Secondary才会同步。这时候空的mongo-0作为Primary,其他节点反而会从它同步空数据,最终整个集群数据丢失。
解决方案
1. 统一所有节点的副本集优先级
修改Bitnami Chart的配置,让所有节点的优先级一致,这样mongo-0重启后不会直接抢主,而是先作为Secondary同步数据,等数据追上后再参与选举。
方式一:修改values.yaml后重新部署
replicaSet: enabled: true priority: mongo-0: 50 mongo-1: 50 mongo-2: 50
方式二:直接用helm upgrade调整
helm upgrade mongodb bitnami/mongodb --set replicaSet.priority.mongo-0=50 --set replicaSet.priority.mongo-1=50 --set replicaSet.priority.mongo-2=50
2. 使用跨节点的持久化存储
放弃hostPath这类节点本地存储,改用MicroK8s支持的分布式存储方案,比如:
- 启用MicroK8s内置的OpenEBS:
microk8s enable openebs,然后用OpenEBS的存储类创建PV - 使用NFS类型的PersistentVolume,确保数据可以跨节点访问
这样当Pod调度到新节点时,PV会跟着绑定,mongo-0启动时会加载原有数据,不会出现空实例的情况。
3. 延长选举超时时间(可选)
如果需要保留mongo-0的高优先级,可以调整MongoDB的electionTimeoutMillis参数,延长选举等待时间,给空节点足够的时间完成初始同步再参与选举。
在Chart中添加如下配置:
mongodb: extraEnvVars: - name: MONGODB_EXTRA_FLAGS value: "--electionTimeoutMillis 30000"
将选举超时从默认的10秒改为30秒(可根据数据量调整),给空节点更多同步时间。
4. 维护时的手动干预(临时方案)
如果正在进行节点维护,可以先临时调低mongo-0的优先级,等它同步完成后再恢复:
- 进入当前主节点(比如mongo-1)的shell:
kubectl exec -it mongodb-1 -- mongosh - 修改副本集配置,调低mongo-0的优先级:
cfg = rs.conf() cfg.members[0].priority = 10 rs.reconfig(cfg) - 等待mongo-0同步完成(用
rs.status()查看syncingTo字段和optimeDate是否和主节点一致) - 恢复mongo-0的优先级:
cfg = rs.conf() cfg.members[0].priority = 100 rs.reconfig(cfg)
内容的提问来源于stack exchange,提问作者FCR

