RHCE 学习笔记(二):变量、流程控制、Jinja2、角色、Vault 与 Navigator

学习红帽课程中的一些笔记,本系列共 2 篇,这是第 2 篇。

ansible 的变量

列表与字典的概念

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
users:                          <--- 【变量名】指向整个列表

- name: bob <--- 【列表中的元素 1】(一个字典)
job: developer ├── 键: "name" -> 值: "bob"
uid: 1101 ├── 键: "job" -> 值: "developer"
└── 键: "uid" -> 值: 1101

- name: sally <--- 【列表中的元素 2】(一个字典)
job: manager ├── 键: "name" -> 值: "sally"
uid: 1102 ├── 键: "job" -> 值: "manager"
└── 键: "uid" -> 值: 1102

- name: fred <--- 【列表中的元素 3】(一个字典)
job: developer ├── 键: "name" -> 值: "fred"
uid: 1103 ├── 键: "job" -> 值: "developer"
└── 键: "uid" -> 值: 1103

定义变量的方式

类别 定义方式 / 位置 典型语法 / 示例 作用域与特点 优先级排序
1. 命令行变量 Extra Vars (外部变量) ansible-playbook site.yml -e "http_port=8080"
或 -e "@vars.yml"
全局生效。优先级最高(Level 22),可覆盖其他所有位置定义的同名变量。 最高 (1)
2. Playbook 级变量 vars 关键字 hosts: webservers
vars:
   http_port: 80
Play 内部生效。在 Playbook 顶层显式定义,直观易读。 中 (4)
vars_files 外部文件 hosts: webservers
vars_files:
   - vars/web.yml
Play 内部生效。将变量解耦写在单独的 YAML 文件中,适合多变量管理。 中 (4)
vars_prompt 交互式输入 vars_prompt:
   - name: db_password
      prompt: "Enter DB password"
Play 内部生效。运行时在终端弹窗提示人工手动输入(常用于敏感密码)。 中 (4)
3. Inventory 清单变量 主机变量 (Host Vars) 清单文件 hosts 中:
web01.example.com http_port=8080
或创建文件 host_vars/web01.yml
单台主机生效。针对具体节点单独设置(如某台节点的特有端口或 IP)。 低 (6)
组变量 (Group Vars) 清单文件 hosts 中:
[web:vars]
http_port=80
或 group_vars/web.yml
特定主机组生效。对整个组内的所有主机生效(如 web 组统一使用 80 端口)。 低 (7)
4. Role (角色) 变量 vars/main.yml Role 目录结构下的 vars/main.yml Role 内部生效。随 Role 调用的高优先级变量,通常存放不希望被用户随意覆盖的内部变量。 中上 (3)
defaults/main.yml Role 目录结构下的 defaults/main.yml Role 内部生效。优先级最低(Level 2),作为 Role 的默认兜底值,非常方便调用者二次覆盖。 最低 (8)
5. Task (任务) 级变量 vars 关键字 - name: Install pkg
   dnf: name={{ pkg }}
   vars:
      pkg: nginx
仅当前 Task 生效。作用域极小,专门服务于单个任务。 高 (2)
register 注册变量 - name: Check file
   command: cat /etc/issue
   register: issue_out
后续 Tasks 全局生效。捕获上游 Task 的运行返回结果(包含 stdout, rc, changed 等)。 高 (2)
6. 系统自动采集 Facts 变量 {{ ansible_facts['default_ipv4']['address'] }}
或 {{ ansible_distribution }}
全局生效。由 setup 模块自动在受控节点采集(如操作系统版本、网卡 IP、内存等)。 特殊 (预定义)

fact var 事实变量

收集与查看

用于探知、查看受控节点的系统客观状态,以及控制剧本执行时的采集行为。

操作类型 核心命令 / 语法位置 代码示例 说明与最佳实践
命令行查看全量 Fact Ad-hoc setup 模块 ansible node1 -m setup 连接目标主机,实时收集并打印结构化的全量 JSON 格式系统信息。
命令行过滤特定 Fact Ad-hoc setup 模块 + filter ansible node1 -m setup -a "filter=ansible_default_ipv4"
ansible node1 -m setup -a "filter=ansible_distribution*"
使用通配符对返回结果进行精准筛选,避免全量输出刷屏,常用于调试或排查变量名。
Playbook 自动采集 (默认) Play 顶层 gather_facts - hosts: webservers
   gather_facts: true
Play 运行的第 1 步自动执行 setup 模块。如果 Task 或 Template 中需要使用系统变量,必须保证此选项为 true。
关闭采集以提升性能 Play 顶层 gather_facts - hosts: webservers
   gather_facts: false
