Ansible 角色(Role):从创建到应用

发布于:2025-09-10 ⋅ 阅读:(22) ⋅ 点赞:(0)

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 服务”为例,完整演示角色的创建、配置与调用流程,需求如下:

  1. 配置本地 YUM 源(挂载 ISO 镜像);
  2. 安装 httpd 软件包;
  3. 用模板生成动态首页(显示主机名与 IP);
  4. 配置防火墙允许 HTTP 服务;
  5. 首页变更时自动重启 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.ymldefaults/main.yml 中的定义,无需修改角色内部文件。

1. 角色变量配置(以 zhang3 角色为例)

先确认角色 zhang3vars 目录已定义变量:

# 查看角色 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   
 

执行逻辑验证:

  1. 先执行 pre_tasks 中的 debug1 任务;
  2. pre_tasks 触发 handler lisi,立即执行 lisi 任务;
  3. 执行 zhang3 角色的任务;
  4. 最后执行 post_tasks 中的 debug2 任务。

三、动态调用角色:include_role/import_role

在 Play 的 tasks 中通过模块动态调用角色,而非在 roles 字段声明,原文示例如下:

1. 编写动态调用角色的 Playbook

vim /etc/ansible/dynamic_role.yml

写入配置(支持 include_roleimport_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

执行结果中,任务顺序为:debugzhang3 角色任务 → 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 角色是自动化运维的“积木”,通过标准化结构实现代码复用与高效管理。核心要点如下:

  1. 角色结构:记住 tasks(核心任务)、templates(动态模板)、handlers(触发器)等关键目录的功能;
  2. 实战流程初始化角色 → 配置任务/模板/触发器 → 编写 Playbook 调用 → 验证结果
  3. 高级用法:通过变量传递定制角色行为,用 pre_tasks/post_tasks 控制执行顺序,动态导入角色;
  4. 资源复用:优先使用 RHEL 系统角色或 Galaxy 社区角色,减少重复开发。

掌握角色的使用,可大幅提升 Ansible 自动化项目的可维护性与扩展性,尤其适合中大型运维场景。


网站公告

今日签到

点亮在社区的每一天
去签到