You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Ansible通配符匹配主机时任务会重复执行?

Ansible任务重复执行问题分析与解决

问题背景

在Hetzner云服务器环境中使用Ansible 2.9.27及动态库存,共有20台服务器需通过playbook遍历。动态库存中的主机列表如下:

$ ansible-inventory -i inventory/production/ --graph | grep srv
  |  |  |--srv01.mydomain.co.uk
  |  |  |--srv02.mydomain.co.uk
  |  |  |--srv03.mydomain.co.uk
  |  |  |--srv04.mydomain.co.uk
  |  |  |--srv05.mydomain.co.uk
  |  |  |--srv06.mydomain.co.uk
  |  |  |--srv07.mydomain.co.uk
  |  |  |--srv08.mydomain.co.uk
  |  |  |--srv09.mydomain.co.uk
  |  |  |--srv10.mydomain.co.uk
  |  |  |--srv11.mydomain.co.uk
  |  |  |--srv12.mydomain.co.uk
  |  |  |--srv13.mydomain.co.uk
  |  |  |--srv14.mydomain.co.uk
  |  |  |--srv15.mydomain.co.uk
  |  |  |--srv16.mydomain.co.uk
  |  |  |--srv17.mydomain.co.uk
  |  |  |--srv18.mydomain.co.uk
  |  |  |--srv19.mydomain.co.uk
  |  |  |--srv20.mydomain.co.uk

编写的playbook如下:

- name: test iteration over names
  hosts: "{{ HOSTS }}"
  gather_facts: False

  tasks:

  - ping:
    with_items: "{{ ansible_play_hosts }}"     

执行playbook时,指定匹配srv?5.mydomain.co.uk的主机,结果如下:

$ ansible-playbook --inventory inventory/production iteration.yaml --extra-vars "HOSTS=srv?5.mydomain.co.uk "

PLAY [test iteration over names] *************************************************************************************************************************************************************************

TASK [ping] **********************************************************************************************************************************************************************************************
ok: [srv05.mydomain.co.uk] => (item=srv05.mydomain.co.uk)
ok: [srv05.mydomain.co.uk] => (item=srv15.mydomain.co.uk)
ok: [srv15.mydomain.co.uk] => (item=srv05.mydomain.co.uk)
ok: [srv15.mydomain.co.uk] => (item=srv15.mydomain.co.uk)

PLAY RECAP ***********************************************************************************************************************************************************************************************
srv05.mydomain.co.uk : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
srv15.mydomain.co.uk : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

现象:每台主机的ping执行次数与通配符匹配的主机数量一致——匹配2台时各执行2次,匹配10台时各执行10次。需要明确该现象的原因,以及如何实现每台主机仅执行一次任务。

现象原因

ansible_play_hosts变量包含当前play中所有目标主机的列表,当你在任务中使用with_items: "{{ ansible_play_hosts }}"时,每台目标主机都会遍历整个主机列表执行一次任务。

比如匹配到2台主机时,每台主机都会循环2次(对应列表里的2个主机项),所以最终每台主机执行2次ping任务;匹配N台主机时,每台主机就会执行N次任务。

解决方案

不需要额外使用with_items循环,Ansible本身会自动对hosts字段指定的每台主机执行一次任务。直接去掉循环逻辑即可:

- name: test iteration over names
  hosts: "{{ HOSTS }}"
  gather_facts: False

  tasks:

  - ping:

执行该playbook后,每台匹配的主机只会执行一次ping任务,符合预期。

如果确实需要基于主机列表做自定义遍历(比如对当前主机只处理自身相关的逻辑),可以通过条件判断过滤,只在当前主机与列表项匹配时执行:

- name: test iteration over names
  hosts: "{{ HOSTS }}"
  gather_facts: False

  tasks:

  - ping:
    with_items: "{{ ansible_play_hosts }}"
    when: item == inventory_hostname

这种方式下,每台主机只会在循环到自身时执行任务,最终每台主机仅执行一次。


内容的提问来源于stack exchange,提问作者Kevin Jones

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 08:55:06