Ansible 任务委派

Ansible 任务委派

任务委派

先说两个场景:

  • 通过 Ansible 部署 K8S 集群(假设用 kubeadm 初始化集群),Playbook 刚开始会对 all 主机组进行初始化配置(安装软件包,设置 sysctlselinux 等),之后需要在一个节点执行 kubeadm init 启动一个集群,但是这个命令只需要执行一次并不需要在所有节点执行
  • 配置负载均衡集群,需要在负载均衡节点添加后端服务器的信息,需要在负载均衡节点执行

针对这两种情况,Ansible 提供了委派功能,委派实现的是将原本在其他节点执行的任务委派给一个特定主机,详细如图:

delegate

ansible.builtin.shell 模块为例,默认情况下模块会在所有被控节点执行,如果使用委派,那么原本应该在三个节点执行的任务会全部放到被委派的节点执行。

将所有任务委派到一个节点

看下边这个 YAML:

- name: test delegate_to
  hosts: all
  gather_facts: true
  tasks:
  - name: delegate_to command
    ansible.builtin.command: "echo {{ ansible_facts.hostname }}"
    delegate_to: servera
    register: delegate_to
  - name: debug
    ansible.builtin.debug:
      var: delegate_to.stdout
  - name: delegate_to shell
    ansible.builtin.shell: "echo {{ ansible_facts.hostname }} >> /tmp/testlog"
    delegate_to: servera

上边这个就是将 ansible.builtin.command 委派给 servera,如果有三个主机 serveraserverbserverc,就会有如下输出:

[root@study ansible]# ansible-playbook delegate.yml

PLAY [test delegate_to] *******************************************************************************************************************************************

TASK [Gathering Facts] ********************************************************************************************************************************************
ok: [serverb]
ok: [servera]
ok: [serverc]

TASK [delegate_to command] ****************************************************************************************************************************************
changed: [servera]
changed: [serverb -> servera]
changed: [serverc -> servera]

TASK [debug] ******************************************************************************************************************************************************
ok: [servera] => {
    "delegate_to.stdout": "servera"
}
ok: [serverc] => {
    "delegate_to.stdout": "serverc"
}
ok: [serverb] => {
    "delegate_to.stdout": "serverb"
}

TASK [delegate_to shell] ******************************************************************************************************************************************
changed: [serverc -> servera]
changed: [servera]
changed: [serverb -> servera]

PLAY RECAP ********************************************************************************************************************************************************
servera                    : ok=4    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
serverb                    : ok=4    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
serverc                    : ok=4    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

[root@study ansible]# ssh servera cat /tmp/testlog
serverc
servera
serverb

可以看到,任务都在 servera 上执行了,但是使用的变量还是原被控节点的,检查委派节点的 /tmp/testlog 也可以看到有三个节点的主机名,所以可以通过委派实现所有任务在一个节点执行。

