在配置管理体系中,MongoDB的安装和副本集初始化经常被当作一次性手工操作,但当节点扩容、参数调整或安全加固频繁出现时,这种做法会带来大量重复劳动。mongodb-chef-cookbook把安装包源、MongoDB版本、端口、数据目录、日志路径、副本集名称以及认证参数等全部抽象为attribute,再通过recipe转换成包安装、模板渲染和服务管理动作。一个最小化的部署流程可以在几分钟内把裸机变成可用的MongoDB节点。

环境准备与依赖管理
使用mongodb-chef-cookbook前,要先解决依赖获取和版本锁定问题。Chef社区同时存在多个与MongoDB相关的cookbook,命名相近但行为差异很大。在Berksfile中显式声明源和版本,可以避免上游意外升级带来配置不兼容。对于企业内网环境,可以把源替换成私有Supermarket地址,但依赖声明方式不变。
source 'https://supermarket.chef.io' cookbook 'mongodb-chef-cookbook', '~> 3.2.0'
运行berks install会生成锁定文件,运行berks upload则会把cookbook上传到Chef Server。已经使用Policyfile的团队可以在Policyfile.rb中采用同样的版本约束。固定版本并不是保守,而是让MongoDB的变更窗口可控,尤其是主版本升级涉及存储引擎或配置语法变化时,版本约束可以避免自动拉取新版本造成的意外。
接着在封装业务应用的cookbook中声明依赖,确保Chef运行时会自动加载mongodb-chef-cookbook。
name 'my_application' version '0.1.0' depends 'mongodb-chef-cookbook', '~> 3.2.0'
依赖声明之后,业务cookbook可以通过include_recipe引用MongoDB recipe。建议使用environment或role隔离开发、测试和生产,避免在开发节点误装生产版本,也便于在不同环境覆盖端口和存储路径。
核心属性与配置模板
mongodb-chef-cookbook的主要价值在于把MongoDB配置外部化。下面的属性定义展示了常见可覆盖项,包括包版本、监听端口、数据目录、日志目录、绑定地址和副本集名称。将这些值放在attributes/default.rb后,role或环境可以按需覆盖,而不必修改recipe本身。
default['mongodb']['package']['version'] = '7.0.14' default['mongodb']['config']['port'] = 27017 default['mongodb']['config']['dbpath'] = '/var/lib/mongodb' default['mongodb']['config']['logdir'] = '/var/log/mongodb' default['mongodb']['config']['bind_ip'] = '0.0.0.0' default['mongodb']['config']['replSet'] = 'rs0' default['mongodb']['config']['auth'] = true
端口和存储目录的变化会直接影响可用性和容量。数据目录建议放在独立挂载的磁盘上,日志目录与数据目录分离,方便日志轮转和磁盘满时的故障定位。绑定地址不建议始终写成0.0.0.0,生产环境应绑定内网地址或具体网卡,避免将MongoDB暴露到公网。Chef执行前需要确保目录存在并归属mongodb用户,因此recipe中通常会包含目录资源。
directory node['mongodb']['config']['dbpath'] do owner 'mongodb' group 'mongodb' mode '0750' recursive true end directory node['mongodb']['config']['logdir'] do owner 'mongodb' group 'mongodb' mode '0750' recursive true end
配置文件由模板渲染生成。MongoDB 4.0之后推荐使用YAML格式配置,模板中不要硬编码参数,而是从变量传入。这样修改属性后,Chef会在下一次运行时比对模板并触发服务重启。
storage: dbPath: /var/lib/mongodb systemLog: destination: file path: /var/log/mongodb/mongod.log net: port: 27017 bindIp: 0.0.0.0 replication: replSetName: rs0 security: authorization: enabled
模板资源负责将属性填入配置文件并通知服务重启。使用:delayed通知可以把多次变更合并成一次重启,避免Chef运行期间频繁打断MongoDB写入。
template '/etc/mongod.conf' do
source 'mongod.conf.erb'
owner 'mongodb'
group 'mongodb'
mode '0644'
variables(
config: node['mongodb']['config']
)
notifies :restart, 'service[mongod]', :delayed
end
service 'mongod' do
supports status: true, restart: true, reload: true
action [:enable, :start]
end
副本集初始化与幂等性处理
生产环境很少以单节点运行MongoDB,副本集初始化是部署中最容易出错的一步。直接执行rs.initiate()的命令如果放入recipe且不加保护,每次Chef运行都会重复执行,第二次就会因为已初始化而报错,甚至可能干扰正常集群状态。正确的做法是用not_if或only_if守卫。
execute 'initiate_mongodb_replset' do
command "mongosh --quiet --eval 'rs.initiate({_id: \"rs0\", members: [{_id: 0, host: \"10.0.0.10:27017\"}]})'"
not_if "mongosh --quiet --eval 'rs.status().ok' | grep -q 1"
only_if { node['mongodb']['config']['replSet'] == 'rs0' }
end
上面的守卫逻辑简单直接,但在复杂场景中仍显脆弱。rs.status().ok只能判断命令是否成功,不能区分当前节点已经在副本集中、还是刚刚启动但尚未初始化。更好的方式是在Ruby block中连接MongoDB,检查rs.status()返回的set字段和myState字段,再决定是否需要执行初始化。对于已有副本集新增节点,则应该使用rs.add(),而不是重新初始化全部成员。
execute 'add_mongodb_replset_member' do
command "mongosh --host 10.0.0.10 --quiet --eval 'rs.add(\"10.0.0.11:27017\")'"
not_if "mongosh --host 10.0.0.10 --quiet --eval 'rs.status().members.some(function(m){return m.name == \"10.0.0.11:27017\"})' | grep -q true"
end
初始化副本集前,必须确保节点主机名和/etc/hosts配置准确,否则成员列表中的主机名无法被其他节点解析,会导致后续自动选主和心跳失败。mongodb-chef-cookbook通常会提供replset recipe和shard recipe,分别处理副本集和分片集群的初始化。使用时要确认recipe的默认端口与配置属性一致,避免出现配置文件中端口为27017,但初始化命令连接27018的情况。
用Test Kitchen验证与生产调优
在提交到Chef Server前,通过Test Kitchen在虚拟机或容器中完整执行一遍部署,可以提前发现包源不可达、目录权限错误和模板渲染问题。Kitchen配置中可以使用Vagrant作为驱动,Chef Zero作为Provisioner,这样不需要真实的Chef Server就能测试整个run list。
---
driver:
name: vagrant
provisioner:
name: chef_zero
always_update_cookbooks: true
platforms:
- name: ubuntu-22.04
- name: centos-stream-9
suites:
- name: default
run_list:
- recipe[mongodb-chef-cookbook::default]
attributes:
mongodb:
config:
port: 27018
replSet: rs0
执行kitchen converge会创建节点并运行cookbook,kitchen verify可以触发InSpec测试,检查MongoDB服务状态和端口监听。这种验证方式比手工登录服务器检查更可靠,也能把部署标准固化到测试代码中。
describe port(27018) do
it { should be_listening }
end
describe service('mongod') do
it { should be_enabled }
it { should be_running }
end
生产环境还需要关注资源限制和存储引擎参数。MongoDB对文件描述符和进程数有一定要求,Chef recipe可以写入/etc/security/limits.d/mongodb.conf,确保mongodb用户不会因默认限制而拒绝连接。
mongodb soft nofile 64000 mongodb hard nofile 64000 mongodb soft nproc 64000 mongodb hard nproc 64000
此外,启用认证后副本集节点之间必须使用相同的keyfile,并且该文件权限应设为0400。备份策略不要只依赖云盘快照,还应该定期执行mongodump并验证恢复流程。WiredTiger缓存大小默认可能占用物理内存的一半,通过attribute暴露storage.wiredTiger.engineConfig.cacheSizeGB后,可以根据实际内存和业务负载调整。任何配置变更都建议采用滚动重启方式,先重启从节点,再切换主节点,避免写入中断。
MongoDBChef Cookbook自动化部署修改时间:2026-09-19 01:31:47