课程三:深入功能模块 - 不止于 Playbook
欢迎来到第三课!在前两课中,我们掌握了 Ansible Runner 的核心概念和基本执行方式。你已经知道如何使用私有数据目录,以及如何用 run、start 等命令管理 Playbook 的执行。
但是,Ansible Runner 的能力远不止执行 Playbook。它还可以运行 Ad-Hoc 命令、直接调用角色、灵活管理清单,并为我们提供结构化的输出工件。本课我们将一一探索这些功能,让你能够用 Runner 完成更多类型的自动化任务。
3.1 运行 Ad-Hoc 命令
Ad-Hoc 命令是指直接使用 Ansible 模块执行临时任务,而不需要编写 Playbook。例如,你想快速检查所有主机的存活状态,或者批量重启服务。
在 ansible-runner 中,使用 -m 指定模块,-a 指定模块参数,--hosts 指定目标主机。
3.1.1 基本语法
css
ansible-runner run /path/to/private_data_dir -m <模块名> -a "<模块参数>" --hosts <主机模式>
-m:模块名称,如ansible.builtin.ping、ansible.builtin.shell。-a:模块参数,通常是字符串形式,例如"uptime"或"echo hello"。--hosts:指定要执行的主机模式,可以是all、webservers(组名)或具体主机名。
3.1.2 实操案例:执行 Ad-Hoc 命令
假设我们有一个私有数据目录 runner_adhoc,里面有一个简单的清单文件 inventory/hosts:
ini
[webservers]
web1 ansible_host=192.168.1.10
web2 ansible_host=192.168.1.11
[databases]
db1 ansible_host=192.168.1.20
我们想对所有 webservers 执行 uptime 命令。可以这样:
arduino
ansible-runner run runner_adhoc -m ansible.builtin.shell -a "uptime" --hosts webservers
Runner 会在每个目标主机上执行命令,并将结果记录在 artifacts 中。你同样可以通过 stdout 或 JSON 事件查看输出。
arduino
ansible-runner run . -m ansible.builtin.ping --hosts localhost
注意:这里私有数据目录是当前目录 .,其中可以没有清单文件 ,Runner 默认会包含 localhost。
3.1.3 使用场景
- 快速故障排查:执行
df -h、free -m等命令。 - 批量操作:在所有主机上安装某个包(如
yum install -y tree)。 - 测试连通性:
ping模块。
Ad-Hoc 命令非常适合集成到自动化平台的"一键执行"功能中。
3.2 运行 Ansible 角色
如果你已经将常用的自动化任务封装成了 Ansible 角色,可以直接通过 ansible-runner 运行角色,而无需编写 Playbook 来调用它。
3.2.1 基本语法
css
ansible-runner run /path/to/private_data_dir --role <角色名> --role-vars "<变量>"
--role:指定要运行的角色的名称。Runner 会在project/roles/目录下查找该角色。--role-vars:以 YAML/JSON 格式传递变量给角色,例如'{"package": "httpd", "state": "present"}'。
3.2.2 准备角色
我们需要在私有数据目录的 project/roles/ 下存放角色。假设我们有一个简单的角色 nginx,目录结构如下:
bash
runner_role_demo/
├── inventory/
│ └── hosts # 配置localhost
├── project/
│ └── roles/
│ └── nginx/
│ ├── tasks/
│ │ └── main.yml
│ └── vars/
│ └── main.yml
└── env/
tasks/main.yml 内容:
yaml
---
- name: 安装 nginx
ansible.builtin.package:
name: "{{ nginx_package }}"
state: present
- name: 启动 nginx
ansible.builtin.service:
name: "{{ nginx_service }}"
state: started
enabled: yes
vars/main.yml 可以定义默认变量,如 nginx_package: nginx、nginx_service: nginx。
3.2.3 实操案例:运行角色
在 runner_role_demo 目录下执行:
arduino
ansible-runner run . --role nginx --role-vars "nginx_package=nginx nginx_service=nginx"
Runner 会使用该角色对清单中的主机执行安装和启动任务。
3.2.4 注意事项
- 角色必须存放在
project/roles/下。 - 可以通过
--role-vars覆盖角色默认变量。 - 如果角色需要额外的文件(如
files/、templates/),也应放在角色目录下。
3.3 灵活的清单管理
Ansible Runner 支持多种方式指定清单:
- 通过私有数据目录中的
inventory/目录 :这是最常用的方式。可以在inventory/下放置静态文件、动态脚本或hosts文件。 - 通过命令行参数
--inventory:可以指定额外的清单文件或目录,这些清单会与私有数据目录中的清单合并。 - 通过环境变量 :在
env/envvars中设置ANSIBLE_INVENTORY。
3.3.1 实操案例:使用额外清单
假设我们有一个中央清单文件 /etc/ansible/hosts,里面定义了生产环境的所有主机。现在我们想针对其中的 test 组执行一个 Playbook,但不想复制整个清单到私有数据目录。可以使用 --inventory:
css
ansible-runner run . --role nginx --role-vars "nginx_package=nginx nginx_service=nginx"
--inventory /etc/ansible/hosts --hosts test
注意:--hosts 用于限制执行范围,可以与清单配合使用。
3.3.2 清单的动态脚本
如果使用动态清单脚本(如 AWS EC2、OpenStack 等),只需将脚本放在 inventory/ 目录下并赋予执行权限,Runner 会自动调用它。
3.4 深入理解输出工件
在第二课中,我们初步接触了 artifacts 目录。现在,让我们更深入地了解它的结构,以及如何利用这些数据。
一次执行的 artifacts/<uuid>/ 目录下通常包含:
job_events/:所有事件按顺序编号的 JSON 文件,例如1-<uuid>.json、2-<uuid>.json......stdout:可读的文本输出。status:最终状态,如successful、failed、timeout。rc:返回码(0 成功,非 0 失败)。facts(可选):如果 Playbook 开启了gather_facts,facts 会被存储在这里,可供后续执行复用。
3.4.1 事件类型
每个事件文件包含一个 JSON 对象,其中 event 字段标识事件类型,常见的有:
playbook_on_start:Playbook 开始。playbook_on_play_start:Play 开始。playbook_on_task_start:任务开始。runner_on_ok:任务在某主机上成功。runner_on_failed:任务在某主机上失败。playbook_on_stats:执行结束时的统计信
3.4.2 实操案例:解析事件数据
假设我们执行了一个 Playbook,想要找出所有失败的任务及其错误信息。可以编写一个简单的 Python 脚本,遍历 job_events 目录下的文件,筛选 event 为 runner_on_failed 的事件。
例如:
python
import os
import json
events_dir = "artifacts/<uuid>/job_events/"
for filename in os.listdir(events_dir):
with open(os.path.join(events_dir, filename)) as f:
event = json.load(f)
if event.get('event') == 'runner_on_failed':
print(f"Task failed on {event['host']}: {event['event_data']['res']['msg']}")
这种能力使得我们可以将 Ansible Runner 与监控系统、日志分析平台无缝集成。
3.4.3 使用 -j 参数
在命令行中,可以通过 -j 让 Runner 在终端输出 JSON 格式的摘要信息,便于脚本解析。例如:
arduino
my_third_runner# ansible-runner run . --role nginx -j | jq
输出会是一个 JSON,包含状态、事件数量等。
3.5 综合实操:构建一个多功能 Runner 调用脚本
为了巩固本课内容,我们来编写一个 Python 脚本,它能够根据用户输入,灵活地执行 Ad-Hoc 命令、Playbook 或角色,并解析输出。
脚本示例:runner_cli.py
python
import argparse
import ansible_runner
import json
def main():
parser = argparse.ArgumentParser(description='Ansible Runner 多功能调用')
parser.add_argument('--private-data-dir', required=True, help='私有数据目录路径')
parser.add_argument('--playbook', help='要执行的 Playbook 文件名')
parser.add_argument('--module', help='要执行的模块名')
parser.add_argument('--module-args', help='模块参数')
parser.add_argument('--hosts', default='all', help='目标主机模式')
parser.add_argument('--role', help='要执行的角色名')
parser.add_argument('--role-vars', help='角色变量 JSON 字符串')
args = parser.parse_args()
kwargs = {
'private_data_dir': args.private_data_dir,
'host_pattern': args.hosts,
}
if args.playbook:
kwargs['playbook'] = args.playbook
elif args.module:
kwargs['module'] = args.module
kwargs['module_args'] = args.module_args
elif args.role:
kwargs['role'] = args.role
if args.role_vars:
kwargs['role_vars'] = json.loads(args.role_vars)
else:
print("请指定 --playbook、--module 或 --role")
return
r = ansible_runner.run(**kwargs)
print(f"状态: {r.status}")
print(f"返回码: {r.rc}")
if r.status == 'successful':
print("执行成功!")
else:
print("执行失败,请查看工件目录获取详细信息。")
if __name__ == '__main__':
main()
注意:private-data-dir使用绝对路径
css
python runner_cli.py --private-data-dir /usr/local/src/py_projects/automatic/ansible-runner/tip3-深入功能模块/my_third_runner --role nginx --hosts localhost
也可以编写playbook,并指定playbook执行:
在 my_third_runner/project/ 下创建 site.yml:
yaml
---
- name: 应用 nginx 角色
hosts: all
roles:
- nginx
css
python runner_cli.py --private-data-dir my_third_runner --playbook site.yml --hosts localhost
否则,会提示:
makefile
ERROR! the playbook: my_third_runner/project/main.json could not be found
状态: failed
返回码: 1
执行失败,请查看工件目录获取详细信息。
为什么会出现 main.json 错误?
错误信息中的 main.json 是 Runner 尝试查找默认 playbook 时产生的。当你指定 --role 但缺少必要的目录结构时,Runner 会回退到默认行为,导致路径解析错误。
这个脚本展示了如何将本课所学整合到一个工具中。
3.6 小结
本课我们学习了:
- 如何运行 Ad-Hoc 命令,快速执行模块化任务。
- 如何直接运行 Ansible 角色,并传递变量。
- 多种清单指定方式,灵活适应不同环境。
- 深入解析输出工件,为集成监控、日志分析打下基础。
现在,你已经能够用 Runner 应对更多自动化场景了。下一课我们将深入 Python API,将 Runner 嵌入到自己的应用中,实现真正的"自动化引擎"。