控制任务运行位置:委托和本地操作
默认情况下,Ansible 会在与剧本中 hosts
行匹配的机器上收集事实并执行所有任务。本页面将向您展示如何将任务委托给其他机器或组、将事实委托给特定机器或组,或在本地运行整个剧本。使用这些方法,您可以精确有效地管理相互关联的环境。例如,更新 Web 服务器时,您可能需要暂时将其从负载均衡池中删除。您无法在 Web 服务器本身上执行此任务。通过将任务委托给 localhost,您可以将所有任务保留在同一个剧本中。
无法委托的任务
一些任务始终在控制节点上执行。这些任务(包括 include
、add_host
和 debug
)无法委托。您可以从 connection
属性文档中确定某项操作是否可以委托。如果 connection
属性指示 support
为 False
或 None
,则该操作不使用连接,因此无法委托。
委托任务
如果要在某一台主机上执行一项任务,并参考其他主机,请在任务上使用 delegate_to
关键字。这非常适合管理负载均衡池中的节点或控制停机时间。您可以将委托与 serial 关键字一起使用,以控制同时执行主机的数量
---
- hosts: webservers
serial: 5
tasks:
- name: Take out of load balancer pool
ansible.builtin.command: /usr/bin/take_out_of_pool {{ inventory_hostname }}
delegate_to: 127.0.0.1
- name: Actual steps would go here
ansible.builtin.yum:
name: acme-web-stack
state: latest
- name: Add back to load balancer pool
ansible.builtin.command: /usr/bin/add_back_to_pool {{ inventory_hostname }}
delegate_to: 127.0.0.1
此剧本中的第一项和第三项任务在 127.0.0.1 上运行,即运行 Ansible 的机器。您还可以在每项任务的基础上使用简写语法:local_action
。以下是与上面相同的剧本,但使用简写语法委托给 127.0.0.1
---
# ...
tasks:
- name: Take out of load balancer pool
local_action: ansible.builtin.command /usr/bin/take_out_of_pool {{ inventory_hostname }}
# ...
- name: Add back to load balancer pool
local_action: ansible.builtin.command /usr/bin/add_back_to_pool {{ inventory_hostname }}
您可以使用本地操作来调用“rsync”将文件递归地复制到管理的服务器
---
# ...
tasks:
- name: Recursively copy files from management server to target
local_action: ansible.builtin.command rsync -a /path/to/files {{ inventory_hostname }}:/path/to/target/
请注意,您必须配置无密码 SSH 密钥或 ssh 代理才能使此操作正常工作,否则 rsync 会提示输入密码。
若要指定更多参数,请使用以下语法
---
# ...
tasks:
- name: Send summary mail
local_action:
module: community.general.mail
subject: "Summary Mail"
to: "{{ mail_recipient }}"
body: "{{ mail_body }}"
run_once: True
注意
如果存在,
ansible_host
变量和其他连接变量会反映有关委托给任务的主机的信息,而不是 inventory_hostname。委托给任务的主机不会继承委托任务的主机的变量。
警告
尽管您可以将 delegate_to
委托给库存中不存在的主机(通过添加 IP 地址、DNS 名称或连接插件所需的任何内容),但这不会将主机添加到您的库存,并且可能会导致问题。以这种方式委托给的主机不会继承“所有”组的变量(假设 VARIABLE_PRECEDENCE 包含 all_inventory
)。如果您必须将 delegate_to
委托给非库存主机,请使用 添加主机模块。
委托上下文中的模板化
请注意,在委托下,执行解释器(通常为 Python)、connection
、become
和 shell
插件选项现在将使用委托给主机的值进行模板化。除了 inventory_hostname
之外的所有变量现在都将从该主机中获取,而不是从原始任务主机中获取。如果您需要来自原始任务主机的变量用于这些选项,则必须使用 hostvars[inventory_hostname]['varname']
,即使 inventory_hostname_short
也指的是委托主机。
委托和并行执行
默认情况下,Ansible 任务会并行执行。委托任务不会更改这一点,也不会处理并发问题(多个 fork 写入同一文件)。最常见的是,当用户为所有主机更新委托给主机上的单个文件(例如,使用 copy
、template
或 lineinfile
模块)时,他们会受到影响。它们仍将在并行 fork(默认值为 5)中运行,并相互覆盖。
这可以通过多种方法解决
- name: "handle concurrency with a loop on the hosts with `run_once: true`"
lineinfile: "<options here>"
run_once: true
loop: '{{ ansible_play_hosts_all }}'
通过使用包含 serial: 1 的中间剧本,或者在任务级别使用 throttle: 1,有关更多详细信息,请参阅 控制剧本执行:策略及更多
委托事实
委托 Ansible 任务就像在现实生活中委托任务一样——即使有人将您的杂货送到您的家门口,它们也归您所有。同样,委托任务收集的任何事实默认情况下都分配给 inventory_hostname(当前主机),而不是生成事实的主机(委托给的主机)。若要将收集到的事实分配给委托的主机,而不是当前主机,请将 delegate_facts
设置为 true
---
- hosts: app_servers
tasks:
- name: Gather facts from db servers
ansible.builtin.setup:
delegate_to: "{{ item }}"
delegate_facts: true
loop: "{{ groups['dbservers'] }}"
此任务会为 dbservers 组中的机器收集事实,并将事实分配给这些机器,即使剧本的目标是 app_servers 组。这样,您就可以查找 hostvars[‘dbhost1’][‘ansible_default_ipv4’][‘address’],即使 dbservers 不属于剧本的一部分,或者通过使用 --limit
被排除在外。
本地剧本
将剧本在远程主机上本地使用,而不是通过 SSH 连接,可能很有用。这对于通过将剧本放在 crontab 中来确保系统的配置很有用。这也可以用来在操作系统安装程序(例如 Anaconda kickstart)中运行剧本。
若要在本地运行整个剧本,只需将 hosts:
行设置为 hosts: 127.0.0.1
,然后像这样运行剧本
ansible-playbook playbook.yml --connection=local
或者,即使剧本中的其他剧本使用默认的远程连接类型,也可以在单个剧本中使用本地连接
---
- hosts: 127.0.0.1
connection: local
注意
如果您将连接设置为本地,并且没有设置 ansible_python_interpreter,则模块将在 /usr/bin/python 下运行,而不是在 {{ ansible_playbook_python }} 下运行。请确保在 host_vars/localhost.yml 中设置 ansible_python_interpreter: “{{ ansible_playbook_python }}”,例如。您可以通过使用 local_action
或 delegate_to: localhost
来避免此问题。
另请参阅
- Ansible 剧本
剧本介绍
- 控制剧本执行:策略及更多
更多控制 Ansible 如何以及在何处执行的方法
- 交流
有问题?需要帮助?想分享你的想法?请访问 Ansible 交流指南