如果剧本纯粹用于执行命令、复制文件等不依赖系统变量的任务,置为 false 可省去连接采集过程,显著提升执行速度。
剧本中途手动重新采集 Task 模块 setup - name: Re-gather facts after network change
   setup:
如果前面的 Task 修改了系统配置(如修改了主机名或配置了网卡 IP),可在 Task 中显式调用 setup 刷新 Fact 字典。

set_fact 模块

用于在 Playbook 执行过程中,将计算好的值、拼接的字符串或 Task 返回值即时固化为新的 Fact 变量。

功能/特性 语法结构 代码示例 关键注意事项
基础变量定义 set_fact:
   <var_name>: <value>
- name: Set environment fact
   set_fact:
      app_env: "production"
定义的变量会直接注入当前主机的 Fact 字典中,作用域为当前主机后续的所有 Tasks。
结合现有 Fact 组合新变量 配合 Jinja2 表达式 - name: Build custom node ID
   set_fact:
      node_id: "{{ ansible_hostname }}-{{ ansible_default_ipv4.address }}"
相比在 vars 中定义,set_fact 会在当前 Task 执行的瞬间进行即时求值并固化,后续调用时不会重复计算。
配合条件判断 (when) set_fact + when - name: Set package name based on OS
   set_fact:
      web_pkg: "httpd"
   when: ansible_os_family == "RedHat"
极适合根据受控节点的系统差异(如 OS 家族、内存大小),动态赋予变量不同的值。
变量逻辑兜底 结合 Jinja2 default 过滤器 - name: Set safe IP fact
   set_fact:
      listen_ip: "{{ ansible_default_ipv4.address \| default('127.0.0.1') }}"
防止目标主机缺乏某个特定 Fact(如无默认网卡)导致后续 Tasks 发生未定义变量错误。

lookup

用于在控制节点(Control Node)端读取外部数据(如文件、环境变量、Vault 密钥等),通常与 set_fact 结合将外部数据转化为受控节点的 Fact。

数据源类型 lookup 语法格式 代码示例 (结合 set_fact) 执行位置与应用场景
读取控制节点文件 lookup('file', '<path>') - set_fact:
      pub_key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
控制节点端执行。把控制节点本地的文件内容读取并存入变量,方便后续 copy 或 authorized_key 模块使用。
读取控制节点环境变量 lookup('env', '<VAR_NAME>') - set_fact:
      deploy_token: "{{ lookup('env', 'CI_JOB_TOKEN') }}"
控制节点端执行。常用于 CI/CD 流水线中提取 GitLab/GitHub Actions 注入的环境变量。
读取模板渲染内容 lookup('template', '<path>') - set_fact:
      rendered_config: "{{ lookup('template', './nginx.j2') }}"
控制节点端执行。直接把 Jinja2 模板渲染后的纯文本内容存在变量中,无需直接写出到磁盘。
查找通配符文件列表 lookup('fileglob', '<pattern>') - set_fact:
      cert_files: "{{ lookup('fileglob', 'certs/*.crt') }}"
控制节点端执行。返回控制节点匹配指定通配符的文件路径列表(逗号分隔)。

自定义事实变量

通过在目标主机放置静态 .fact 文件或动态脚本,扩展 Ansible 的事实采集能力,将业务相关的元数据存入 ansible_local 命名空间。

维度 配置/调用方式 代码/结构示例 说明与最佳实践
受控节点存储路径 固定目录规范 /etc/ansible/facts.d/ 必须在目标主机上创建此目录。路径下的所有 .fact 格式文件都会被 setup 模块自动扫描并解析。
静态配置文件 (INI 格式) /etc/ansible/facts.d/app.fact [settings]
max_connections=500
role=web_primary
解析后生成的变量层级为:
ansible_local.app.settings.max_connections
静态配置文件 (JSON 格式) /etc/ansible/facts.d/datacenter.fact {\n "dc_name": "shanghai-zone-a",\n "rack_id": 102\n} 解析后生成的变量层级为:
ansible_local.datacenter.dc_name
动态生成脚本 可执行脚本 (需加 chmod +x) #!/bin/sh
echo "{\"uptime_seconds\": $(cut -d' ' -f1 /proc/uptime)}"
必须输出合法的 JSON 格式。每次 Ansible 采集 Facts 时会自动运行该脚本并捕获标准输出。
在 Playbook 中调用 统一前缀 ansible_local - debug:
      msg: "Server is in {{ ansible_local.datacenter.dc_name }}"
变量统一存放在 ansible_local.<文件名(无后缀)>.<内部层级> 中。

magic var 魔法变量

四种魔法变量

