1. 概述

Ansible 是一个强大的自动化工具,主要用于在远程主机上执行任务。但在某些场景下,我们也需要在 Ansible 控制器(即运行 Ansible 的主机)上执行命令。

通常,我们称这台机器为 localhost。本文将介绍几种在 Ansible 控制器上执行命令的方法。要完成本教程,建议先搭建一个基础实验环境

2. 本地执行命令的典型用途

在 Ansible 控制器上执行命令有多种常见用途,例如:

  • 创建目录用于备份
  • 下载配置模板
  • 执行本地 shell 脚本,比如部署前的准备脚本

这些只是常见场景,实际使用中还可能根据需求扩展。

3. 在本地执行命令的方式

Ansible 提供了多种方式直接在控制器主机上执行命令:

  • 使用 connection 关键字
  • 使用 local_action 模块
  • 使用 delegate_to 关键字
  • 使用 Ansible ad-hoc 命令
  • 使用 Ansible Inventory 配置

接下来我们逐一介绍这些方法。

4. 使用 connection 插件

Ansible 提供了多种 connection 插件,其中一种是 ansible.builtin.local,简称 local。这个插件允许在控制器上执行任务,且无需建立 SSH 连接,因此执行速度较快。

4.1. 在 Playbook 中配置连接方式

我们可以在 Playbook 中通过 connection: local 指定使用本地连接,可以作用于整个 Playbook,也可以作用于单个 Task。

以下是一个获取系统 uptime 的 Playbook 示例:

---
- name: 获取系统运行时间
  hosts: localhost
  connection: local
  tasks:
    - name: 打印 uptime
      command: uptime
      register: "output"
    - debug: var=output.stdout

执行这个 Playbook 会输出控制器的系统运行时间:

$ ansible-playbook connection.yaml 
...
TASK [debug] *************************************************
ok: [localhost] => {
    "output.stdout": " 07:06:39 up 16 min,  1 user,  load average: 0.19, 0.06, 0.03"
}
...

4.2. 通过命令行指定连接方式

也可以不在 Playbook 中写 connection: local,而是通过命令行参数 --connection=local 来指定:

$ ansible-playbook connection.yaml --connection=local

这样也能实现本地执行的效果,输出内容与上面一致。

⚠️ 注意:如果不指定 inventory 文件,Ansible 会提示 provided hosts list is empty 的警告。可以通过添加 inventory 文件来避免这个问题。

5. 使用 Ansible Inventory 文件

我们可以通过 Inventory 文件定义 localhost 的别名,从而在 Playbook 中引用。

例如,创建一个 inventory.ini 文件:

controller ansible_connection=local

然后修改 Playbook:

---
- name: 获取系统运行时间
  hosts: controller
  tasks:
    - name: 打印 uptime
      command: uptime
      register: "output"
    - debug: var=output.stdout

执行时带上 inventory 文件:

$ ansible-playbook inventory_demo.yaml -i inventory.ini

这样就能在控制器上执行命令,并避免警告信息。

6. 使用 delegate_to 关键字

delegate_to 用于将任务委托给特定主机执行,包括控制器本身。这在需要从多个主机上下文中执行本地操作时非常有用。

例如,从所有主机中复制文件到控制器:

---
- name: 将文件复制到本地
  hosts: all
  tasks:
    - name: 本地复制文件
      copy:
        src: /home/vagrant/abc.txt
        dest: /home/vagrant/ansible/
      delegate_to: localhost
      register: copy_result
    - name: 显示复制结果
      debug:
        var: copy_result

执行后,只有控制器上完成了文件复制,其他主机跳过该任务。

7. 使用 local_action 模块

local_actiondelegate_to: localhost 的简化写法,更简洁明了。

以下是一个使用 local_action 的 Playbook 示例:

---
- name: 使用 local_action 复制文件
  hosts: all
  tasks:
    - name: 打印 uptime
      command: uptime
      register: "uptime_result"
    - debug: var=uptime_result.stdout
    - name: 本地复制文件
      local_action: copy src=/home/vagrant/abc.txt dest=/home/vagrant/ansible/
      register: "copy_result"
    - name: 显示复制结果
      debug:
        var: copy_result
      when: inventory_hostname == 'localhost'

执行后,uptime 会在所有主机上运行,但复制操作只在控制器上执行。

8. 使用 Ansible Ad-hoc 命令

Ansible 也支持通过 ad-hoc 命令在控制器上执行操作。

例如,使用 shell 模块打印信息:

$ ansible localhost -c local -m shell -a 'echo abc abc'
localhost | CHANGED | rc=0 >>
abc abc

也可以使用 IP 地址:

$ ansible 127.0.0.1 -c local -m shell -a 'echo abc abc'
127.0.0.1 | CHANGED | rc=0 >> abc abc

如果在 inventory 文件中将 127.0.0.1 定义为 controller,也可以这样执行:

$ ansible controller -c local -m shell -a 'echo abc abc' -i inventory.ini

✅ 小贴士:使用 ad-hoc 命令时,-i 参数用于指定 inventory 文件。

9. 总结

本文介绍了在 Ansible 控制器上执行命令的多种方式:

方法 说明
connection: local 在 Playbook 中指定本地连接方式
local_action 简化本地执行命令的写法
delegate_to 将任务委托给本地执行,适用于多主机场景
Ansible Inventory 通过 inventory 文件定义本地主机
Ad-hoc 命令 快速执行本地命令

通过这些方法,你可以灵活地在 Ansible Playbook 或命令行中控制本地和远程任务的执行,提高自动化效率。


原始标题:Run a Command on Ansible Host