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 会自动创建必要的子目录结构(如artifacts、project等)。-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 生成的工件,了解了其结构化输出的优势。
📝 课后习题
为了巩固本课所学,请完成以下习题。只有全部正确才能解锁下一课哦!
- 选择题:Ansible Runner 的主要设计目标是什么? C
A. 提供比
ansible-playbook更快的执行速度 B. 让系统管理员更容易阅读 Playbook 输出 C. 为其他程序和自动化流程提供一个标准化的 Ansible 执行接口 D. 替代 Ansible,成为新的配置管理工具 - 简答题:简述 Ansible Runner 的“私有数据目录”是什么?它有什么作用?
- 私有数据目录是一个包含ansible runner执行所需的所有文件,用于隔离
- 实操题:
- 创建一个名为
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