Ansible Runner 简介
Runner 旨在作为自动化和工具的一部分,这些自动化和工具需要调用 Ansible 并使用其结果。大多数 Ansible 命令行的参数化在 Runner 命令行上也可用,但 Runner 也可以依赖于映射到目录结构的输入接口,例如,可以在 源代码树 中看到。
本文档中的后续部分将介绍该层次结构的配置和布局。这不是与 Runner 本身交互的唯一方法。Python 模块接口允许以多种形式将这些详细信息作为直接模块参数提供,而命令行接口允许将其直接作为参数提供,模仿 ansible-playbook
的行为。拥有目录结构确实允许从其他地方收集输入并准备供 Runner 使用,然后工具可以继续并在运行后检查结果。
这在 Ansible AWX 使用 Runner 的方式中得到了最好的体现,其中大部分内容来自数据库(以及其他内容管理组件),但在启动 Ansible 任务时最终需要在一个地方集中起来。
Runner 输入目录层次结构
此目录包含所有必要的输入。以下是 演示目录 的视图,显示了活动的配置。
请注意,并非所有内容都是必需的。如果未提供,将使用默认值或省略值。
.
├── env
│ ├── envvars
│ ├── extravars
│ ├── passwords
│ ├── cmdline
│ ├── settings
│ └── ssh_key
├── inventory
│ └── hosts
└── project
├── test.yml
└── roles
└── testrole
├── defaults
├── handlers
├── meta
├── README.md
├── tasks
├── tests
└── vars
env
目录
env 目录包含设置和敏感文件,这些文件会影响 Ansible 进程调用的某些方面,例如,可以在 演示 env 目录 中找到。每个文件也可以由命名管道表示,从而提供额外的安全层。这些文件的格式和预期略有不同,具体取决于它们表示的内容。
env/envvars
注意
有关示例,请参见 演示 envvars。
Ansible Runner 将继承启动 shell 的环境。此文件(可以是 json 或 yaml 格式)表示将在运行时添加到环境的环境变量。
---
TESTVAR: exampleval
env/extravars
注意
有关示例,请参见 演示 extravars。
Ansible Runner 收集此处提供的额外变量,并将其提供给 Ansible 进程本身。此文件可以是 json 或 yaml 格式。
---
ansible_connection: local
test: val
env/passwords
注意
有关示例,请参见 演示 passwords。
警告
我们预计此接口将在未来发生变化/简化,但将保证向后兼容性。目标是让 Runner 的用户不必担心 Ansible 本身发出的某些提示的格式。特别是,保管库密码需要变得更加灵活。
Ansible 本身被设置为将密码发送到某些提示,这些提示可以被请求(例如,-k
用于提示连接密码)。同样,可以通过 vars_prompt 以及 Ansible 保管库 发出提示。
为了使 Runner 能用正确的密码进行响应,它需要能够匹配提示并提供正确的密码。目前支持通过提供一个 yaml 或 json 格式的文件来实现,该文件包含一个正则表达式和一个要发出的值,例如
---
"^SSH password:\\s*?$": "some_password"
"^BECOME password.*:\\s*?$": "become_password"
env/cmdline
警告
当前 Ansible Runner 不会验证使用此方法传递的命令行参数,因此由剧本编写者提供一组有效的选项。通过此方法提供的命令行选项的优先级低于 Ansible Runner 设置的选项。例如,这不会覆盖 inventory
或 limit
值。
Ansible Runner 收集此处提供的命令行选项作为字符串,并将其提供给 Ansible 进程本身。此文件应包含要添加的参数,例如
--tags one,two --skip-tags three -u ansible --become
env/ssh_key
注意
目前只能通过此机制提供单个 ssh 密钥,但这将 很快发生变化。
此文件应包含用于连接到主机(s)的 ssh 私钥。Runner 检测到何时提供了私钥,并将对 Ansible 的调用包装在 ssh-agent 中。
env/settings
- Runner 自身设置
settings 文件与此部分中提供的其他文件略有不同,因为其内容旨在直接控制 Runner。
idle_timeout
:600
如果在这么多秒内未检测到来自 ansible 的输出,则将终止执行。job_timeout
:3600
允许作业运行的最长时间,超过此时间,将终止执行。pexpect_timeout
:10
内部 pexpect 命令在继续之前等待阻塞输入的秒数。pexpect_use_poll
:True
使用poll()
函数与子进程通信,而不是select()
。当值为False
时使用select()
。select()
具有已知的限制,即仅使用最多 1024 个文件描述符。suppress_output_file
:False
允许 ansible 的输出不会流式传输到工件目录内的stdout
或stderr
文件。suppress_ansible_output
:False
允许 ansible 的输出不会打印到屏幕上。fact_cache
:'fact_cache'
相对于artifacts
的目录,其中将存储jsonfile
事实缓存。默认为fact_cache
。如果fact_cache_type
不同于jsonfile
,则忽略此项。fact_cache_type
:'jsonfile'
要使用的事实缓存类型。默认为jsonfile
。
Runner 的进程隔离设置
进程隔离设置旨在控制 Runner 的进程隔离功能。
process_isolation
:False
启用限制剧本运行可以访问的文件系统上的目录。process_isolation_executable
:bwrap
将用于提供文件系统隔离的可执行文件的路径。process_isolation_path
:/tmp
隔离的剧本运行将用于暂存的路径。process_isolation_hide_paths
:None
系统上应从剧本运行中隐藏的路径或路径列表。process_isolation_show_paths
:None
系统上应公开给剧本运行的路径或路径列表。process_isolation_ro_paths
:None
系统上应以只读方式公开给剧本运行的路径或路径列表。
这些设置指示 **Runner** 在容器环境中执行 **Ansible** 任务。有关构建执行环境的信息,请参阅 ansible-builder。
要使用执行环境执行 **Runner**
ansible-runner run --container-image my-execution-environment:latest --process-isolation -p playbook.yml .
有关其他与容器相关的选项,请参阅 ansible-runner -h
。
清单
私有数据目录下的 **Runner** inventory
位置与直接提供给 ansible 本身的清单具有相同的期望。它可以是单个文件或脚本,也可以是包含静态清单文件或脚本的目录。此清单在调用时会自动加载并提供给 **Ansible**,并且可以在命令行或通过 ANSIBLE_INVENTORY
环境变量进一步覆盖以直接指定主机。为清单位置提供绝对路径是最佳实践,因为相对路径相对于 当前工作目录
解释,默认为 项目
目录。
项目
**Runner** project
目录是包含剧本和这些剧本可以直接使用的角色的剧本根目录。这也是在启动 **Ansible** 进程时将设置为 当前工作目录
的目录。
模块
**Runner** 能够使用 Ansible 特设模式直接执行模块。
角色
**Runner** 能够直接执行 角色,而无需首先需要剧本来引用它们。此目录保存用于此目的的角色。在幕后,**Runner** 将生成一个剧本并调用 角色
。
Runner 工件目录层次结构
此目录将包含 **Runner** 调用结果,这些结果分组在 identifier
目录下。此标识符可以直接提供给 **Runner**,如果未提供,则会生成一个标识符作为 UUID。这就是目录结构从顶层开始的样子
.
├── artifacts
│ └── identifier
├── env
├── inventory
├── profiling_data
├── project
└── roles
工件目录本身包含一个特定的结构,该结构提供了来自 Ansible/Runner 正在运行或先前运行调用的许多额外详细信息
.
├── artifacts
│ └── 37f639a3-1f4f-4acb-abee-ea1898013a25
│ ├── fact_cache
│ │ └── localhost
│ ├── job_events
│ │ ├── 1-34437b34-addd-45ae-819a-4d8c9711e191.json
│ │ ├── 2-8c164553-8573-b1e0-76e1-000000000006.json
│ │ ├── 3-8c164553-8573-b1e0-76e1-00000000000d.json
│ │ ├── 4-f16be0cd-99e1-4568-a599-546ab80b2799.json
│ │ ├── 5-8c164553-8573-b1e0-76e1-000000000008.json
│ │ ├── 6-981fd563-ec25-45cb-84f6-e9dc4e6449cb.json
│ │ └── 7-01c7090a-e202-4fb4-9ac7-079965729c86.json
│ ├── rc
│ ├── status
│ └── stdout
**rc** 文件包含 **Ansible** 进程的实际返回代码。
**status** 文件包含三个适合显示的状态之一
success: **Ansible** 进程成功完成
failed: **Ansible** 进程失败
timeout: **Runner** 超时(请参阅 env/settings - Runner 本身设置)
**stdout** 文件包含此时显示的实际标准输出。
Runner 工件作业事件(主机和剧本事件)
**Runner** 收集作为 **Ansible** 运行的一部分发出的单个任务和剧本事件。如果您不想处理或读取从 **Ansible** 返回的标准输出,这非常有用,因为它包含比普通标准输出更多的详细信息和状态。它承担了一些将顺序分配给事件的繁重工作,并将它们存储在 job_events
工件目录下的 json 格式中。它还比普通的 **Ansible** 回调插件更进一步,因为它会将与事件关联的 stdout
与原始事件数据一起存储(以及标准输出行号)。它还为没有相应主机事件数据的标准输出生成虚拟事件
{
"uuid": "8c164553-8573-b1e0-76e1-000000000008",
"parent_uuid": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"counter": 5,
"stdout": "\r\nTASK [debug] *******************************************************************",
"start_line": 5,
"end_line": 7,
"event": "playbook_on_task_start",
"event_data": {
"playbook": "test.yml",
"playbook_uuid": "34437b34-addd-45ae-819a-4d8c9711e191",
"play": "all",
"play_uuid": "8c164553-8573-b1e0-76e1-000000000006",
"play_pattern": "all",
"task": "debug",
"task_uuid": "8c164553-8573-b1e0-76e1-000000000008",
"task_action": "debug",
"task_path": "\/home\/mjones\/ansible\/ansible-runner\/demo\/project\/test.yml:3",
"task_args": "msg=Test!",
"name": "debug",
"is_conditional": false,
"pid": 10640
},
"pid": 10640,
"created": "2018-06-07T14:54:58.410605"
}
如果剧本运行完成而没有被终止,则最后一个事件将始终是 stats
事件
{
"uuid": "01c7090a-e202-4fb4-9ac7-079965729c86",
"counter": 7,
"stdout": "\r\nPLAY RECAP *********************************************************************\r\n\u001b[0;32mlocalhost,\u001b[0m : \u001b[0;32mok=2 \u001b[0m changed=0 unreachable=0 failed=0 \r\n",
"start_line": 10,
"end_line": 14,
"event": "playbook_on_stats",
"event_data": {
"playbook": "test.yml",
"playbook_uuid": "34437b34-addd-45ae-819a-4d8c9711e191",
"changed": {
},
"dark": {
},
"failures": {
},
"ok": {
"localhost,": 2
},
"processed": {
"localhost,": 1
},
"skipped": {
},
"artifact_data": {
},
"pid": 10640
},
"pid": 10640,
"created": "2018-06-07T14:54:58.424603"
}
注意
**Runner 模块接口** 提供了这些事件的编程接口,允许获取最终状态并执行任务事件的主机过滤。
Runner 分析数据目录
如果为 **Runner** 启用了资源分析,则 profiling_data
目录将填充一组包含分析数据的文件
.
├── profiling_data
│ ├── 0-34437b34-addd-45ae-819a-4d8c9711e191-cpu.json
│ ├── 0-34437b34-addd-45ae-819a-4d8c9711e191-memory.json
│ ├── 0-34437b34-addd-45ae-819a-4d8c9711e191-pids.json
│ ├── 1-8c164553-8573-b1e0-76e1-000000000006-cpu.json
│ ├── 1-8c164553-8573-b1e0-76e1-000000000006-memory.json
│ └── 1-8c164553-8573-b1e0-76e1-000000000006-pids.json
每个文件都采用 JSON 文本格式。文件的每一行都将以记录分隔符 (RS) 开头,后跟 JSON 字典,最后以换行符 (LF) 结尾。以下提供了资源文件可能是什么样子的示例。请注意,由于 RS 和 LF 是控制字符,因此它们实际上并未在下面打印
==> 0-525400c9-c704-29a6-4107-00000000000c-cpu.json <==
{"timestamp": 1568977988.6844425, "task_name": "Gathering Facts", "task_uuid": "525400c9-c704-29a6-4107-00000000000c", "value": 97.12799768097156}
{"timestamp": 1568977988.9394386, "task_name": "Gathering Facts", "task_uuid": "525400c9-c704-29a6-4107-00000000000c", "value": 94.17538298892688}
{"timestamp": 1568977989.1901696, "task_name": "Gathering Facts", "task_uuid": "525400c9-c704-29a6-4107-00000000000c", "value": 64.38272588006255}
{"timestamp": 1568977989.4594045, "task_name": "Gathering Facts", "task_uuid": "525400c9-c704-29a6-4107-00000000000c", "value": 83.77387744259856}
==> 0-525400c9-c704-29a6-4107-00000000000c-memory.json <==
{"timestamp": 1568977988.4281094, "task_name": "Gathering Facts", "task_uuid": "525400c9-c704-29a6-4107-00000000000c", "value": 36.21484375}
{"timestamp": 1568977988.6842303, "task_name": "Gathering Facts", "task_uuid": "525400c9-c704-29a6-4107-00000000000c", "value": 57.87109375}
{"timestamp": 1568977988.939303, "task_name": "Gathering Facts", "task_uuid": "525400c9-c704-29a6-4107-00000000000c", "value": 66.60546875}
{"timestamp": 1568977989.1900482, "task_name": "Gathering Facts", "task_uuid": "525400c9-c704-29a6-4107-00000000000c", "value": 71.4609375}
{"timestamp": 1568977989.4592078, "task_name": "Gathering Facts", "task_uuid": "525400c9-c704-29a6-4107-00000000000c", "value": 38.25390625}
==> 0-525400c9-c704-29a6-4107-00000000000c-pids.json <==
{"timestamp": 1568977988.4284189, "task_name": "Gathering Facts", "task_uuid": "525400c9-c704-29a6-4107-00000000000c", "value": 5}
{"timestamp": 1568977988.6845856, "task_name": "Gathering Facts", "task_uuid": "525400c9-c704-29a6-4107-00000000000c", "value": 6}
{"timestamp": 1568977988.939547, "task_name": "Gathering Facts", "task_uuid": "525400c9-c704-29a6-4107-00000000000c", "value": 8}
{"timestamp": 1568977989.1902773, "task_name": "Gathering Facts", "task_uuid": "525400c9-c704-29a6-4107-00000000000c", "value": 13}
{"timestamp": 1568977989.4593227, "task_name": "Gathering Facts", "task_uuid": "525400c9-c704-29a6-4107-00000000000c", "value": 6}
资源分析数据按剧本任务分组。
对于每个任务,将有三个文件,分别对应于 cpu、内存和 pid 计数数据。
每个文件包含在剧本任务过程中收集的一组数据点。
如果任务执行速度很快,并且给定指标的轮询率足够大,则可能在任务执行期间不会收集任何分析数据。如果是这种情况,则不会创建任何数据文件。