遍历Ansible清单主机名出现混乱及WordPress密码更新失败问题
问题场景
清单配置
[servers] host1 ansible_ssh_host=xxx host2 ansible_ssh_host=xxx
剧本内容
- name: Setup hosts: servers gather_facts: false remote_user: ansible become: true roles: - task
调试用角色任务
- name: Show all the hosts in the inventory ansible.builtin.debug: msg: "{{ item }}" loop: "{{ query('inventory_hostnames', 'all') }}"
调试任务执行结果
执行剧本后出现主机循环混乱,输出如下:
TASK [task : Show all the hosts in the inventory] *************************************************************** ok: [host1] => (item=host1) => { "msg": "host1" } ok: [host2] => (item=host1) => { "msg": "host1" } ok: [host1] => (item=host2) => { "msg": "host2" } ok: [host2] => (item=host2) => { "msg": "host2" }
实际任务及报错
尝试在数百台服务器上执行WordPress管理员密码更新任务:
- name: Update admin user's password command: wp user update admin --user_pass="{{ wp_admin_pwd }}" args: chdir: "/var/www/{{ item }}" become: yes become_user: www-data with_items: "{{ query('inventory_hostnames', 'all') }}"
执行后大量报错,示例错误信息:
failed: [host1] (item=host2) => {"ansible_loop_var": "item", "changed": false, "cmd": "", "delta": null, "end": null, "item": "host2", "msg": "Unable to change directory before execution: [Errno 2] No such file or directory: b'/var/www/host2'"
问题核心:wp-cli必须在站点根目录执行,但当前循环方式错误,导致在host1上尝试访问host2的目录,引发不存在的路径错误。
解决方案
错误原因
使用query('inventory_hostnames', 'all')作为循环源,会让每一台目标主机都遍历整个清单的所有主机。也就是说,host1会循环处理host1和host2,host2也会循环处理host1和host2,最终导致在host1上尝试进入仅存在于host2的目录,触发报错。
修正方法
方法1:针对当前主机直接操作
不需要循环清单主机,直接使用Ansible内置变量inventory_hostname(代表当前执行任务的主机名):
- name: Update admin user's password command: wp user update admin --user_pass="{{ wp_admin_pwd }}" args: chdir: "/var/www/{{ inventory_hostname }}" become: yes become_user: www-data
这样每台主机只会处理自己对应的站点目录,避免跨主机路径错误。
方法2:单主机多站点场景适配
如果单台主机上部署了多个WordPress站点,可在主机变量中定义站点列表,循环站点而非主机:
- 修改清单,给主机添加站点变量:
[servers] host1 ansible_ssh_host=xxx wp_sites=["site1", "site2"] host2 ansible_ssh_host=xxx wp_sites=["site3"]
- 更新任务,循环站点列表:
- name: Update admin user's password for all sites command: wp user update admin --user_pass="{{ wp_admin_pwd }}" args: chdir: "/var/www/{{ item }}" become: yes become_user: www-data loop: "{{ wp_sites }}"
补充说明
- 若站点目录命名规则与主机名不一致,可在清单中给每个主机单独定义
wp_site_dir变量,任务中直接引用{{ wp_site_dir }}即可。 - 仅当需要在每台主机上遍历所有其他主机时,才使用
query('inventory_hostnames')做任务循环,日常单主机任务无需此操作。
内容的提问来源于stack exchange,提问作者Roberto Jobet
相关产品推荐
相关产品推荐

