Ansible play设置serial属性时组变量未定义但任务执行时可用问题咨询
问题结论
这是Ansible的预期行为,核心原因是Ansible不同执行阶段的变量加载逻辑不同。
根因说明
- Ansible的play级属性(包括
serial、hosts、name、gather_facts等)会在play初始化阶段完成解析,这个阶段只会加载三类变量:静态清单配置的变量、全局配置定义的变量、命令行通过--extra-vars传入的变量。你在动态清单运行过程中生成的组变量,此时还未被加载,因此解析serial时会提示变量未定义。 - 任务级的变量解析发生在任务执行阶段,该阶段会先完成所有动态清单变量、主机变量、组变量的加载,再逐行执行任务,因此你在loop中可以正常读取
host_set的值。
可行的解决方案
方案1:通过extra vars传入变量
--extra-vars传入的变量优先级最高,且会在play初始化阶段被加载,直接执行如下命令即可:
ansible-playbook your_playbook.yaml -e "host_set=['host1','host2']"
原playbook中serial的表达式无需修改即可正常生效。
方案2:将变量写入静态变量配置
如果不需要动态生成该变量,可以把host_set定义在静态inventory的group_vars目录、或ansible.cfg指定的全局变量路径下,静态变量会在play初始化阶段被读取,也可被serial参数识别。
方案3:拆分play实现动态控制
如果必须使用动态清单生成的host_set控制串行度,可以将play拆分为两段:
# 第一段play先获取动态清单的变量 - name: 预加载动态清单变量 hosts: all gather_facts: no run_once: yes tasks: - name: 存储host_set变量到本地 set_fact: play_serial: "{{ host_set | default(false) | ternary('100%', '5') }}" delegate_to: localhost delegate_facts: yes # 第二段play使用预加载的变量设置serial - name: 实际执行业务任务 hosts: all serial: "{{ hostvars['localhost']['play_serial'] }}" tasks: - include_tasks: include/restart.yaml loop: "{{ host_set | default(['all']) }}" loop_control: loop_var: h
内容的提问来源于stack exchange,提问作者Radu Stoenescu
相关产品推荐
相关产品推荐