魔法变量名 类型/数据结构 主要作用与说明 常见使用场景与语法示例
inventory_hostname 字符串 (String) 当前任务正在运行的目标主机标识。
即在 Inventory 清单中为该主机定义的别名或名称,不受受控端系统真实主机名修改的影响。
单个节点独有配置/标识
· 动态生成节点专属文件:path: "/etc/app/{{ inventory_hostname }}.conf"
· 作为字典的主键在模板中查找数据。
group_names 列表 (List) 当前主机所在的所有主机组名称集合。
按当前运行的主机视角,列出它在 Inventory 中被分配到了哪些组。
按节点角色/组别进行条件过滤
when: "'webservers' in group_names"
(当且仅当当前主机属于 webservers 组时才执行任务)。
groups 字典 (Dictionary) 全量 Inventory 清单的“组-主机”映射表。
包含了清单中定义的所有组名称,以及各个组内包含的所有主机列表({ 组名: [主机1, 主机2...] })。
获取指定组内的全量主机列表
在 Jinja2 模板中循环渲染集群节点:
{% for host in groups['db_servers'] %}`
   `server {{ host }};`
`{% endfor %}
hostvars 字典 (Dictionary) 跨主机数据检索聚合表。
包含了所有主机的变量与 Fact 数据(格式为 { 主机名: { 变量名: 变量值 } }),允许当前主机跨节点读取其他主机的变量。
跨节点提取配置(如提取数据库节点的 IP)
{{ hostvars['db01']['ansible_default_ipv4']['address'] }}
或结合 groups 遍历生成负载均衡/集群 Upstream 配置。

联合使用的场景

假设清单中包含 webservers 和 dbservers 两个组。

业务逻辑:在数据库节点(dbservers)上配置访问限制,允许所有 Web 节点(webservers)的 IP 访问;如果其中某个 Web 节点正好就是当前运行 Task 的数据库节点自身(即单机兼任两角),则额外打上本地环回标记。

  1. 主机清单
1
2
3
4
5
6
7
[webservers]
web01 ansible_host=192.168.1.11
web02 ansible_host=192.168.1.12

[dbservers]
db01 ansible_host=192.168.1.21
web01 # web01 既是 web 也是 db
  1. Playbook
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- name: 组合使用 4 个魔法变量配置数据库访问白名单
hosts: all
gather_facts: true

tasks:
- name: 仅在数据库节点上打印允许访问的 Web 节点列表
# 1. 使用 group_names 判断:只有当前主机属于 dbservers 组时才执行此 Task
when: "'dbservers' in group_names"
debug:
msg:
- "当前正在配置的主机 (inventory_hostname): {{ inventory_hostname }}"
- "允许访问本数据库的 Web 节点 (来自 groups): {{ item }}"
- "该 Web 节点对应的 IP 地址 (来自 hostvars): {{ hostvars[item]['ansible_host'] }}"
- "特殊标记: {{ '【注意:该 Web 节点就是本机自身】' if item == inventory_hostname else '【远程 Web 节点】' }}"
# 2. 使用 groups 获取 webservers 组里的所有主机列表进行循环
loop: "{{ groups['webservers'] }}"
loop_control:
label: "{{ item }}" # 简化终端输出展示

ansible 的条件判断

在 Ansible 中,when 是用于控制 Task(任务)是否执行的条件判断关键字。

它的作用类似于编程语言中的 if 语句:只有当 when 后面的条件计算结果为 True(真)时,Ansible 才会执行该任务;如果条件为 False(假),Ansible 会直接跳过(Skipped)该任务。

比较运算符

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- name: 综合比较运算符应用示例
hosts: all
gather_facts: true # 默认
tasks:
- name: 检查并部署高可用 Web 节点
debug:
msg: "系统满足高可用 Web 节点部署条件!"
when:
# 1. 成员关系判断 (in):当前主机必须属于 webservers 组
# group_names 是一个列表,单台主机可以同时属于多个组
- "'webservers' in group_names"
# 2. 数值转换与逻辑比较 (>=):总物理内存必须大于等于 4096MB (4GB)
# 通过管道符 | int 将其强制转换为整数,再与 4096 进行数值比较
- (ansible_memtotal_mb | int) >= 4096
# 3. 逻辑非与变量状态测试 (not / is defined):系统未处于维护模式
# 管道符 | bool 将其强转为布尔值
- not (is_maintenance_mode is defined and is_maintenance_mode | bool)
# 4. 正则搜索匹配 (is search):主机名必须以 shanghai-web 或 beijing-web 开头
- inventory_hostname is search("^(shanghai|beijing)-web")

基础比较运算符

运算符 名称 / 含义 示例表达式 规则与说明
== 等于 ansible_distribution == "Ubuntu" 判断两端的值是否完全一致(区分大小写)。
!= 不等于 ansible_os_family != "RedHat" 判断两端的值是否不相等。
> 大于 ansible_processor_vcpus > 4 通常用于数值比较。若用于字符串,则按字典序比较。
< 小于 memtotal_mb < 2048 通常用于数值比较。
>= 大于或等于 ansible_memtotal_mb >= 8192 数值或字符顺序比较。
<= 小于或等于 ansible_distribution_major_version | int <= 7 常配合 | int 过滤器将字符串版本号转换为整数后再比较。