不是所有模块都适合委派,比方说 ansible.builtin.copy 在使用委派时,只会将文件复制到委派的节点。(想要实现委派主机复制文件到其他节点可以使用 ansible.posix.synchronize

委派默认会将所有任务放在委派节点执行,但是有时我们只希望任务只执行一次(比方说只想通过 ansible.builtin.command 在某个节点执行一次命令),这时就需要使用 run_once,这个看下边。

只在某个节点执行一次命令

delegate_to 可以和 run_once 结合使用,以实现只在某个节点执行一次命令,看下边这个 YAML:

- name: test delegate_to
  hosts: all
  become: true
  gather_facts: false
  tasks:
  - name: file delegate to servera
    ansible.builtin.file:
      path: /tmp/hostlist
      state: touch
    delegate_to: servera
    run_once: true
  - name: lineinfile delegate to servera
    ansible.builtin.lineinfile:
      path: /tmp/hostlist
      line: "{{ inventory_hostname }}"
    delegate_to: servera
  - name: shell delegate to servera
    ansible.builtin.shell:
      cmd: "echo 'test kubeadm init' > /tmp/kubeadm.log"
    delegate_to: servera
    run_once: true

这里用 echo 'test kubeadm init' > /tmp/kubeadm.log 代替 K8S 初始化,这个命令只需要在第一个节点执行,其他节点就不需要执行了,所以添加了 run_once: true

在本地执行委派

如果要在控制节点执行委派任务,可以使用 local_action,它等效于 delegate_to: localhost

- name: file delegate to localhost
  ansible.builtin.file:
    path: /tmp/log
    state: touch
  delegate_to: localhost
  run_once: true
- name: lineinfile delegate to localhost
  ansible.builtin.lineinfile:
    path: /tmp/log
    line: "{{ inventory_hostname }}"
  delegate_to: localhost

# 上下效果一样

- name: file with local_action
  local_action:
    module: ansible.builtin.file
    path: /tmp/log
    state: touch
- name: lineinfile with local_action
  local_action: ansible.builtin.lineinfile path=/tmp/log line="{{ inventory_hostname }}"

# 上边这个也可以写成下边这个格式

- name: file with local_action
  local_action:
    module: ansible.builtin.file
    path: /tmp/log
    state: touch
- name: lineinfile with local_action
  local_action: 
    module: ansible.builtin.lineinfile
    path: /tmp/log
    line: "{{ inventory_hostname }}"

事实委派

事实委派可以将不在被执行范围内节点的 ansible_facts 输出给其他节点,举个例子:

下边这个 Playbook 只对 webserver 主机组执行任务,但是有个任务需要使用 dbserver 主机组中的变量,因为 dbserver 主机组不在执行范围内,默认情况下无法获取到 dbserver 组的事实变量,所以需要通过 delegate_facts: true 来将 dbserver 事实变量委派给 webserver 主机组。

- name: test delegate_facts
  hosts: webserver
  become: true
  gather_facts: true
  tasks:
  - name: file delegate to servera
    ansible.builtin.setup:
    delegate_to: "{{ item }}"
    delegate_facts: true
    loop: "{{ groups['dbserver'] }}"
  - name: print hostname from dbserver groups
    debug:
      var: hostvars['{{ item }}']['ansible_facts'].hostname
    loop: "{{ groups['dbserver'] }}"
  - name: print hostname with delegate
    debug:
      var: ansible_facts.hostname
    delegate_to: servera

默认情况下,anisble_facts.hostname 只会打印原本要被执行任务的节点的信息,比方说将 serverb 的任务委派给 servera,那么结果就是任务在 servera 执行,但是输出是 serverbanisble_facts.hostname,可以看下边的输出:

[root@study ansible]# ansible-playbook delegate_test.yml

PLAY [test delegate_facts] ****************************************************************************************************************************************

TASK [Gathering Facts] ********************************************************************************************************************************************
ok: [servera]
ok: [serverc]

TASK [file delegate to servera] ***********************************************************************************************************************************
ok: [serverc -> serverb] => (item=serverb)
ok: [servera -> serverb] => (item=serverb)

TASK [print hostname from dbserver groups] ************************************************************************************************************************
ok: [servera] => (item=serverb) => {
    "ansible_loop_var": "item",
    "hostvars['serverb']['ansible_facts'].hostname": "serverb",
    "item": "serverb"
}
ok: [serverc] => (item=serverb) => {
    "ansible_loop_var": "item",
    "hostvars['serverb']['ansible_facts'].hostname": "serverb",
    "item": "serverb"
}

TASK [print hostname with delegate] *******************************************************************************************************************************
ok: [servera] => {
    "ansible_facts.hostname": "servera"
}
ok: [serverc -> servera] => {
    "ansible_facts.hostname": "serverc"
}

PLAY RECAP ********************************************************************************************************************************************************
servera                    : ok=4    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
serverc                    : ok=4    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

所以如果想获取特定主机的变量,需要通过 hostvars[],比方说获取 serverb 的信息,可以写 hostvars['serverb']

Ansible 任务委派
https://www.linuxstudynotes.com/2025/07/24/ansible/ansible-%e4%bb%bb%e5%8a%a1%e5%a7%94%e6%b4%be/
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