环境隔离靠清单而不是靠判断
同一份 playbook 要在测试与生产上跑,最容易走偏的做法是在剧本里写一堆“如果是生产就怎样”的判断:久而久之两套逻辑交织,谁也不敢改。更清晰的方式是按环境拆分清单与变量:一套编排逻辑保持不变,环境差异全部落在各自的清单目录与变量文件里,切换环境只是换一个清单路径。
基本信息
| 清单组织 | inventory/<环境>/ 各一份清单,环境之间互不引用 |
|---|---|
| 变量组织 | 每个环境目录下自带 group_vars 与 host_vars |
| 剧本要求 | 环境无关:不出现测试或生产的字面量判断 |
| 秘密隔离 | 各环境独立的口令来源与加密文件,生产密钥单独管控 |
| 连接差异 | 跳板机、端口、认证方式等按环境写在清单变量里 |
| 防误操作 | 不给默认清单,执行时必须显式指定环境 |
典型使用场景
- 三套环境(开发、预发、生产)共用一套角色与剧本
- 生产与测试的连接方式不同:生产走跳板机、测试直连
- 参数取值不同:副本数、限流阈值、备份保留策略按环境区分
- 密钥隔离:生产凭据只对少数人可见,测试环境用另一套
- 上线前演练:先在预发清单上跑同一份剧本,验证流程本身
- 防止误操作:限制生产清单的访问与执行权限,测试清单保持可频繁重跑
清单与变量的分环境写法
清单与变量的分环境写法
# inventory/production/hosts.ini
# [web]
# web1.prod.internal
#
# inventory/production/group_vars/all/
# vars.yml 副本数、限流、备份保留等生产取值
# vault.yml 生产秘密,单独加密
#
# inventory/staging/hosts.ini
# [web]
# web1.stage.internal
#
# inventory/staging/group_vars/all/
# vars.yml 测试取值(副本数更小、日志更详细)
#
# 执行时永远显式指定环境清单
# ansible-playbook -i inventory/staging site.yml --check --diff
# ansible-playbook -i inventory/production site.yml
# 环境自检任务(放进剧本开头,防止清单拿错)
# - name: 断言操作对象属于预期环境
# ansible.builtin.assert:
# that:
# - inventory_hostname | regex_search(expected_env_suffix)
# fail_msg: "当前清单与预期环境不一致,已中止"差异该放在哪一层
| 差异类型 | 放置位置 | 理由 |
|---|---|---|
| 环境参数(阈值、副本数) | 环境目录下的分组变量 | 与环境绑定,切换清单即生效 |
| 连接方式(跳板、端口) | 环境清单内联或清单级变量 | 属于访问路径,不是业务参数 |
| 秘密值 | 环境各自的加密文件与口令来源 | 隔离访问权限与轮换节奏 |
| 主机个别差异 | host_vars | 避免污染分组级取值 |
| 编排流程本身 | 保持共用 | 流程差异说明分层没做干净 |
不要给 ansible.cfg 配一个指向生产的默认清单:任何忘记加 -i 的执行都会直接打到生产。宁可让工具在缺清单时报错,也不要让默认值替你选择一个环境。
多环境共用一个分组名时,变量优先级容易让人误判:两个环境的同名变量文件不会同时生效,但如果清单目录写错或清单被误改,实际取值会静默变成另一个环境的值,执行结果表面成功、配置却是错的。用开头断言做一道环境自检是低成本的保险。
怎么验证隔离是否彻底
做一次交叉实验:用预发清单跑生产参数的检查,看是否所有差异都来自清单与变量文件;再 grep 剧本里是否出现环境字面量。如果剧本里干净、差异全部落在清单目录里,隔离就到位了;反之,说明还有环境判断混在逻辑里,应当继续拆。