Ansible多环境(dev/prod)配置文件的组织方式?

文章导读
在维护 Ansible 配置时,dev 和 prod 的差异往往不只是几个变量不同,还涉及主机清单、变量加载路径、密钥管理。先把目录结构定清楚,后面会减少很多“改不动又不敢删”的尴尬。这里整理一种适合中小团队直接落地的组织方式,以及需要结合自身环境确认的地方。
📋 目录
  1. 先区分变量按环境变化还是按主机变化
  2. 目录组织:把 inventory 和 group_vars 放在同一个环境中
  3. 变量优先级是大多数问题的根源
  4. 敏感信息需要单独处理
  5. 尽量通过模板和变量表达差异
  6. 每次改动后可以做的检查
A A

在维护 Ansible 配置时,dev 和 prod 的差异往往不只是几个变量不同,还涉及主机清单、变量加载路径、密钥管理。先把目录结构定清楚,后面会减少很多“改不动又不敢删”的尴尬。这里整理一种适合中小团队直接落地的组织方式,以及需要结合自身环境确认的地方。

先区分变量按环境变化还是按主机变化

组织多环境配置时,先区分变量按环境变化还是按主机变化。如果大部分变量(如数据库地址、日志级别)随环境整体切换,优先使用group_vars目录按环境分组;只有少数主机专属变量(如IP、端口)才放入host_vars。判断标准是:同一环境内所有主机共享的配置放进group_vars/dev.yml或group_vars/prod.yml,而每台主机独立的配置才放在host_vars下。如果环境间差异仅靠变量就能表达,就不需要维护多份playbook,否则会引入大量重复。

实际项目里,dev 环境可能只有一台机器,而 prod 有几十台,这时组名比主机名稳定,所以仍应该按环境建组,而不是按主机建目录。如果你发现很多变量在每台机器上都不一样,那要么是环境划分不够准确,要么是这份配置根本不适合用静态 inventory 表达,可以考虑动态清单。

目录组织:把 inventory 和 group_vars 放在同一个环境中

推荐在仓库顶层维护inventory目录,每个环境一个hosts文件或一个yml文件,例如inventory/dev/hosts和inventory/prod/hosts。同时将group_vars直接放在对应环境的目录下,形如inventory/dev/group_vars/all.yml,这样执行ansible-playbook -i inventory/dev/hosts playbook.yml时,变量会自动从该目录加载,不需额外指定变量文件路径。注意hosts文件内要显式声明环境组名,如[dev]和[prod:children],避免组名模糊导致变量加载错乱。

执行命令时建议明确用 -i 指定环境目录。有人习惯把 inventory 文件放在根目录,group_vars 放在仓库根级,那样不是不行,但环境多了以后容易互相覆盖。把每个环境做成一个独立目录,后续加 staging、uat 环境也只是复制目录再改变量,不需要动 playbook。

Ansible多环境(dev/prod)配置文件的组织方式?

变量优先级是大多数问题的根源

一个容易踩的坑是变量优先级理解错位:命令行-e参数覆盖playbook中的vars,playbook中的vars又覆盖group_vars,而group_vars中的文件按字母顺序加载且后加载的覆盖先加载的。因此不要在group_vars下同时使用all.yml和同名环境文件定义相同变量,比如dev.yml中又定义了server_port,而all.yml也有server_port,ansible会按字典序合并,导致非预期覆盖。最稳妥的做法是环境中所有公共变量只放在all.yml,环境特有的变量放在与组名对应的文件里,并避免在playbook里重复定义同名变量。验证方式是用ansible-inventory --list -i inventory/dev/hosts输出实际变量树,看每个主机最终得到哪些值。

在调整变量时,不要只凭印象判断最终值。可以先跑一下命令确认当前维度。比如:ansible-inventory --list -i inventory/prod/hosts --export,然后看某个主机的变量来源。如果输出里出现了来自多个文件的同名变量,通常就是规划出了问题。

敏感信息需要单独处理

生产环境配置中常有密码、密钥等敏感信息。如果直接写成明文,仓库泄露就等于密码泄露。建议对生产环境的 group_vars 文件使用 vault 加密,例如 ansible-vault encrypt inventory/prod/group_vars/all.yml。执行 playbook 时,通过 ANSIBLE_VAULT_PASSWORD_FILE 环境变量或交互式提示提供 vault 密码。

风险边界在于,vault 密码本身不能放进仓库,也不要写进 playbook。团队共用时建议放在 CI 系统的 secret 管理里,或者在本地受保护的文件中。另外,加密后的文件用普通 diff 无法查看,多人协作时容易产生不可读的冲突。建议统一使用 ansible-vault edit 来修改,避免用编辑器直接改后造成整个文件变化。

尽量通过模板和变量表达差异

在 playbook 中尽量用变量引用环境差异,而不是为每个环境写一份重复任务。例如用 template.j2 生成配置时,将数据库地址、日志级别写成 {{ db_host }}{{ log_level }},然后在 dev 和 prod 的变量文件里分别提供不同的值。只有当任务本身逻辑不同,比如 prod 需要额外部署一个外部监控脚本,才使用 when: env == 'prod' 条件判断。

Ansible多环境(dev/prod)配置文件的组织方式?

这里需要确保 env 变量在所有环境都定义了。可以在 inventory 的 all 组中设置,也可以在 hosts 文件中直接定义。有些团队会在 all.yml 里写 env: devenv: prod,但要注意这个文件是放在环境目录下的,所以每个环境的 all.yml 只能定义一个值。如果希望自动识别环境名,可在 hosts 文件中设置组变量,或者用 inventory 文件名的规则做转换,但这依赖你的目录命名,需要结合现有结构确认。

在 playbook 里重复定义 env 容易造成混乱。建议只在 inventory 层定义一个来源,不要同时在 group_vars 和 playbook vars 里各写一份。

每次改动后可以做的检查

每次调整变量文件后,至少运行一遍 ansible-playbook --syntax-check -i inventory/dev/hosts playbook.yml,确认没有语法错误。再用 ansible-inventory --graph -i inventory/dev/hosts 查看组与主机的层级是否正确。接着针对一台受影响的机器执行 ansible-inventory --host dev-server -i inventory/dev/hosts --list --export,核对这台机器最终继承的变量是否与你预期一致。

还可以在 playbook 开头临时加一个 debug 任务,打印几个关键变量,用 --limit 指定单台主机跑一次,确认无误后再全量执行。需要提醒的是,不要在 prod 环境直接调试;先在 dev 环境用同一套 playbook 验证,等变量和逻辑都稳定了,再切到 prod。若生产环境已经出现问题,优先看变量树,而不是反复运行 playbook 试错。