3. 自动化部署基础
当MongoDB节点数量从3台增长到30台,手工登录逐台安装的方式就会迅速失控:版本不一致、目录权限不同、副本集配置参数写错一位、分片集群里某台config server忘记启动,都会让后续排障成本成倍上升。Ansible的价值在于把“安装MongoDB”这件事从一次性操作变成可重复执行的代码,让副本集与分片集群的部署过程具备幂等性和可审计性。
一、标准化部署的核心对象与目录约定
在编写Playbook之前,先固定一套目录与命名约定,这是后续所有模板、变量和初始化脚本的基础。以下约定属于教学示例,实际项目中可按团队规范调整:
- 安装包:
mongodb-linux-x86_64-enterprise-7.0.5.tgz,统一放在控制节点的files/目录。 - 安装路径:
/opt/mongodb/7.0.5,通过软链接/opt/mongodb/current指向当前版本,便于滚动升级。 - 数据目录:
/data/mongodb/{db,log},属主为mongod:mongod。 - 配置文件:
/etc/mongod.conf,由Jinja2模板根据主机角色渲染。 - 角色划分:
mongos、config、shard、repl四类,通过 inventory 分组区分。
副本集与分片集群共用同一套安装逻辑,差异只体现在配置模板和初始化任务上。这种“安装统一、配置分叉”的结构,是Ansible部署MongoDB时最值得坚持的设计。
二、Inventory分组与变量设计
Inventory是Ansible描述集群拓扑的地方。以三节点副本集加两分片集群为例,可以这样组织:
[repl]
mongo-repl-01 ansible_host=10.0.1.11
mongo-repl-02 ansible_host=10.0.1.12
mongo-repl-03 ansible_host=10.0.1.13
[shard]
mongo-shard-01 ansible_host=10.0.2.11 shard_name=shard1
mongo-shard-02 ansible_host=10.0.2.12 shard_name=shard1
mongo-shard-03 ansible_host=10.0.2.13 shard_name=shard2
[config]
mongo-cfg-01 ansible_host=10.0.3.11
mongo-cfg-02 ansible_host=10.0.3.12
mongo-cfg-03 ansible_host=10.0.3.13
[mongos]
mongo-mongos-01 ansible_host=10.0.4.11
[repl:vars]
mongo_role=replset
replset_name=rs0
[shard:vars]
mongo_role=shardsvr
[config:vars]
mongo_role=configsvr
config_replset_name=cfgRepl
[mongos:vars]
mongo_role=mongos
关键变量包括 mongo_role、replset_name、shard_name、bind_ip、port。把这些变量集中放在 group_vars/all.yml 中,模板里只引用变量,不写死IP和端口,才能保证同一套Playbook复用到不同环境。
三、安装与配置模板
安装任务本身并不复杂,核心是解压、建软链、创建用户和目录、渲染配置、注册systemd服务。下面是一个精简后的任务片段:
- name: 创建mongod用户
user:
name: mongod
system: yes
shell: /sbin/nologin
- name: 解压MongoDB安装包
unarchive:
src: files/mongodb-linux-x86_64-enterprise-7.0.5.tgz
dest: /opt/mongodb/
remote_src: no
- name: 建立current软链接
file:
src: /opt/mongodb/mongodb-linux-x86_64-enterprise-7.0.5
dest: /opt/mongodb/current
state: link
- name: 渲染mongod.conf
template:
src: mongod.conf.j2
dest: /etc/mongod.conf
mode: '0644'
notify: restart mongod
配置模板 mongod.conf.j2 根据 mongo_role 分支渲染。副本集节点需要 replication.replSetName,分片节点需要 sharding.clusterRole: shardsvr,config server 需要 sharding.clusterRole: configsvr 并开启副本集。模板中通过 {% if mongo_role == 'replset' %} 这类条件块实现差异化,避免维护多份配置文件。
四、初始化:从进程启动到集群成型
安装完成只是第一步,真正的“初始化”是把独立进程组织成副本集和分片集群。这一步必须用 mongosh 或 mongo 执行管理命令,且要处理“先启动、再初始化、最后验证”的顺序。
副本集初始化流程:先启动所有节点的mongod,然后在主节点执行 rs.initiate(),再通过 rs.add() 加入其余成员。Ansible中可以用 shell 模块配合 when 条件,只在第一个节点执行初始化:
- name: 初始化副本集
shell: |
mongosh --port 27017 --eval '
rs.initiate({_id:"rs0",members:[
{_id:0,host:"10.0.1.11:27017"},
{_id:1,host:"10.0.1.12:27017"},
{_id:2,host:"10.0.1.13:27017"}]})'
when: inventory_hostname == "mongo-repl-01"
run_once: true
分片集群初始化更复杂:先初始化config server副本集,再启动mongos并添加分片,最后对数据库启用分片。顺序不能颠倒,否则mongos无法连接config server。典型命令包括 sh.addShard("shard1/10.0.2.11:27017,10.0.2.12:27017") 和 sh.enableSharding("appdb")。
五、部署流程与状态流转
下图展示了从控制节点到目标集群的标准化部署链路,以及副本集与分片集群在初始化阶段的分叉关系。图中同时标出了每一步的关键判断点,便于理解Ansible任务之间的依赖。
六、幂等性与验证要点
Ansible部署MongoDB最容易踩的坑是“重复执行导致重复初始化”。rs.initiate() 在已初始化的副本集上执行会报错,因此必须用 run_once 配合条件判断,或者先查询 rs.status() 的 ok 字段再决定是否执行。更稳妥的做法是把初始化脚本写成“先检查、后执行”的形式:
- name: 检查副本集是否已初始化
shell: mongosh --quiet --eval 'rs.status().ok' || echo "0"
register: rs_check
changed_when: false
- name: 初始化副本集
shell: mongosh --eval 'rs.initiate({...})'
when: rs_check.stdout | trim != "1"
验证阶段要关注三个层面:进程是否存活(systemctl status mongod)、副本集是否选出PRIMARY(rs.status() 中 stateStr 为 PRIMARY)、分片集群是否所有分片可见(sh.status() 中 shards 数组长度与预期一致)。只有这三层都通过,才能认为标准化部署真正完成。
mongod.conf.j2、inventory模板和初始化脚本一起纳入Git管理,每次变更通过CI触发 ansible-playbook --check 做干跑验证,再对生产环境执行。这样副本集与分片集群的部署过程就具备了版本可追溯、变更可回滚的工程能力。