包含关系运算符

运算符 名称 / 含义 示例表达式 常见应用场景
in 包含于 "webservers" in group_names 判断元素是否存在于列表中,或子串是否存在于字符串中。
· 判断主机所属组:"'db' in group_names"
· 检查输出信息:"'success' in result.stdout"
not in 不包含于 "prod" not in inventory_hostname 判断元素或子串不存在于目标集合/字符串中。

逻辑运算符

运算符 含义 示例表达式 说明
and 逻辑与 ansible_os_family == "RedHat" and ansible_distribution_major_version == "8" 多个条件必须同时满足。在 when 中也可以写成列表形式(列表项之间默认即为 and 关系)。
or 逻辑或 'web' in group_names or 'lb' in group_names 多个条件满足其一即可。
not 逻辑非 not (is_production | default(false) | bool) 对后面的布尔值或表达式结果取反。

register 注册变量

register 是 Ansible 中用于将某个任务(Task)的执行结果保存到一个自定义变量中的关键字,以便后续任务随时读取和判断。

.rc 是 Return Code(返回码 / 退出状态码) 的缩写。
当使用 shell、command 或 script 等模块在目标主机上执行了一条 Linux 命令,并使用 register 关键字将执行结果保存到一个变量中时,这个变量实际上是一个包含许多详细信息的字典(对象)。其中,.rc 专门用来记录那条命令执行后的状态。

在 Linux 和 Ansible 的标准规范中:

  • .rc == 0:代表命令执行成功。
  • .rc != 0(例如 1, 2, 127 等):代表命令执行失败或出现错误。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- name: 演示 register 的用法
hosts: localhost
# connection: local 不要通过 SSH 连接到远程受控节点,而是直接在本地机器上执行该任务。
connection: local
tasks:
# Task 1: 执行命令并把结果存入变量 my_ip
- name: 获取当前机器的公网 IP
command: curl -s ifconfig.me
register: my_ip

# Task 2: 读取上一步保存的结果
- name: 打印获取到的 IP 地址
debug:
msg: "当前机器的公网 IP 是:{{ my_ip.stdout }}"
when: my_ip.rc == 0 # 只有上一步执行成功(返回码为0)时才打印

错误处理机制

  • block(主任务块): 存放主要业务逻辑的任务集合。只要其中任何一个 task 执行失败(Failed),后续的 block 任务将立即中断,并跳转至 rescue。
  • rescue(错误捕获与补救): 类似于编程语言中的 catch。只有当 block 内部发生错误时才会执行,通常用于日志记录、服务回滚(Rollback)或故障告警。若 rescue 内的任务成功执行,整个 Task 块将被 Ansible 认定为已恢复(State: OK)。
  • always(必须执行): 类似于编程语言中的 finally。无论 block 成功执行,还是触发了 rescue,抑或是发生严重错误,always 里的任务都保证会被无条件执行,常用于环境清理、状态重置或释放锁。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
- name: Ansible 错误处理机制示例 (Block / Rescue / Always)
hosts: localhost
gather_facts: no
tasks:
- name: 执行部署逻辑区块
block:
- name: 步骤 1:尝试执行可能失败的任务
command: ls /path/to/non_existent_file
register: task_result

- name: 步骤 2:如果步骤 1 成功,则继续执行
debug:
msg: "主任务执行成功!"

rescue:
- name: 补救措施:当 Block 内任何任务报错时触发
debug:
msg: "捕获到 Block 内部任务报错!正在执行回滚或补救操作..."

always:
- name: 收尾工作:无论成功还是失败,必定会执行
debug:
msg: "清理临时文件,释放资源。"

playbook 循环语句

关键字 支持数据类型 核心适用场景 循环变量语法 历史与当前状态
loop 列表 (List) 现代推荐标准。配合过滤器(如 dict2items、flatten 等)可处理任何数据结构。 {{ item }} 现代标准(Ansible 2.5+ 引入,官方推荐首选)
with_items 列表 (List) / 嵌套列表 自动展平单层嵌套列表。 {{ item }} 传统 Lookup(逐渐被 loop + flatten 替代)
with_dict 字典 (Dictionary) 直接遍历字典的键值对。 {{ item.key }} / {{ item.value }} 传统 Lookup(逐渐被 loop + dict2items 替代)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
---
- name: 演示 with_items, with_dict 与 loop 的用法
hosts: localhost
gather_facts: no
vars:
# 供 with_items 使用的嵌套列表
packages_list:
- ['curl', 'wget']
- ['git']

