1_【自动化引擎】初识Ansible Runner

7 阅读8分钟

1.1 什么是 Ansible Runner?

Ansible Runner 是一个 工具Python 库

  • 提供稳定、可复用的接口:与ansible交互;
  • 自动化执行引擎

Ansible和ansible-runner对比

  • Ansible本身是面向人类用户设计,输出是给人类阅读的彩色文本;
  • Ansible-runner面向程序和自动化流程设计的,输入输出都是结构化,便于被其他系统(如 CI/CD 工具、云平台、监控系统)集成;

1.2 为什么需要 Ansible Runner?

假设你正在开发一个自动化平台(例如一个自服务运维门户),用户通过 Web 界面点击“部署应用”,然后你需要在后端调用 Ansible Playbook 来完成部署。

  • 使用 ansible-playbook 的问题:
    • 输出难以解析:你需要捕获控制台输出,然后用正则表达式去匹配成功或失败,非常脆弱。
    • 状态管理困难:Playbook 可能执行很长时间,你需要跟踪它的状态(运行中、成功、失败),但 ansible-playbook 本身不提供这种状态管理。
    • 环境隔离麻烦:多个任务同时执行时,可能会互相干扰(比如修改了同一个配置文件)。
    • 缺少标准化事件:你不知道 Playbook 执行到哪一步了,每个任务的结果是什么。
  • 使用 Ansible Runner 的好处:
    • 标准化输出:执行过程中产生的所有事件(任务开始、任务完成、主机失败等)都会被保存为 JSON 文件,可以轻松解析。
    • 异步执行管理:你可以将 Playbook 放到后台执行,并随时查询其状态,甚至取消它。
    • 私有数据目录:Runner 会为每次执行创建一个私有数据目录,里面包含了该次执行需要的 Playbook、清单、变量以及生成的日志和工件,天然实现了隔离。
    • Python API:你可以通过 Python 代码直接调用 Runner,并实时处理执行过程中的事件。

1.3 与传统 Ansible 使用方式的区别

特性ansible-playbook 命令ansible-runner 命令 / Python API
目标用户系统管理员(人类)应用程序、自动化脚本(程序)
输出格式彩色控制台文本,适合阅读JSON 事件,便于解析
执行模式前台阻塞执行支持前台、后台、异步等多种模式
状态跟踪需手动管理进程 ID内置状态管理,可查询
环境隔离共享当前工作目录,易冲突私有数据目录,天然隔离
扩展性通过回调插件,但较复杂提供简单的 Python 回调接口

简单来说:ansible-playbook 是手工工具,ansible-runner 是自动化引擎

1.4 环境搭建

Python 3.8 或更高版本

1.4.1 配置虚拟环境

# 创建虚拟环境
python3 -mvenv py3.8
source py3.8/bin/activate

# 安装direnv
 apt-get install direnv
 
 # 配置环境变量
 echo 'eval "$(direnv hook bash)"' >> ~/.bashrc
 source ~/.bashrc
 
 # 进入目录运行,会创建.envrc文件
 direnv allow
 
 # 写入激活虚拟环境的指令
 # .envrc
use virtualenv py3.8 # 这条指令会寻找当前目录下的 py3.8 文件夹,并自动执行 source py3.8/bin/activate。

# 或者 .envrc
source py3.8/bin/activate # 这种方式更直接,但 use virtualenv 的方式更规范,因为它还会处理一些环境清理的工作。

1.4.2 安装ansible-runner

# 配置虚拟环境
pip3 install ansible-runner

# 验证
ansible-runner --version
2.4.3

1.5 第一个实操案例:探索 Ansible Runner 命令

重点关注 run 命令,它是我们执行 Playbook 的主要方式:

ansible-runner run --help

这里你会看到很多参数,比如 --playbook--inventory--hosts 等。不要被吓到,我们接下来会一步步使用它们。

1.6 第二个实操案例:编写一个简单的 Playbook 并用 Runner 执行

为了感受 Runner 的执行流程,我们创建一个最简单的 Playbook,然后用 Runner 运行它。

首先,创建一个工作目录,例如 runner-lab,并进入该目录:

mkdir runner-lab
cd runner-lab

创建一个名为 test.yml 的 Playbook 文件:

---
- name: 测试 Playbook
  hosts: localhost
  gather_facts: no
  tasks:
    - name: 打印一条消息
      ansible.builtin.debug:
        msg: "Hello, Ansible Runner!"

现在,用 Runner 来执行它。注意:Runner 需要一个私有数据目录,但我们暂时不手动创建,而是让 Runner 自动生成。使用以下命令:

ansible-runner run . -p test.yml

解释一下:

  • run:告诉 Runner 我们要执行一个任务。
  • .:指定私有数据目录的路径。这里我们使用当前目录,Runner 会自动创建必要的子目录结构(如 artifactsproject 等)。
  • -p test.yml:指定要运行的 Playbook 文件

你会看到类似下面的输出:

PLAY [测试 Playbook] ***********************************************************

TASK [打印一条消息] ***********************************************************
ok: [localhost] => {
    "msg": "Hello, Ansible Runner!"
}

PLAY RECAP *********************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

