Ansible 角色(Role):从创建到应用
在 Ansible 自动化运维中,角色(Role) 是实现代码模块化、可复用、易维护的核心机制。它通过标准化目录结构,将任务、变量、文件、模板等资源打包,支持跨项目复用与团队协作。本文将从角色的核心概念、创建流程、实战案例到系统角色与 Galaxy 角色管理,全面讲解 Ansible 角色的应用。
一、Ansible 角色核心概念
1. 角色的价值:解决大项目痛点
当 Playbook 规模扩大时,直接编写单文件 Playbook 会面临“代码冗余、维护困难、协作低效”等问题。角色通过以下优势解决这些痛点:
- 模块化复用:将“配置 Web 服务”“部署数据库”等通用功能打包为角色,跨项目直接调用,无需重复编写。
- 结构化管理:按功能划分目录(如任务、变量、模板),代码层次清晰,便于维护。
- 团队并行开发:不同管理员可分别开发“Web 角色”“数据库角色”,最后通过 Playbook 组合,提升效率。
- 灵活定制:角色支持默认变量与外部传参,可通过 Playbook 传递不同参数(如数据库密码、IP 地址),适配不同场景。
2. 角色的标准化目录结构
每个角色对应一个顶级目录(目录名即角色名),内部包含固定子目录,各目录功能明确:
目录/文件 | 功能说明 |
---|---|
defaults/main.yml |
角色默认变量(优先级最低),可被 Playbook 或 vars 目录变量覆盖。 |
files/ |
存储静态文件(如配置文件、脚本),角色任务中引用时无需写路径,Ansible 自动查找。 |
handlers/main.yml |
角色的触发器(如服务重启),由任务中的 notify 调用。 |
meta/main.yml |
角色元信息(作者、许可证、依赖角色、支持的操作系统等),用于共享与管理。 |
tasks/main.yml |
角色的核心任务列表(必选),所有任务按顺序执行。 |
templates/ |
存储 Jinja2 模板文件(后缀 .j2 ),支持变量替换,用于动态生成配置文件。 |
tests/ |
角色测试相关文件(如测试用清单、测试 Playbook),可选。 |
vars/main.yml |
角色内部变量(优先级较高),通常用于角色自身逻辑,不建议被 Playbook 覆盖。 |
二、角色实战:从创建到使用
以“部署 HTTP 服务”为例,完整演示角色的创建、配置与调用流程,需求如下:
- 配置本地 YUM 源(挂载 ISO 镜像);
- 安装
httpd
软件包; - 用模板生成动态首页(显示主机名与 IP);
- 配置防火墙允许 HTTP 服务;
- 首页变更时自动重启
httpd
。
1. 步骤 1:创建角色目录结构
使用 ansible-galaxy init
命令自动生成标准化目录(角色名设为 http
):
# 进入 Ansible 角色目录(也可自定义路径)
[student@master tasks]$ cd /home/student/ansible/roles/
# 初始化角色 http
[student@master roles]$ ansible-galaxy init http
- Role http was created successfully
[student@master roles]$ ls
http
执行后生成 http
目录,内部包含所有子目录与默认 main.yml
文件。
2. 步骤 2:配置角色核心文件
(1)编写模板文件(动态首页)
在 templates/
目录下创建 index.html.j2
,使用 Ansible 内置变量(ansible_fqdn
为主机名,ansible_enp1s0.ipv4.address
为网卡 IP):
[student@master templates]$ vim /home/student/ansible/roles/http/templates/index.html.j2
写入内容:
Welcome to {{ ansible_fqdn }} on {{ ansible_enp1s0.ipv4.address }}
(2)编写任务列表(tasks/main.yml
)
定义角色的所有执行步骤,包括配置 YUM 源、挂载 ISO、安装服务等:
vim /home/student/ansible/roles/http/tasks/main.yml
写入内容:
---
# tasks file for http
- name: repo
yum_repository:
file: repo1
name: baseos
description: BaseOS
baseurl: http://ansible.example.com/rhel9/BaseOS
enabled: yes
gpgcheck: no
- name: repo
yum_repository:
file: repo2
name: appstream
description: AppStream
baseurl: http://ansible.example.com/rhel9/AppStream
enabled: yes
gpgcheck: no
- name: Install httpd package
yum:
name:
- httpd
- firewalld
state: present
- name: Deploy index.html from template
template:
src: index.html.j2 # 模板文件(自动从 templates/ 目录查找)
dest: /var/www/html/index.html # 目标路径
notify: httpd # 首页变更时触发重启
- name: for http firewall
firewalld:
service: http
state: enabled
permanent: yes
immediate: yes
(3)编写触发器(handlers/main.yml
)
定义“重启 httpd
”的触发器,由任务中的 notify
调用:
vim /home/student/ansible/roles/http/handlers/main.yml
写入内容:
---
# handlers file for http
- name: httpd
service:
name: httpd
state: restarted
enabled: yes
3. 步骤 3:编写 Playbook 调用角色
在 /etc/ansible/
目录下创建 newrole.yml
,调用 http
角色并指定目标主机:
vim /home/student/ansible/newrole.yml
写入内容:
---
- name: http service
hosts: all # 在所有受控主机上执行
roles:
- http # 调用 http 角色(自动从 /etc/ansible/roles/ 查找)
4. 步骤 4:执行 Playbook 并验证
(1)执行 Playbook
[student@master ansible]$ ansible-playbook newrole.yml
PLAY [http] ***********************************************************************
TASK [Gathering Facts] ************************************************************
ok: [node5]
ok: [node3]
ok: [node2]
ok: [node1]
ok: [node4]
TASK [http : repo] ****************************************************************
ok: [node1]
ok: [node4]
ok: [node3]
ok: [node5]
ok: [node2]
TASK [http : repo] ****************************************************************
ok: [node1]
ok: [node3]
ok: [node2]
ok: [node4]
ok: [node5]
TASK [http : Install httpd package] ***********************************************
ok: [node2]
ok: [node4]
ok: [node5]
ok: [node1]
ok: [node3]
TASK [http : Deploy index.html from template] *************************************
ok: [node4]
ok: [node5]
ok: [node3]
ok: [node2]
ok: [node1]
TASK [http : for http firewall] ***************************************************
changed: [node3]
changed: [node5]
changed: [node2]
changed: [node4]
changed: [node1]
PLAY RECAP ************************************************************************
node1 : ok=6 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
node2 : ok=6 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
node3 : ok=6 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
node4 : ok=6 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
node5 : ok=6 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
(2)验证结果
在控制节点通过 curl
访问受控主机的 HTTP 服务,确认首页内容正确:
# 访问 node1 的 HTTP 服务
[student@master ansible]$ curl http://node1.example.com
Welcome to node1.example.com on 122.168.122.10
# 访问 node2 的 HTTP 服务
[student@master ansible]$ curl http://node2.example.com
Welcome to node2.example.com on 122.168.122.20
三、角色的高级用法
一、变量传递:Playbook 覆盖角色变量
通过在 Playbook 中为角色指定变量,直接覆盖角色 vars/main.yml
或 defaults/main.yml
中的定义,无需修改角色内部文件。
1. 角色变量配置(以 zhang3
角色为例)
先确认角色 zhang3
的 vars
目录已定义变量:
# 查看角色 cy 的 vars 变量文件
cat/home/student/ansible/roles/zhang3/vars/main.yml
文件内容:
---
# vars file for cy
a1: hina
a2: nina
在 zhang3
角色的任务文件中添加 debug
模块,用于打印变量实际值,确认是否被覆盖:
# 编辑角色任务文件
vim /home/student/ansible/roles/zhang3/tasks/main.yml
向文件中写入以下内容:
---
# tasks file for zhang3
- name: test1
debug:
msg: "当前a1的值: {{ a1 }}, 当前a2的值: {{ a2 }}"
2. Playbook 传参覆盖变量
在 /home/student/ansible/
目录下创建 test.yml
,调用 cy
角色时指定新的 a1
值:
# 编写 Playbook
vim /etc/ansible/test.yml
写入配置:
---
- name: test1
hosts: node1
roles:
- role: zhang3
a1: hanaki # 传递变量,覆盖角色 vars 中的 a1: hina
3. 执行并验证
[student@master ansible]$ ansible-playbook test.yml
PLAY [test] ***********************************************************************
TASK [Gathering Facts] ************************************************************
ok: [node1]
TASK [zhang3 : 打印变量值(验证是否被覆盖)] **************************************
ok: [node1] => {
"msg": "当前a1的值: hanaka, 当前a2的值: nina"
}
PLAY RECAP ************************************************************************
node1 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
执行结果中,debug
任务会输出 hanaki
(而非角色默认的 hina
),说明变量已被覆盖。
二、控制执行顺序:pre_tasks 与 post_tasks
通过 pre_tasks
(角色前执行)和 post_tasks
(角色后执行),调整角色与自定义任务的执行顺序,示例如下:
1. 编写含顺序控制的 Playbook
vim /home/student/ansible/order_test.yml
写入配置:
---
- name: test
hosts: node1
pre_tasks:
- name: debug1
debug:
msg: echo 'hello world'
notify: lisi
roles:
- zhang3 # 调用 zhang3 角色
post_tasks:
- name: debug2
debug:
msg: world peace
handlers: # pre_tasks 触发的 handler
- name: lisi
debug:
msg: Wir
2. 执行并观察顺序
[student@master ansible]$ ansible-playbook order_test.yml
PLAY [test] ***********************************************************************
TASK [Gathering Facts] ************************************************************
ok: [node1]
TASK [debug1] *********************************************************************
ok: [node1] => {
"msg": "hello world"
}
TASK [zhang3 : 打印变量值(验证是否被覆盖)] **************************************
ok: [node1] => {
"msg": "当前a1的值: hina, 当前a2的值: nina"
}
TASK [debug2] *********************************************************************
ok: [node1] => {
"msg": "world peace"
}
PLAY RECAP ************************************************************************
node1 : ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
执行逻辑验证:
- 先执行
pre_tasks
中的debug1
任务; pre_tasks
触发handler lisi
,立即执行lisi
任务;- 执行
zhang3
角色的任务; - 最后执行
post_tasks
中的debug2
任务。
三、动态调用角色:include_role/import_role
在 Play 的 tasks
中通过模块动态调用角色,而非在 roles
字段声明,原文示例如下:
1. 编写动态调用角色的 Playbook
vim /etc/ansible/dynamic_role.yml
写入配置(支持 include_role
或 import_role
):
---
- name: test23
hosts: node1
tasks:
# 角色调用前的自定义任务
- debug:
msg: chenyufdsf
# 动态包含 zhang3 角色(二选一:include_role 或 import_role)
- name: a task to include zhang3 here
include_role: # 也可替换为 import_role
name: zhang3
# 角色调用后的自定义任务
- name: debug2
debug:
msg: world peace
2. 执行并验证
[student@master ansible]$ ansible-playbook dynamic_role.yml
PLAY [test] ***********************************************************************
TASK [Gathering Facts] ************************************************************
ok: [node1]
TASK [debug] **********************************************************************
ok: [node1] => {
"msg": "hello world"
}
TASK [test1] **********************************************************************
TASK [zhang3 : 打印变量值(验证是否被覆盖)] **************************************
ok: [node1] => {
"msg": "当前a1的值: hina, 当前a2的值: nina"
}
TASK [debug2] *********************************************************************
ok: [node1] => {
"msg": "world peace"
}
PLAY RECAP ************************************************************************
node1 : ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
ansible-playbook /etc/ansible/dynamic_role.yml
执行结果中,任务顺序为:debug
→ zhang3
角色任务 → debug2
,符合动态调用逻辑。
四、系统角色:RHEL 预定义角色
Red Hat Enterprise Linux(RHEL)提供 rhel-system-roles
软件包,包含多个预定义角色(如时间同步、网络配置、SELinux 管理),可直接使用,无需手动编写。
1. 安装系统角色
[student@master ansible]$ sudo dnf install -y rhel-system-roles
Updating Subscription Management repositories.
Unable to read consumer identity
This system is not registered with an entitlement server. You can use subscription-manager to register.
Last metadata expiration check: 2:30:56 ago on Wed 27 Aug 2025 06:14:58 PM CST.
Dependencies resolved.
===================================================================================
Package Architecture Version Repository Size
===================================================================================
Installing:
rhel-system-roles noarch 1.20.1-1.el9_1 bb 2.0 M
Transaction Summary
===================================================================================
Install 1 Package
Total download size: 2.0 M
Installed size: 9.7 M
Downloading Packages:
rhel-system-roles-1.20.1-1.el9_1.noarch.rpm 74 MB/s | 2.0 MB 00:00
-----------------------------------------------------------------------------------
Total 69 MB/s | 2.0 MB 00:00
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
Preparing : 1/1
Installing : rhel-system-roles-1.20.1-1.el9_1.noarch 1/1
Verifying : rhel-system-roles-1.20.1-1.el9_1.noarch 1/1
Installed products updated.
Installed:
rhel-system-roles-1.20.1-1.el9_1.noarch
Complete!
系统角色默认路径:/usr/share/ansible/roles/
,包含以下常用角色:
[student@master ansible]$ cd /usr/share/ansible/roles/
[student@master roles]$ ls
linux-system-roles.certificate rhel-system-roles.certificate
linux-system-roles.cockpit rhel-system-roles.cockpit
linux-system-roles.crypto_policies rhel-system-roles.crypto_policies
linux-system-roles.firewall rhel-system-roles.firewall
linux-system-roles.ha_cluster rhel-system-roles.ha_cluster
linux-system-roles.kdump rhel-system-roles.kdump
linux-system-roles.kernel_settings rhel-system-roles.kernel_settings
linux-system-roles.logging rhel-system-roles.logging
linux-system-roles.metrics rhel-system-roles.metrics
linux-system-roles.nbde_client rhel-system-roles.nbde_client
linux-system-roles.nbde_server rhel-system-roles.nbde_server
linux-system-roles.network rhel-system-roles.network
linux-system-roles.postfix rhel-system-roles.postfix
linux-system-roles.selinux rhel-system-roles.selinux
linux-system-roles.ssh rhel-system-roles.ssh
linux-system-roles.sshd rhel-system-roles.sshd
linux-system-roles.storage rhel-system-roles.storage
linux-system-roles.timesync rhel-system-roles.timesync
linux-system-roles.tlog rhel-system-roles.tlog
linux-system-roles.vpn rhel-system-roles.vpn
常用角色名 | 功能 |
---|---|
rhel-system-roles.timesync |
配置 NTP 或 Chrony 时间同步 |
rhel-system-roles.network |
配置网络接口(IP、网关、DNS 等) |
rhel-system-roles.selinux |
管理 SELinux(模式切换、上下文配置、布尔值设置) |
rhel-system-roles.firewall |
配置防火墙规则(允许服务、端口等) |
rhel-system-roles.kdump |
配置内核崩溃恢复服务(kdump) |
2. 实战:用系统角色配置时间同步
需求:所有受控主机使用 classroom.example.com
作为 NTP 服务器,并启用 iburst
参数(快速同步)。
(1)复制系统角色到 Ansible 角色目录
# 将时间同步角色复制到 /etc/ansible/roles/,可以自行重命名 (timesync)
[student@master roles]$ cp -r /usr/share/ansible/roles/rhel-system-roles.timesync /home/student/ansible/roles/timesync
(2)编写 Playbook 调用系统角色
创建 timesync.yml
(可以查看角色的帮助文档README.md):
---
- name: Configure time synchronization
hosts: all
vars:
# 系统角色变量:指定 NTP 服务器与 iburst 参数
timesync_ntp_servers:
- hostname: master.example.com # master已开启时间同步主机服务
iburst: yes
timesync_ntp_provider: chrony # 使用 chrony 作为时间同步工具
roles:
- timesync
(3)执行 Playbook 并验证
[student@master ansible]$ ansible-playbook timesync.yml
# 验证时间同步状态(受控节点执行)
[student@master ansible]$ ansible all -m shell -a 'chronyc sources'
node2 | CHANGED | rc=0 >>
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
^? master.example.com 0 7 0 - +0ns[ +0ns] +/- 0ns
node5 | CHANGED | rc=0 >>
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
^? master.example.com 0 7 0 - +0ns[ +0ns] +/- 0ns
node3 | CHANGED | rc=0 >>
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
^? master.example.com 0 7 0 - +0ns[ +0ns] +/- 0ns
node1 | CHANGED | rc=0 >>
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
^? master.example.com 0 7 0 - +0ns[ +0ns] +/- 0ns
node4 | CHANGED | rc=0 >>
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
^? master.example.com 0 7 0 - +0ns[ +0ns] +/- 0ns
# 输出包含 master.example.com 的同步信息
五、从 Ansible Galaxy 获取角色
Ansible Galaxy(galaxy.ansible.com)是社区共享角色的平台,可通过 ansible-galaxy
命令下载、安装与管理角色。
1. 安装 Galaxy 角色
(1)单个角色安装
# 安装 geerlingguy.apache 角色(社区热门 HTTP 角色)
# -p 指定安装路径(默认 ~/.ansible/roles)
ansible-galaxy install geerlingguy.apache -p /etc/ansible/roles/
(2)批量安装角色(通过 requirements 文件)
创建 roles_requirements.yml
,定义需安装的角色列表:
# roles_requirements.yml
- name: geerlingguy.apache # 角色名
src: geerlingguy.apache # Galaxy 角色标识
- name: geerlingguy.mysql
src: geerlingguy.mysql
执行批量安装:
ansible-galaxy install -r roles_requirements.yml -p /etc/ansible/roles/
2. 管理本地角色
- 列出本地角色:
ansible-galaxy list # 按 roles_path 查找并列出所有角色
- 删除本地角色:
ansible-galaxy remove geerlingguy.apache # 删除指定角色
总结
Ansible 角色是自动化运维的“积木”,通过标准化结构实现代码复用与高效管理。核心要点如下:
- 角色结构:记住
tasks
(核心任务)、templates
(动态模板)、handlers
(触发器)等关键目录的功能; - 实战流程:
初始化角色 → 配置任务/模板/触发器 → 编写 Playbook 调用 → 验证结果
; - 高级用法:通过变量传递定制角色行为,用
pre_tasks/post_tasks
控制执行顺序,动态导入角色; - 资源复用:优先使用 RHEL 系统角色或 Galaxy 社区角色,减少重复开发。
掌握角色的使用,可大幅提升 Ansible 自动化项目的可维护性与扩展性,尤其适合中大型运维场景。