一、Ansible 角色:标准化的配置复用单元
角色是 Ansible 在 2.0 版本引入的配置复用单元,它通过约定式的目录结构,将任务、变量、模板、处理程序等配置打包为独立的可复用单元,实现了配置的模块化拆分。
1.1 角色的标准目录结构
Ansible 角色采用约定大于配置的设计,所有角色都遵循统一的目录结构,Ansible 会自动识别该结构中的内容,无需用户手动声明每个文件的位置。一个标准的角色目录结构如下:
角色名/ ├── defaults/ │ └── main.yml ├── files/ ├── handlers/ │ └── main.yml ├── meta/ │ ├── main.yml │ └── README.md ├── tasks/ │ └── main.yml ├── templates/ ├── tests/ │ ├── inventory │ └── test.yml └── vars/ └── main.yml每个目录的技术作用为:
- defaults 目录:存储角色的默认变量,该目录下的变量优先级为所有变量层级中最低,可被其他层级的变量覆盖。
- vars 目录:存储角色的固定变量,该目录下的变量优先级高于默认变量,通常用于角色内部的固定配置。
- tasks 目录:角色的任务入口,该目录下的 main.yml 定义了角色要执行的所有任务,Ansible 调用角色时,默认运行该文件中的所有任务。
- handlers 目录:存储角色的处理程序,用于定义任务触发的后续操作,如配置变更后的服务重启。
- files 目录:存储静态文件,角色中的 copy 等模块可直接引用该目录下的文件,无需填写完整路径。
- templates 目录:存储 Jinja2 模板文件,角色中的 template 模块可直接引用该目录下的模板,无需填写完整路径。
- meta 目录:存储角色的元数据,包括角色的依赖、支持的平台、作者信息,以及角色的说明文档。
- tests 目录:存储角色的测试用例,用于验证角色的功能是否正常。
1.2 角色变量的优先级规则
变量的优先级是角色机制中较难理解的点,Ansible 对变量的优先级有明确的定义,从低到高的顺序为:角色defaults变量 < 清单中的主机/组变量 < group_vars/host_vars中的变量 < play的vars变量 < 调用角色时传入的变量该规则的技术逻辑为:越靠近调用端的变量,优先级越高,默认变量作为兜底的配置,而调用时传入的变量作为最高优先级的自定义配置,确保用户可以根据不同的场景,灵活修改角色的行为。
1.3 角色的调用方式与技术差异
角色有三种调用方式,其中import_role与include_role是最容易混淆的两个机制,二者的技术实现存在本质差异:
1.3.1 roles 列表调用
这是最早期的角色调用方式,用户在 play 中定义 roles 列表,列出要运行的角色。该方式的运行规则为:无论 roles 列表的位置在 play 的哪个部分,角色的任务都会在所有普通任务之前运行。
1.3.2 import_role:静态导入
import_role是静态导入机制,它的技术逻辑为:在 Ansible 的 playbook 解析阶段(pre-run 阶段),就会将角色的所有内容,包括任务、变量、处理程序,合并到当前 play 中,成为 play 的一部分。该机制的技术特性为:
- 解析阶段就会处理角色的内容,因此如果角色存在语法错误,会在 playbook 运行前就报错。
- 角色的变量会合并到 play 的全局变量空间,因此 play 中所有的任务,包括在导入之前的任务,都可以访问角色的变量。
- 如果为导入操作添加 when 条件,该条件会被应用到角色内的每一个任务,相当于为角色内的所有任务都添加了该条件。
- 不支持循环操作,因为解析阶段无法处理动态的循环变量。
- 使用
ansible-playbook --list-tasks时,会列出角色内的所有任务。
1.3.3 include_role:动态包含
include_role是动态包含机制,它的技术逻辑为:在 Ansible 的任务执行阶段(run-time 阶段),当执行到该任务时,才会加载角色的内容。该机制的技术特性为:
- 执行阶段才会处理角色的内容,因此如果角色存在语法错误,会在执行到该任务时才报错。
- 角色的变量仅在角色的任务空间内可见,不会合并到 play 的全局变量空间,因此 play 中的其他任务无法访问角色的变量。
- 如果为包含操作添加 when 条件,该条件仅用于判断是否加载整个角色,不会应用到角色内的任务。
- 支持循环操作,因为执行阶段可以处理动态的循环变量。
- 使用
ansible-playbook --list-tasks时,仅能看到 include_role 这个任务,无法看到角色内的任务。
1.4 任务阶段与处理程序的运行规则
Ansible 的任务分为四个运行阶段,运行顺序为:pre_tasks -> 角色任务 -> 普通tasks -> post_tasks。处理程序的运行规则也是该机制的难点,它的技术逻辑为:处理程序不是在所有任务结束后统一运行,而是在每个阶段结束后,运行该阶段触发的处理程序:
- pre_tasks 全部执行完成后,运行 pre_tasks 阶段触发的处理程序
- 角色任务与普通 tasks 全部执行完成后,运行该阶段触发的处理程序
- post_tasks 全部执行完成后,运行 post_tasks 阶段触发的处理程序
1.5 外部角色的管理
用户可以通过ansible-galaxy工具,从外部仓库获取现成的角色,该工具支持以下功能:
- 搜索角色:从仓库中搜索符合条件的角色,支持按平台、标签筛选。
- 查看角色信息:查看角色的版本、支持的 Ansible 版本、作者信息。
- 安装角色:将角色安装到本地的项目目录中,支持指定安装路径。
- 批量安装:通过 requirements.yml 文件,批量定义需要安装的角色,支持从 Galaxy、Git 仓库、tar 包等不同来源安装角色,该文件可纳入版本控制,实现依赖的统一管理。
二、Ansible 内容集合:模块化的内容分发机制
内容集合是 Ansible 在 2.9 版本引入的内容分发机制,它解决了早期核心模块的分发与版本管理问题,实现了内容的独立更新与分发。
2.1 内容集合的出现背景
早期的 Ansible,所有的模块都打包在核心软件包中,随着模块数量的增长,出现了以下问题:
- 核心软件包体积过大,用户即使只用到少量模块,也需要安装所有的模块。
- 模块的更新必须跟随 Ansible 核心的版本,无法独立更新,导致模块的迭代速度受限。
- 模块的命名冲突,不同的开发者开发的模块,可能出现同名的情况,导致使用时的冲突。
内容集合的出现,解决了这些问题,它将相关的模块、角色、插件打包为独立的单元,实现了内容的独立分发与更新。
2.2 命名空间与 FQCN 的技术解析
为了解决命名冲突的问题,内容集合引入了命名空间的机制,集合的命名格式为命名空间.集合名,其中命名空间用于标识内容的维护方,如community代表社区维护的内容,redhat代表红帽维护的内容,cisco代表思科维护的内容。在使用集合中的内容时,需要使用 FQCN(完全限定名称),格式为集合名.内容名,例如:
- 使用
community.mysql集合中的mysql_user模块,需要写为community.mysql.mysql_user - 使用
redhat.satellite集合中的organizations角色,需要写为redhat.satellite.organizations该机制的技术作用为:通过命名空间的隔离,解决了不同集合之间的内容重名问题,即使不同的集合中存在同名的模块,也可以通过 FQCN 进行区分,避免冲突。
2.3 内容集合的安装与管理
内容集合的管理与角色类似,用户可以通过ansible-galaxy工具进行管理:
- 安装集合:将集合安装到本地的项目目录中,支持指定安装路径,解决了 ansible-navigator 执行环境的加载问题。
- 批量安装:通过 requirements.yml 文件,批量定义需要安装的集合,支持从不同的来源安装,该文件可纳入版本控制,实现依赖的统一管理。
- 仓库配置:用户可以配置多个内容仓库,如红帽的 Automation Hub、私有 Automation Hub、Ansible Galaxy,ansible-galaxy 会按顺序从这些仓库中查找内容,认证信息通过环境变量配置,避免了凭据泄露的问题。
三、RHEL 系统角色:跨版本的标准化配置实现
RHEL 系统角色是红帽提供的一套标准化的系统配置角色,它基于内容集合分发,解决了跨 RHEL 版本的配置适配问题。在企业环境中,通常存在多个版本的 RHEL 系统,不同的版本中,系统服务的实现存在差异,例如:
- RHEL 6 中,时间同步服务为 ntpd
- RHEL 9 中,时间同步服务为 chronyd如果用户自己编写配置,需要针对不同的版本,编写不同的配置逻辑,维护成本较高。RHEL 系统角色的技术逻辑为:红帽预先编写了适配所有 RHEL 版本的角色,角色会自动根据受管主机的 RHEL 版本,选择对应的服务与配置逻辑,用户只需要调用角色,设置统一的变量,即可完成跨版本的配置,无需自己处理版本适配的逻辑。该角色集合涵盖了常用的系统配置场景,包括时间同步、网络配置、防火墙配置、系统调优、日志记录等。
总结
Ansible 的角色与内容集合,是 Ansible 自动化体系中,实现配置复用与分发的核心机制:
- 角色通过约定式的目录结构,实现了配置的模块化拆分,解决了大 playbook 的维护问题,通过变量优先级与调用方式的设计,实现了配置的灵活适配。
- 内容集合通过命名空间与独立分发的机制,解决了核心模块的版本管理与命名冲突问题,实现了内容的独立更新与分发。
- RHEL 系统角色基于这两个机制,实现了跨 RHEL 版本的标准化配置,降低了企业跨版本自动化的维护成本。这两个机制共同构成了 Ansible 大规模自动化的基础,为企业的自动化运维提供了标准化的复用与分发体系。