Ansible local_action连接异常:变量定义位置引发的连接方式差异
我编写了两个Ansible角色:
- 一个通过WinRM在远程服务器安装OpenSSH
- 另一个通过SSH在同一台服务器安装Windows功能
当前遇到的问题是,角色中使用local_action委派到控制节点的任务出现连接异常,具体情况:
- 当变量定义在playbook的
vars下时,执行install-openssh.yml会报错,无法通过WinRM连接localhost; - 将变量移至对应角色的
defaults/main.yml后,install-openssh.yml执行成功,此时localhost采用本地连接;但install-wfeature.yml仍报错,SSH连接localhost时出现主机密钥验证失败。
非委派任务均可正常执行,疑惑的是变量值完全相同,仅定义位置不同,为何会导致localhost的连接方式产生差异?
相关代码如下:
install-openssh.yml
--- - name: Install and configure OpenSSH hosts: all vars: ansible_user: ansible ansible_password: "{{ server_password }}" ansible_connection: winrm ansible_port: 5985 roles: - install-openssh
install-wfeature.yml
--- - name: Install Windows features hosts: all vars: ansible_user: ansible ansible_connection: ssh ansible_port: 22 roles: - install-wfeature
报错信息示例
移动变量前install-openssh.yml报错:
<localhost> ESTABLISH WINRM CONNECTION FOR USER: ansible on PORT 5985 to localhost fatal: [target_server -> localhost]: UNREACHABLE! => { "changed": false, "msg": "plaintext: HTTPConnectionPool(host='localhost', port=5985): Max retries exceeded with url: /wsman (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7fdb8b10bb20>: Failed to establish a new connection: [Errno 111] Connection refused'))", "unreachable": true }
移动变量后install-wfeature.yml报错:
<localhost> ESTABLISH SSH CONNECTION FOR USER: ansible [...] fatal: [target_server -> localhost]: UNREACHABLE! => { "changed": false, "msg": "Data could not be sent to remote host \"localhost\". Make sure this host can be reached over ssh: Host key verification failed.\r\n", "unreachable": true }
问题根源:变量作用域与委派任务的连接参数继承
Playbook级
vars的作用范围:在playbook的vars中定义ansible_connection这类连接参数时,参数会被所有任务继承,包括local_action委派到localhost的任务。这导致原本应使用本地连接(local)的localhost任务,被强制套用playbook指定的winrm或ssh连接方式——而你的控制节点(localhost)并未开启WinRM服务(第一个报错的原因),或未配置SSH密钥验证(第二个报错的原因)。角色
defaults的作用范围:角色的defaults变量优先级更低,且仅在角色内部生效,不会覆盖Ansible对localhost的默认连接配置(默认使用local连接,无需走WinRM/SSH)。因此将变量移至角色defaults后,委派到localhost的任务会使用默认本地连接,执行成功;但install-wfeature.yml仍在playbook的vars中定义了ansible_connection: ssh,委派任务依然继承该参数,尝试用SSH连接localhost,导致密钥验证失败。
解决步骤
分离远程节点与localhost的连接参数:不要在playbook的
vars中定义全局连接参数,将ansible_connection、ansible_port等参数放到inventory文件中,针对远程目标主机单独配置,示例:[windows_servers] target_server ansible_user=ansible ansible_password={{ server_password }} ansible_connection=winrm ansible_port=5985这样只有远程主机使用WinRM/SSH连接,localhost的委派任务保持默认本地连接。
处理
install-wfeature.yml的SSH密钥问题:若确实需要用SSH连接localhost(不建议,优先用本地连接),可在控制节点执行ssh-keygen生成密钥,将公钥添加到~/.ssh/authorized_keys;或在委派任务中临时跳过密钥验证(仅限测试环境):- name: 示例委派任务 local_action: module: command cmd: echo "test" vars: ansible_ssh_common_args: "-o StrictHostKeyChecking=no"更合理的做法是避免在playbook全局设置SSH连接参数,确保委派任务使用本地连接。
角色内变量规范:将针对远程节点的配置变量放在角色的
defaults或vars中,主机级的连接参数统一在inventory中管理,避免作用域混淆。
内容的提问来源于stack exchange,提问作者C. Güzelhan

