把任务放到别的主机上执行
默认情况下任务在“当前这台主机”上执行。委派机制允许把它改到另一台机器上执行,典型场景是共享资源的单点操作:把主机注册到负载均衡、在统一的登记系统里写一条记录。与之配套的单次执行开关让该任务在整批主机里只跑一次,避免同样的操作重复几十遍。
基本信息
| 委派执行 | 把某个任务的执行目标换成另一台主机,连接按被委派主机建立 |
|---|---|
| 单次执行 | 该任务在一批主机中只执行一次,通常与委派配合使用 |
| 变量归属 | 连接相关变量按被委派主机解析,业务变量与事实仍属于当前主机 |
| 事实归属 | 可通过开关决定采集到的事实记在当前主机还是被委派主机上 |
| 批次影响 | 配合滚动批次使用时,单次执行会在每一批各执行一次 |
| 依赖前提 | 被委派的目标需要在清单中可见,或使用本机这一特殊目标 |
典型使用场景
- 负载均衡注册:所有主机装完后由控制节点统一更新一次后端列表
- DNS 与配置中心:写共享记录只需一次,不必每台主机各写一遍
- 控制节点上的编排动作:调用外部接口、拉取构件、生成证书请求
- 绕过访问限制:只有某台跳板机能访问外部服务时,把动作委派给它
- 共享锁与配额检查:全局性判断只应执行一次,避免并发争抢
- 跨主机取值:需要读取另一台主机的状态时,把查询委派过去
写法与变量归属
写法与变量归属
- hosts: web
tasks:
- name: 每台主机各自装包
ansible.builtin.package:
name: app-server
state: present
- name: 只在控制节点执行一次,把主机登记到负载均衡
ansible.builtin.uri:
url: "http://lb.internal/api/backends"
method: POST
body_format: json
body:
host: "{{ inventory_hostname }}" # 仍是当前主机的名字
port: "{{ app_port }}"
delegate_to: localhost
run_once: true
register: register_result
- name: 单次执行注册的变量对整批主机可用
ansible.builtin.debug:
msg: "登记结果 {{ register_result.status }}"
when: register_result is defined
- name: 委派到另一台主机并让事实记在它名下
ansible.builtin.setup:
gather_subset: ['network']
delegate_to: bastion1
delegate_facts: true
run_once: true组合方式对照
| 组合 | 行为 | 适用 |
|---|---|---|
| 委派到本机 | 在控制节点执行该任务 | 调用接口、生成构件、写共享记录 |
| 委派到清单内主机 | 在指定主机上执行,连接指向它 | 跳板机动作、读取特定主机状态 |
| 单次执行 | 整批只执行一次 | 共享资源的单点操作 |
| 单次执行加滚动批次 | 每批各执行一次 | 需确认是否真的只需要全局一次 |
| 委派并转移事实 | 采到的事实记在被委派主机名下 | 需要以被委派主机视角记录信息 |
最容易混淆的是变量视角:任务被委派后,业务变量与主机名仍表达“当前处理的那台主机”,而连接相关设置按被委派主机解析。这也是同一任务里既能取到当前主机名、又能在另一台机器上执行的原因。
单次执行与滚动批次叠加时会按批重复,原本假定“全局只做一次”的操作(例如初始化集群元数据)就会被执行多次。使用前先确认该动作在多次执行下是否安全,必要时加幂等判断或改用显式的串行步骤。
什么时候该改设计
如果大量任务都要靠委派与单次执行才能正确工作,说明剧本的职责划分有问题:共享级别的操作本应拆成单独的 play 或独立剧本,在明确的一台主机上执行。用得越多越偏离“任务与被管主机一一对应”的直觉,维护成本也随之上升。