看到了吗?Runner 成功地执行了 Playbook,并在控制台输出了 Ansible 的标准输出。这看起来和直接用 ansible-playbook test.yml 没什么区别?别急,真正的魔法在于 Runner 生成的工件

1.7 深入理解:查看 Runner 生成的工件

在刚才的命令中,我们指定当前目录 . 为私有数据目录。执行后,Runner 会在当前目录下创建一个名为 artifacts 的目录,里面存放了本次执行的所有输出数据。让我们来看看:

ls -l artifacts/

你应该会看到一个以UUID命名的目录,这是本次执行的唯一标识。进入该目录:

artifacts# cd aac9d8b0-6686-4305-91d2-45f83a2e9ac0/
# 文件结构:
job_events/
stdout
stderr
status
rc
  • job_events/:这是一个目录,里面包含了 Playbook 执行过程中产生的每一个事件的 JSON 文件。每个任务开始、结束、每个主机的结果,都会被记录为一个独立的事件文件。这些文件是按时间顺序编号的。
  • stdout:这是 Playbook 执行的标准输出文本,和你刚才在终端看到的完全一样。
  • stderr:这是 Playbook 执行的错误出文本,如果执行出错会记录在此处。
  • status:一个文本文件,记录了 Playbook 的最终状态,例如 successful
  • rc:返回码,0 表示成功,非 0 表示失败。

现在,我们来查看一下事件文件。进入 job_events 目录,查看一个事件文件:

9d8b0-6686-4305-91d2-45f83a2e9ac0/job_events# cat 5-000c293a-cf94-77ed-1f98-000000000001.json | jq
{
  "uuid": "000c293a-cf94-77ed-1f98-000000000001",
  "counter": 5,
  "stdout": "\r\nPLAY [测试 Playbook] ***********************************************************",
  "start_line": 3,
  "end_line": 5,
  "runner_ident": "aac9d8b0-6686-4305-91d2-45f83a2e9ac0",
  "event": "playbook_on_play_start",
  "pid": 13814,
  "created": "2026-03-17T12:46:21.243991+00:00",
  "parent_uuid": "c27f2be9-e61d-49db-a8c5-42d5f170a22b",
  "event_data": {
    "playbook": "test.yml",
    "playbook_uuid": "c27f2be9-e61d-49db-a8c5-42d5f170a22b",
    "play": "测试 Playbook",
    "play_uuid": "000c293a-cf94-77ed-1f98-000000000001",
    "play_pattern": "localhost",
    "name": "测试 Playbook",
    "pattern": "localhost",
    "uuid": "000c293a-cf94-77ed-1f98-000000000001"
  }
}

你会看到一个 JSON 对象,包含了该事件的详细信息,如事件名称(event)、任务名称、主机、结果等。这正是 Runner 提供给程序消费的结构化数据。

1.8 小结

在这一课中,我们学习了:

  • Ansible Runner 是一个自动化执行引擎,为程序集成 Ansible 而生。
  • 它的核心价值在于标准化输出、异步管理、环境隔离和编程友好。
  • 我们安装了 Runner 并运行了第一个 Playbook。
  • 我们初步探索了 Runner 生成的工件,了解了其结构化输出的优势。

📝 课后习题

为了巩固本课所学,请完成以下习题。只有全部正确才能解锁下一课哦!

  1. 选择题:Ansible Runner 的主要设计目标是什么? C A. 提供比 ansible-playbook 更快的执行速度 B. 让系统管理员更容易阅读 Playbook 输出 C. 为其他程序和自动化流程提供一个标准化的 Ansible 执行接口 D. 替代 Ansible,成为新的配置管理工具
  2. 简答题:简述 Ansible Runner 的“私有数据目录”是什么?它有什么作用?
    • 私有数据目录是一个包含ansible runner执行所需的所有文件,用于隔离
  3. 实操题
    • 创建一个名为 my_first_runner 的目录。
    • 在该目录下,编写一个 Playbook hello.yml,内容为向本机 localhost 发送一条 ping 消息(使用 ansible.builtin.ping 模块)。
    • 使用 ansible-runner run 命令执行该 Playbook。
    • 执行成功后,进入 artifacts 目录,找到本次执行的 job_events 文件夹,查看其中一个事件文件的内容,并找到 ping 模块返回的 pong 消息在 JSON 中的位置。(提示:查找 "pong"
ansible-runner run . -p  hello.yml

---
- name: "My first runner: ping"
  hosts: localhost
  gather_facts: no
  tasks:
  - name: ping 
    ansible.builtin.ping:

    "task": "ping",
    "task_uuid": "000c293a-cf94-0c14-73e4-000000000003",
    "task_action": "ansible.builtin.ping",
    "resolved_action": "ansible.builtin.ping",
    "task_args": "",
    "task_path": "/usr/local/src/py_projects/automatic/ansible-runner/tip1-初始ansible-runner/my_first_runner/hello.yml:6",
    "host": "localhost",
    "remote_addr": "127.0.0.1",
    "res": {
      "ping": "pong",
      "invocation": {
        "module_args": {
          "data": "pong"
        }
      },
      "_ansible_no_log": false,
      "changed": false