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 集群链路 控制节点 inventory + group_vars Playbook + Jinja2模板 安装与配置阶段 解压 → 软链 → 建用户/目录 渲染 mongod.conf → systemd 按角色分叉 replset / shardsvr / configsvr / mongos 模板条件渲染,端口与bind_ip变量化 启动 mongod 进程 systemctl start mongod 启动 mongos / config server configsvr 先于 mongos 启动 副本集初始化 rs.initiate() rs.add() 逐台加入 run_once 仅主节点执行 分片集群初始化 初始化 config server 副本集 sh.addShard() 添加分片 sh.enableSharding() 启用分片 验证副本集状态 rs.status() 检查 PRIMARY rs.conf() 核对成员列表 验证分片集群状态 sh.status() 查看分片与均衡 db.printShardingStatus() 核对chunk 图例 安装/验证 副本集 分片角色 分片初始化

六、幂等性与验证要点

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 做干跑验证,再对生产环境执行。这样副本集与分片集群的部署过程就具备了版本可追溯、变更可回滚的工程能力。