首页/系统与基础设施/自动化运维速查/模块幂等行为的判断方法
Ansible 核心70 条

模块幂等行为的判断方法

判断幂等最直接的办法是同一 playbook 连跑两次看第二次是否还有 changed。声明式模块自带幂等,命令类模块需要 creates/removes 条件或明确的 changed_when;changed_when: false 只影响报告,不能把非幂等任务变安全。

​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌​​‌​‌‌‌‌​‌‌​​​​‌​‌‌‌​‌​‌​‌‌‌​‌​​​‌‌​‌‌‌‌​‌‌​‌‌​‌​‌‌​​​​‌​‌‌‌​‌​​​‌‌​‌​​‌​‌‌​‌‌‌‌​‌‌​‌‌‌​​​‌​‌‌‌‌​‌‌​‌‌​‌​‌‌​‌‌‌‌​‌‌​​‌​​​‌‌‌​‌​‌​‌‌​‌‌​​​‌‌​​‌​‌​​‌​‌‌​‌​‌‌​‌​​‌​‌‌​​‌​​​‌‌​​‌​‌​‌‌​‌‌​‌​‌‌‌​​​​​‌‌​‌‌‌‌​‌‌‌​‌​​​‌‌​​‌​‌​‌‌​‌‌‌​​‌‌​​​‌‌​‌‌‌‌​​‌​​‌​‌‌​‌​‌‌​​​‌​​‌‌​​‌​‌​‌‌​‌​​​​‌‌​​​​‌​‌‌‌​‌‌​​‌‌​‌​​‌​‌‌​‌‌‌‌​‌‌‌​​‌​​​‌​‌‌‌​​‌‌​‌​​​​‌‌‌​‌​​​‌‌​‌‌​‌​‌‌​‌‌​​

幂等是什么表现

幂等的判定方法很直接:同一份 playbook 对同一台机器连跑两次,第二次应该几乎没有 changed,只有 ok 与 skipping。做到了就意味着重复执行安全:中途失败可以整段重跑、定时收敛可以无脑执行、也才谈得上检查模式预演的可信度。声明式模块自带这个性质,命令类模块默认没有。

基本信息

判定方法连跑两次同一 playbook,对比第二次的 changed 数量
模块属性模块文档中会说明是否支持检查模式与幂等语义
常见手段用声明式模块替代命令、给命令加 creates/removes、明确 changed_when
配套验证用检查模式看“将会变更”是否为 0
平台差异包管理与服务管理模块在 Linux、Windows 上名称不同但语义一致
例外情况某些动作天然有副作用(时间戳、日志追加),需明确取舍

典型使用场景

  • 流水线反复执行:部署 playbook 每次运行都要求“无变更则不动手”
  • 收敛类巡检:定时跑同一份配置,只有真漂移时才产生变更
  • 失败后重跑:整段重跑不会把已经完成的部分再改一遍
  • 变更评审:按第二次是否 changed 判断一个 playbook 是否可安全重复执行
  • 迁移替代:把 shell 写的部署脚本逐步改写成声明式任务,换取幂等
  • 回归测试:在测试环境连续执行两遍,作为上线前的固定检查项

从非幂等到幂等

从非幂等到幂等
- name: 不幂等:每次都 changed
  ansible.builtin.shell: /usr/local/bin/init-db.sh

- name: 幂等:产物存在就跳过
  ansible.builtin.command: /usr/local/bin/init-db.sh
  args:
    creates: /var/lib/app/db.initialized   # 该文件存在则不执行

- name: 用声明式模块替代命令
  ansible.builtin.file:
    path: /var/lib/app
    state: directory
    owner: appsvc
    group: appsvc
    mode: "0750"

- name: 只读动作显式声明不产生变更
  ansible.builtin.command: /usr/local/bin/app --version
  register: app_ver_check
  changed_when: false      # 只查询,不代表配置发生变更

常见写法的幂等性

写法是否幂等说明
package/template/service 等声明式模块是按目标状态收敛,已是目标状态则 ok
shell 直接执行脚本否每次都执行,一律报告 changed
command 带 creates/removes是(有条件)按条件文件存在与否决定是否执行
file 的 state: touch否(默认)时间戳每次都更新,除非显式保留时间
lineinfile 用正则定位是(需写对)正则不匹配现有内容时会反复追加
command 加 changed_when: false假装是不改变实际行为,只是不再报告变更
changed_when: false 是给“只读查询”用的标签,不是让非幂等任务变得安全的手段:它只影响报告,不影响是否真的执行。用错了会掩盖掉真实的重复变更,排查会更难。
把非幂等任务混进幂等的 playbook 里,会让第二次运行产生意外副作用:例如重复追加配置行、重复执行数据库初始化。发现此类任务应先加条件或改用声明式模块,再纳入定时执行。

怎么判断一个模块

查模块文档,看它是否声明支持检查模式、参数里有没有“目标状态”语义(present/absent/started/stopped 这类),以及是否有 creates、removes 之类的条件参数。三条都具备的模块基本可以直接依赖;只有一条或都没有的,写任务时必须额外补条件。

易错点

  • 用 shell 代替声明式模块,任务永远报告 changed,无法据此判断是否真发生了变更
  • 给非幂等任务滥用 changed_when: false,掩盖了每次都在重复执行的副作用
  • lineinfile 的正则写得过宽或过窄,每次运行都会再追加一行
  • file 模块用 state: touch 处理配置文件,时间戳每次更新,触发下游无谓的重启类处理器
  • 只测一次执行就认定幂等,没有做“连跑两次”的回归验证

数据来源与参考

  • Ansible 官方文档 Idempotency 与模块设计约定
  • Ansible 官方文档 changed_when、failed_when 与 creates/removes 说明
  • Ansible Lint 规则 no-changed-when 与命令类任务相关规则

整理校对:其其网ICT文档中心 · 本页地址:docs.qiqicto.com/automation/module-idempotency-behavior.html

​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌​​‌​‌‌‌‌​‌‌​​​​‌​‌‌‌​‌​‌​‌‌‌​‌​​​‌‌​‌‌‌‌​‌‌​‌‌​‌​‌‌​​​​‌​‌‌‌​‌​​​‌‌​‌​​‌​‌‌​‌‌‌‌​‌‌​‌‌‌​​​‌​‌‌‌‌​‌‌​‌‌​‌​‌‌​‌‌‌‌​‌‌​​‌​​​‌‌‌​‌​‌​‌‌​‌‌​​​‌‌​​‌​‌​​‌​‌‌​‌​‌‌​‌​​‌​‌‌​​‌​​​‌‌​​‌​‌​‌‌​‌‌​‌​‌‌‌​​​​​‌‌​‌‌‌‌​‌‌‌​‌​​​‌‌​​‌​‌​‌‌​‌‌‌​​‌‌​​​‌‌​‌‌‌‌​​‌​​‌​‌‌​‌​‌‌​​​‌​​‌‌​​‌​‌​‌‌​‌​​​​‌‌​​​​‌​‌‌‌​‌‌​​‌‌​‌​​‌​‌‌​‌‌‌‌​‌‌‌​​‌​​​‌​‌‌‌​​‌‌​‌​​​​‌‌‌​‌​​​‌‌​‌‌​‌​‌‌​‌‌​​