可行,但必须绕开systemd重载、初始化时序和端口/目录隔离三类坑,否则第三节点易卡住或初始化失败。

直接上结论:用 Shell 脚本部署 MongoDB 副本集可行,但必须绕开 systemd 服务自动重载、副本集初始化时序、以及 mongod 进程间端口/数据目录隔离这三类坑——否则脚本大概率在第三台节点上卡住或初始化失败。
为什么不能直接套用单机安装脚本跑多实例
单机部署脚本通常只起一个 mongod,而副本集至少要三个独立实例;它们必须共存于同一台机器(测试环境)或跨机器(生产),但共享内核参数、/tmp、SELinux 策略和 ulimit。常见错误现象包括:
-
Address already in use—— 多个实例绑定相同端口或未清空/tmp/mongodb-*.sock -
child process failed, exited with error number 100——dbPath权限不对,或storage.journal.enabled: true但磁盘无写权限 - 副本集初始化后只有 PRIMARY,其余节点状态为
STARTUP2卡住 ——host字段写成localhost,导致其他成员无法反向连接
实操建议:mongod 实例必须用绝对路径启动,每个实例配独立 pidFilePath、dbPath、logPath 和 port;配置文件里 replication.replSetName 统一,但 net.bindIp 设为 0.0.0.0(或具体网卡 IP),绝不用 127.0.0.1 或 localhost。
如何让 initReplSet 自动成功不卡住
关键不是“执行 rs.initiate()”,而是确保所有节点在执行前已就绪且可互相发现。手动操作时容易忽略的检查点,在脚本里必须显式等待:
- 用
curl -s http://$HOST:$PORT/?serverStatus=1或mongosh --eval "db.runCommand({ping:1})" --host $HOST --port $PORT --quiet验证每个mongod已响应 - 用
ss -tln | grep :$PORT确认端口已 LISTEN,而非 TIME_WAIT 或 CLOSE_WAIT - 初始化命令必须由 PRIMARY 节点发起,且传入完整成员数组:
rs.initiate({ _id: "rs0", members: [ { _id: 0, host: "192.168.1.10:27017" }, { _id: 1, host: "192.168.1.11:27017" }, { _id: 2, host: "192.168.1.12:27017" } ] })
别用 rs.add() 分步加节点——它依赖已有 PRIMARY 在线,而刚启动的集群没有 PRIMARY,会报 not master。必须一步 initiate 全量定义。
如何避免 systemd 重启后副本集状态丢失
很多脚本用 systemctl start mongod 启动,但默认 unit 文件没设 Restart=always 且没等副本集 ready 就返回,导致服务看似运行,rs.status() 却是空的。更糟的是,重启后 mongod 恢复为 standalone 模式。
- 修改
/etc/systemd/system/mongod@.service(带实例名模板),启用Restart=on-failure和RestartSec=10 - 在
ExecStartPost=加钩子:调用mongosh --eval "rs.status()" --host 127.0.0.1 --port %i | grep -q \"ok.*1\",失败则重试或退出 - 禁止用
mongod --replSet命令行参数启动 —— systemd 无法持久化该参数,应统一走config file,并在其中写死replication.replSetName
真正稳定的方案是:每个实例有独立 service unit(如 mongod-27017.service),配置文件里明确 storage.dbPath 和 replication.replSetName,且首次启动后不再依赖脚本干预副本集状态。
最易被忽略的一点:MongoDB 6.0+ 默认启用 featureCompatibilityVersion: "6.0",如果脚本里混用 5.0 和 6.0 的二进制或配置项(比如误写 security.authorization: enabled 而非 security.authorization: "enabled"),整个副本集会拒绝选举。版本对齐和配置语法校验,比写循环启动逻辑重要得多。