# 供 with_dict 使用的字典
user_roles:
alice: "admin"
bob: "developer"

# 供 loop 使用的标准列表
service_names:
- nginx
- redis

tasks:
- name: Task 1 - 使用 with_items 遍历并自动展平列表
debug:
msg: "安装软件包: {{ item }}"
with_items: "{{ packages_list }}"

- name: Task 2 - 使用 with_dict 遍历字典键值对
debug:
msg: "用户 {{ item.key }} 的角色是 {{ item.value }}"
with_dict: "{{ user_roles }}"

- name: Task 3 - 使用 loop 遍历标准列表 (现代标准写法)
debug:
msg: "重启服务: {{ item }}"
loop: "{{ service_names }}"

Jinja2

jinja2 模板

在 Ansible 中,Jinja2 是内置的模板引擎(Template Engine)。它的核心作用是将静态的配置文件转换为动态模板,通过结合 Ansible 的变量、Facts(系统信息)以及逻辑判断,在部署时动态生成符合目标主机环境的定制配置文件。

Ansible 通常使用 template 模块 来处理以 .j2 为后缀的 Jinja2 模板文件(如 nginx.conf.j2),渲染后再分发到目标主机的指定位置。

  • 示例 Jinja2 模板文件 app.ini.j2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
{# ==================== INI 模板文件 ==================== #}
[global]
; 1. 格式 & 简单引用:直接输出 Playbook 变量和系统的 Facts 信息
app_name = {{ app_name }}
host_ip = {{ ansible_default_ipv4.address | default('127.0.0.1') }}

; 2. 条件判断 (if/else):根据环境类型(environment_type)动态决定配置
{% if environment_type == 'production' %}
debug = false
log_level = ERROR
{% else %}
debug = true
log_level = DEBUG
{% endif %}

[database]
; 3. 条件判断 (if):判断可选变量是否定义,定义了才渲染出连接串
{% if db_host is defined %}
db_url = mysql://{{ db_user }}:{{ db_pass }}@{{ db_host }}:3306/{{ db_name }}
{% endif %}

[redis_cluster]
; 4. 循环 (for) + -% 消除空行:遍历 Redis 节点列表,生成节点清单
; {%- 和 -%} 可以吃掉多余的换行符,保证 INI 文件的格式整洁
{% for node in redis_nodes -%}
node_{{ loop.index }} = {{ node.ip }}:{{ node.port }}
{% endfor -%}
  • 示例 Playbook 文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
- name: 演示 Jinja2 模板在 INI 配置文件中的渲染
hosts: localhost
gather_facts: yes # 开启 Facts 采集,以便获取目标机的 IP (ansible_default_ipv4)

vars:
# --- 全局基础变量 ---
app_name: "MyCoreService"
environment_type: "production" # 可选: production 或 development

# --- 数据库变量(测试 is defined 逻辑)---
db_host: "192.168.1.100"
db_user: "app_user"
db_pass: "SecretPass123"
db_name: "prod_db"

# --- 列表变量(供 for 循环遍历使用)---
redis_nodes:
- { ip: "10.0.0.1", port: 6379 }
- { ip: "10.0.0.2", port: 6379 }
- { ip: "10.0.0.3", port: 6380 }

tasks:
- name: 渲染 Jinja2 模板并生成最终的 INI 配置文件
template:
src: app.ini.j2 # 本地/控制端上的 .j2 模板文件路径
dest: /tmp/app.ini # 目标主机上最终生成的 INI 文件路径
mode: '0644' # 设置生成文件的系统权限
  • 渲染后的文件 app.ini
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[global]
; 1. 格式 & 简单引用:直接输出 Playbook 变量和系统的 Facts 信息
app_name = MyCoreService
host_ip = 192.168.1.10

; 2. 条件判断 (if/else):根据环境类型(environment_type)动态决定配置
debug = false
log_level = ERROR

[database]
; 3. 条件判断 (if):判断可选变量是否定义,定义了才渲染出连接串
db_url = mysql://app_user:SecretPass123@192.168.1.100:3306/prod_db

[redis_cluster]
; 4. 循环 (for) + -% 消除空行:遍历 Redis 节点列表,生成节点清单
; {%- 和 -%} 可以吃掉多余的换行符,保证 INI 文件的格式整洁
node_1 = 10.0.0.1:6379
node_2 = 10.0.0.2:6379
node_3 = 10.0.0.3:6380

Jinja2 过滤器

过滤器名称 功能解释 常见参数 / 选项 使用示例 渲染/执行结果
default
(或 d)
当变量未定义(默认)或为假值时,返回指定的默认值,防止因变量缺失导致 Playbook 报错中断。 • default_value: 变量缺失时使用的回退值(必填)
• boolean: 设为 true 时,即便变量已定义,但值为空字符串 ""、None 或 false 等假值时也会触发默认值(可选,默认 false)
{{ http_port | default(8080) }}

{{ custom_title | default('Untitled', true) }}
若 http_port 未定义 → 8080

若 custom_title 为 "" → Untitled
password_hash 将明文密码转换为目标系统(如 Linux /etc/shadow 或 htpasswd)支持的加密哈希散列值。 • hashtype: 哈希算法,如 sha512(默认)、sha256、md5、blowfish 等
• salt: 自定义盐值(可选,留空则自动生成随机盐)
{{ 'MySecretPass' | password_hash('sha512') }}

{{ 'MySecretPass' | password_hash('sha512', 'mycustomsalt') }}
输出形如 $6$rounds=65536$... 的加盐哈希串(常用于 user 模块创建系统用户密码)
dict2items 将字典(Dict)转换为键值对列表(List of K/V Dicts)。常与 loop 配合使用,替代传统的 with_dict。 • key_name: 自定义输出列表中表示“键”的字段名(默认 'key')
• value_name: 自定义输出列表中表示“值”的字段名(默认 'value')
输入变量:
users: { alice: admin, bob: dev }

模板调用:
{{ users | dict2items }}
转换结果:
[
   {'key': 'alice', 'value': 'admin'},
   {'key': 'bob', 'value': 'dev'}
]

角色与集合

在项目根目录或家目录下创建/修改 ansible.cfg,配置 roles_path 和 collections_path

1
2
3
4
5
6
7
[defaults]
# 指定 Roles 的搜寻路径,多个路径用冒号 : 分隔
# 查找顺序:从左到右依次查找
roles_path = ./roles

# 指定 Collections 的搜寻路径
collections_path = ./collections

ansible-galaxy 常用命令

ansible-galaxy 是 Ansible 官方提供的一个命令行包管理工具,同时也是红帽官方运维社区的开源组件共享平台(类似 Python 的 pip、Node.js 的 npm 或 Linux 的 apt/dnf)。

简单来说,它的核心作用有两个:“自己造轮子时帮你建模板”,以及“不想重造轮子时帮你找现成的代码”。

功能分类 常用命令 参数说明与示例 适用场景 / 核心用途
初始化角色 ansible-galaxy role init <role_name> • <role_name>:角色目录路径
例如:ansible-galaxy role init roles/webserver
一键生成包含 tasks, vars, templates 等目录的标准 Role 文件夹结构。
搜索角色 ansible-galaxy search <keyword> • --author <author>:按作者检索
例如:ansible-galaxy search nginx --author geerlingguy
在 Galaxy 线上平台或配置的私有仓库中搜索可用的 role。
安装角色 ansible-galaxy role install <author.role_name> • -p <path>:指定安装保存的本地路径
例如:ansible-galaxy role install geerlingguy.nginx -p ./roles
从 Galaxy 平台下载指定社区 Role 到本地项目。
角色列表 ansible-galaxy role list • -p <path>:指定查看的 Roles 目录 列出本地或特定路径下已经安装的所有 Role 及其版本号。
安装集合 ansible-galaxy collection install <namespace.collection> • --force:强制重新下载覆盖
例如:ansible-galaxy collection install community.general
安装包含特殊模块或插件的 Ansible Collection 扩展包。
集合列表 ansible-galaxy collection list 例:ansible-galaxy collection list 列出当前 Python/Ansible 环境中已安装的所有 Collection。
安装依赖 ansible-galaxy install -r <file> • -r <file>:指定清单文件,默认为 requirements.yml
• -p <path>:指定 Roles 安装安装目录
根据配置文件批量安装项目中定义的所有 Roles 和 Collections(RHCE 考试与 CI/CD 必考)。

角色 Role

在 Ansible 中,Role(角色) 是将变量、任务、模板、处理程序(Handlers)等按标准目录结构组织起来的“可复用模块”。它能够让你把复杂的 Playbook 拆解为结构清晰、易于维护的代码块。

rhel-system-roles.noarch 是 RHEL 官方提供的一个 RPM 软件包,包含了一套由红帽官方编写、测试和维护的 Ansible Roles 和 Collections,专门用来帮运维人员通过自动化方式快速配置 Linux 系统的各项核心功能(如网络、防火墙、存储、时间同步、SELinux 等)。

  • Role 的文件结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
项目根目录/
├── ansible.cfg
└── roles/webserver/
├── defaults/
│ └── main.yml # 最低优先级的默认变量(建议在此写基础默认配置)
├── vars/
│ └── main.yml # 高优先级的变量(不希望被轻易覆盖的固定变量)
├── tasks/
│ └── main.yml # 核心:角色要执行的任务列表(入口)
├── handlers/
│ └── main.yml # 触发器:如配置文件修改后重启服务的任务
├── templates/
│ └── nginx.conf.j2 # 存放 Jinja2 模板文件(如配置文件模板)
├── files/
│ └── index.html # 存放静态文件(使用 copy 模块直接下发的文件)
├── meta/
│ └── main.yml # 角色的元数据(如作者、许可证、依赖的其他 Role)
└── README.md # 角色的说明文档
  • 在 Playbook 调用 Role
1
2
3
4
5
6
- name: 部署 Web 服务器
hosts: webservers
become: true

roles:
- webserver # <--- 这里直接写文件夹名字 webserver

集合 Collection

Ansible Collections(集合)是从 Ansible 2.9 版本开始引入的标准化包管理格式,也是目前 Ansible 社区和官方推荐的最高层级代码分发与打包机制。

  • Collection 的文件结构
1
2
3
4
5
6
7
8
9
10
11
12
13
项目根目录/
├── ansible.cfg
└── collection/my_namespace/my_collection
├── docs/ # 文档
├── plugins/ # 核心:自定义扩展插件
│ ├── modules/ # 自定义 Ansible 模块 (如 Python 写的 Task 模块)
│ ├── lookup/ # 查找插件
│ └── filter/ # 自定义 Jinja2 过滤器
├── roles/ # 核心:包含的多个标准化 Roles
│ ├── webserver/
│ └── database/
├── playbooks/ # 预置的 Playbook 剧本
└── meta/runtime.yml # 元数据与依赖说明

ansible-vault 加密

Ansible Vault 常用指令与核心概念速查表

功能分类 常用命令 参数说明与示例 适用场景 / 核心用途
文件创建 ansible-vault create <file> • <file>:新建的加密 YAML 文件路径
例:ansible-vault create vars/secrets.yml
从零创建一个全新的密文文件(会自动弹出文本编辑器提示输入并确认密码)。
文件编辑 ansible-vault edit <file> 例:ansible-vault edit vars/secrets.yml 安全地解密并打开现有的加密文件进行编辑,保存退出后自动重新加密。加密过的文件不能使用 vim 编辑。
现有文件加密 ansible-vault encrypt <file> • --vault-id <id>:可选,指定特定的密钥标识
例:ansible-vault encrypt vars/db_passwords.yml
将已存在的明文 YAML 变量文件直接加密转化为密文形态。
现有文件解密 ansible-vault decrypt <file> • --output=<new_file>:解密并另存为新文件
例:ansible-vault decrypt vars/db_passwords.yml
将加密文件永久还原为明文格式(生产环境中请谨慎使用)。
密钥查看与管理 ansible-vault view <file> 例:ansible-vault view vars/secrets.yml 在终端直接只读查看加密文件的明文内容,不会在磁盘上留下解密文件。
密码变更 ansible-vault rekey <file> 例:ansible-vault rekey vars/secrets.yml 修改加密文件的解密密码(需先输入旧密码,再输入新密码)。
字符串级加密 ansible-vault encrypt_string '<text>' • --name '<var_name>':指定变量名
例:ansible-vault encrypt_string 'MySecretPass' --name 'db_password'
仅加密单个敏感变量值(如密码或 API Token),输出格式可直接粘贴进普通明文 YAML 文件中。
Playbook 运行解密 ansible-playbook --ask-vault-pass 例:ansible-playbook -i inventory site.yml --ask-vault-pass 运行含有 Vault 加密内容的剧本时,在终端交互式提示输入解密密码(RHCE 常用)。
ansible-playbook --vault-password-file <path> 例:ansible-playbook site.yml --vault-password-file ~/.vault_pass 运行剧本时从指定的明文密码文件或可执行脚本中自动获取密钥(适合 CI/CD 自动化)。

ansible-navigator 导航器

ansible-navigator 的核心设计理念是“开发与运行环境解耦”。它不再直接利用宿主机(Control Node)本地的 Python 或 Ansible 环境,而是将运行所需的所有依赖(Ansible Core、模块、Collections、系统依赖等)打包在一个标准的容器镜像——执行环境(Execution Environment, 简称 EE) 中运行。

graph TD
    A[用户终端 CLI/TUI] -->|1. 执行 ansible-navigator| B[ansible-navigator Engine]

    subgraph Host [控制节点]
        B -->|2. 读取项目文件| C[项目目录: Playbook/ansible.cfg/Vault/SSH Key]
        B -->|3. 启动并挂载文件| D[容器引擎 Podman / Docker]
    end

    subgraph EE [执行环境容器 EE]
        D -->|4. 运行容器| E[ansible-runner]
        E --> F[Ansible Core]
        F --> G[容器内预装的 Collections / Python 包]
    end

    subgraph Managed [被控节点]
        F -->|5. SSH / WinRM 发送指令| H[目标服务器 1]
    end

    E -.->|6. 返回 TUI 结果 / 生成 Artifact JSON| A

常用命令

功能分类 子命令 / 命令行指令 常用参数与示例 核心用途与作用
剧本运行 ansible-navigator run <playbook.yml> • -m stdout:切回传统终端输出模式
• --eei <image_name>:指定 EE 镜像
例如:ansible-navigator run site.yml -m stdout
在 EE 容器中执行 Playbook,默认进入交互式 TUI 界面查看任务进度。
文档查阅 ansible-navigator doc <module_name> • -t plugin_type:查看特定类型插件
例如:ansible-navigator doc ansible.builtin.copy
替代传统的 ansible-doc,从 EE 镜像内实时查阅模块/插件的参数与 Example。
环境与镜像管理 ansible-navigator images 例:ansible-navigator images 交互式浏览本地及配置仓库中的 EE 镜像列表、内置 Python 包及 Collections 版本。
ansible-navigator exec <command> 例:ansible-navigator exec -- ansible --version 直接在 EE 容器环境内部执行原生的 Ansible 底层指令(如 ansible-playbook 或 ansible)。
配置管理 ansible-navigator config 例:ansible-navigator config 查看或交互式排查当前生效的 Ansible 配置文件(ansible.cfg)参数与解析路径。
ansible-navigator --help-config 例:ansible-navigator --help-config > ansible-navigator.yml 快速生成带有详细注释的 ansible-navigator.yml 默认配置文件模板。
清单文件管理 ansible-navigator inventory • -i <inventory_file>:指定主机清单
例如:ansible-navigator inventory -i inventory
交互式树状浏览、校验与审查主机清单(Inventory)的主机分组与变量设置。
历史记录复盘 ansible-navigator replay <artifact.json> 例:ansible-navigator replay artifact.json 重新加载并交互式浏览先前运行 Playbook 时自动生成的 Artifact(JSON 格式日志)历史。
环境信息诊断 ansible-navigator builder 例:ansible-navigator builder 辅助查阅与诊断容器镜像构建工具 ansible-builder 的运行状态与环境属性。

配置文件

navigator.yml 是 ansible-navigator 工具的核心配置文件。

如果把 ansible.cfg 比作 Ansible 自动化逻辑与引擎的配置文件(控制主机清单路径、并发数、SSH 连接参数等),那么 ansible-navigator.yml 就是执行环境(Execution Environment, EE)与界面交互的配置文件

ansible-navigator.yml 绝大多数情况下都直接与 ansible.cfg 放置在同一个目录下

  • ansible-navigator.yml 示例文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# ansible-navigator 的核心配置根节点
ansible-navigator:
# -------------------------------------------------------------------
# 1. 运行模式与输出设置 (Execution & Mode)
# -------------------------------------------------------------------
mode: stdout # 运行模式:可选 'stdout' (传统终端日志模式) 或 'interactive' (TUI 交互界面)
# 💡 建议设为 stdout,排错更直观,行为与经典 ansible-playbook 保持一致

# -------------------------------------------------------------------
# 2. 执行环境容器设置 (Execution Environment - EE)
# -------------------------------------------------------------------
execution-environment:
enabled: true # 是否启用容器环境运行 (默认为 true)
container-engine: podman # 指定容器引擎:可选 'podman' 或 'docker' (RHCE/RHEL 默认使用 podman)
image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel8:latest
# 指定运行 Playbook 所使用的 EE 容器镜像路径
pull:
policy: missing # 镜像拉取策略:可选 'missing' (不存在才拉取)、'always' (总是拉取)、'never' (仅使用本地镜像)

# 容器目录挂载配置 (用于将宿主机的文件/目录映射到容器内部)
volume-mounts:
- src: "/etc/ansible" # 宿主机源路径
dest: "/etc/ansible" # 容器内目标路径
options: "Z" # 挂载选项:在开启 SELinux 的系统上,必须加上 "Z" (私有标签) 或 "z" (共享标签) 以避免权限拒绝

# -------------------------------------------------------------------
# 3. 关联 Ansible 引擎参数 (Ansible Core Configuration)
# -------------------------------------------------------------------
ansible:
config:
path: ./ansible.cfg # 显式指定使用的 ansible.cfg 配置文件路径 (默认会优先寻找当前目录下的 ansible.cfg)

# -------------------------------------------------------------------
# 4. 运行日志与 Artifact 历史记录 (Logging & Artifacts)
# -------------------------------------------------------------------
playbook-artifact:
enable: true # 是否在运行完毕后生成 JSON 格式的执行结果日志 (Artifact)
save-as: ./artifacts/{playbook_name}-artifact-{time_stamp}.json
# 指定 Artifact 文件的保存路径与命名模板