Ansible Runner 简介
Runner 旨在作为自动化和工具的一部分最有帮助,这些自动化和工具需要调用 Ansible 并使用其结果。大多数 Ansible 命令行参数化也适用于 Runner 命令行,但 Runner 还可以依赖于映射到目录结构的输入接口,例如,源代码树 中所示。
本文档中的后续部分引用了该层次结构的配置和布局。这不是与 Runner 本身交互的唯一方式。Python 模块接口允许以多种形式将这些详细信息作为直接模块参数提供,而命令行接口允许将它们直接作为参数提供,模拟 ansible-playbook
的行为。拥有目录结构确实允许从其他地方收集输入并准备它们以供 Runner 使用,然后工具可以随之而来并在运行后检查结果。
这在 Ansible AWX 使用 Runner 的方式中最为明显,其中大多数内容来自数据库(以及其他内容管理组件),但最终需要在启动 Ansible 任务时集中到一个地方。
Runner 输入目录层次结构
该目录包含所有必要的输入。下面是 demo 目录 的视图,显示了活动配置。
请注意,并非所有内容都是必需的。如果未提供,将使用默认值或省略值。
.
├── env
│ ├── envvars
│ ├── extravars
│ ├── passwords
│ ├── cmdline
│ ├── settings
│ └── ssh_key
├── inventory
│ └── hosts
└── project
├── test.yml
└── roles
└── testrole
├── defaults
├── handlers
├── meta
├── README.md
├── tasks
├── tests
└── vars
The env
目录
env 目录包含设置和敏感文件,这些文件会通知 Ansible 进程调用的某些方面,例如,demo env 目录 中所示。这些文件中的每一个也可以由命名管道表示,从而提供额外的安全层。这些文件的格式和期望值略有不同,具体取决于它们所代表的内容。
env/envvars
注意
例如,请参阅 demo envvars。
Ansible Runner 将继承启动 shell 的环境。此文件(可以是 json 或 yaml 格式)表示将在运行时添加到环境中的环境变量。
---
TESTVAR: exampleval
env/extravars
注意
例如,请参阅 demo extravars。
Ansible Runner 收集此处提供的额外变量,并将它们提供给 Ansible 进程 本身。此文件可以是 json 或 yaml 格式。
---
ansible_connection: local
test: val
env/passwords
注意
例如,请参阅 demo passwords。
警告
我们希望此接口将来会更改/简化,但会保证向后兼容性。目标是让 Runner 的用户不必担心 Ansible 本身发出的某些提示的格式。特别是,Vault 密码需要变得更加灵活。
Ansible 本身被设置为向某些提示发出密码,这些提示可以被请求(例如 -k
用于提示输入连接密码)。同样,提示可以通过 vars_prompt 和 Ansible Vault 发出。
为了让 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 检测到提供私钥时,将在 ssh-agent 中包装对 Ansible 的调用。
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
环境变量进一步覆盖,以直接指定主机。为清单位置提供绝对路径是最佳实践,因为相对路径相对于 current working directory
解释,默认情况下为 project
目录。
项目
**Runner** project
目录是包含剧本和角色的剧本根目录,这些剧本可以直接使用这些角色。这也是在启动 **Ansible** 进程时将设置为 current working directory
的目录。
模块
**Runner** 能够使用 Ansible 的临时模式直接执行模块。
角色
**Runner** 能够直接执行 角色,无需首先需要剧本来引用它们。此目录包含为此使用的角色。在幕后,**Runner** 将生成一个剧本并调用 Role
。
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** 返回的标准输出,这非常有用,因为它包含比纯标准输出更多的详细信息和状态。它在为事件分配顺序方面做了很多工作,并将它们以 JSON 格式存储在 job_events
工件目录下。它还比普通的 **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 计数数据。
每个文件包含在剧本任务过程中收集的一组数据点。
如果任务执行速度很快,并且给定指标的轮询率足够高,则可能在任务执行期间不会收集任何分析数据。如果是这种情况,将不会创建任何数据文件。