目录
[一、什么是 Roles?](#一、什么是 Roles?)
[Roles 的优势](#Roles 的优势)
[二、Roles 目录结构](#二、Roles 目录结构)
[1. 标准目录结构](#1. 标准目录结构)
[2. 各目录作用说明](#2. 各目录作用说明)
[三、创建 Roles](#三、创建 Roles)
[1. 手动创建目录结构](#1. 手动创建目录结构)
[2. 使用 ansible-galaxy 命令自动创建](#2. 使用 ansible-galaxy 命令自动创建)
[四、Roles 实战案例](#四、Roles 实战案例)
[案例1:部署 Nginx 服务](#案例1:部署 Nginx 服务)
[1. tasks/main.yml - 主要任务](#1. tasks/main.yml - 主要任务)
[2. handlers/main.yml - 处理器](#2. handlers/main.yml - 处理器)
[3. templates/nginx.conf.j2 - Nginx 配置模板](#3. templates/nginx.conf.j2 - Nginx 配置模板)
[4. files/index.html - 静态文件](#4. files/index.html - 静态文件)
[5. vars/main.yml - 角色变量(高优先级)](#5. vars/main.yml - 角色变量(高优先级))
[6. defaults/main.yml - 默认变量(低优先级)](#6. defaults/main.yml - 默认变量(低优先级))
[7. meta/main.yml - 元数据](#7. meta/main.yml - 元数据)
[案例2:NFS 服务角色](#案例2:NFS 服务角色)
[五、使用 Roles](#五、使用 Roles)
[1. 在 Playbook 中使用 Roles](#1. 在 Playbook 中使用 Roles)
[混合使用 tasks 和 roles](#混合使用 tasks 和 roles)
[2. 角色依赖](#2. 角色依赖)
[3. 角色标签](#3. 角色标签)
[六、Roles 进阶应用](#六、Roles 进阶应用)
[案例3:完整的 LNMP 环境](#案例3:完整的 LNMP 环境)
[七、Roles 最佳实践](#七、Roles 最佳实践)
[1. 角色命名规范](#1. 角色命名规范)
[2. 变量命名规范](#2. 变量命名规范)
[3. 目录结构规范](#3. 目录结构规范)
[4. 使用 vault 加密敏感信息](#4. 使用 vault 加密敏感信息)
[5. 角色文档](#5. 角色文档)
[八、Roles 知识点小结](#八、Roles 知识点小结)
[1. 角色结构](#1. 角色结构)
[2. 使用方式](#2. 使用方式)
[3. 变量优先级(从低到高)](#3. 变量优先级(从低到高))
[4. 常用命令](#4. 常用命令)
一、什么是 Roles?
Roles(角色) 是 Ansible 中用于组织 Playbook 的标准结构方式。它将变量、任务、模板、文件等按照特定的目录结构组织在一起,使得 Playbook 更加模块化、可复用和易于维护。
Roles 的优势
-
模块化:将功能拆分成独立的角色
-
可复用:同一个角色可以在不同项目中使用
-
易维护:结构清晰,便于团队协作
-
标准化:遵循标准的目录结构
-
依赖管理:可以定义角色间的依赖关系
二、Roles 目录结构
1. 标准目录结构
roles/
└── role_name/ # 角色名称
├── tasks/ # 任务目录
│ └── main.yml # 主任务文件
├── handlers/ # 处理器目录
│ └── main.yml # 主处理器文件
├── templates/ # 模板目录
│ └── file.j2 # Jinja2 模板文件
├── files/ # 文件目录
│ └── file.conf # 静态文件
├── vars/ # 变量目录
│ └── main.yml # 角色变量
├── defaults/ # 默认变量目录
│ └── main.yml # 默认变量(优先级最低)
├── meta/ # 元数据目录
│ └── main.yml # 角色依赖等信息
└── README.md # 角色说明文档
2. 各目录作用说明
| 目录 | 作用 | 优先级 |
|---|---|---|
tasks/ |
定义角色的主要任务 | - |
handlers/ |
定义处理器,用于响应特定事件 | - |
templates/ |
存放 Jinja2 模板文件 | - |
files/ |
存放静态文件 | - |
vars/ |
角色内部变量,优先级高 | 高 |
defaults/ |
默认变量,优先级最低 | 低 |
meta/ |
角色元数据,如依赖关系 | - |
三、创建 Roles
1. 手动创建目录结构
# 创建角色目录
mkdir -p roles/nginx/{tasks,handlers,templates,files,vars,defaults,meta}
# 创建 main.yml 文件
touch roles/nginx/tasks/main.yml
touch roles/nginx/handlers/main.yml
touch roles/nginx/vars/main.yml
touch roles/nginx/defaults/main.yml
touch roles/nginx/meta/main.yml
2. 使用 ansible-galaxy 命令自动创建
# 创建名为 nginx 的角色
ansible-galaxy init nginx
# 查看生成的目录结构
tree nginx/
四、Roles 实战案例
案例1:部署 Nginx 服务
目录结构
roles/
└── nginx/
├── tasks/
│ └── main.yml
├── handlers/
│ └── main.yml
├── templates/
│ └── nginx.conf.j2
├── files/
│ └── index.html
├── vars/
│ └── main.yml
├── defaults/
│ └── main.yml
└── meta/
└── main.yml
1. tasks/main.yml - 主要任务
---
# 安装 Nginx
- name: Install Nginx
yum:
name: nginx
state: present
# 创建 www 组
- name: Create www group
group:
name: www
gid: "{{ nginx_gid | default(666) }}"
state: present
# 创建 www 用户
- name: Create www user
user:
name: www
uid: "{{ nginx_uid | default(666) }}"
group: www
shell: /sbin/nologin
create_home: no
state: present
# 创建网站目录
- name: Create web root directory
file:
path: "{{ nginx_web_root }}"
state: directory
owner: www
group: www
mode: '0755'
# 配置 Nginx
- name: Configure Nginx
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify: Restart Nginx
# 部署网站文件
- name: Deploy index page
copy:
src: index.html
dest: "{{ nginx_web_root }}/index.html"
owner: www
group: www
mode: '0644'
when: deploy_index | default(true)
# 启动 Nginx 服务
- name: Start Nginx service
systemd:
name: nginx
state: started
enabled: yes
# 检查 Nginx 配置
- name: Check Nginx configuration
command: nginx -t
register: nginx_check
changed_when: false
ignore_errors: yes
# 显示检查结果
- name: Display check result
debug:
msg: "Nginx 配置 {{ '正确' if nginx_check.rc == 0 else '错误' }}"
2. handlers/main.yml - 处理器
---
- name: Restart Nginx
systemd:
name: nginx
state: restarted
- name: Reload Nginx
systemd:
name: nginx
state: reloaded
- name: Check and Restart Nginx
block:
- name: Check Nginx config
command: nginx -t
register: check_result
- name: Restart Nginx
systemd:
name: nginx
state: restarted
when: check_result.rc == 0
- name: Config error warning
debug:
msg: "Nginx 配置错误,请检查!"
when: check_result.rc != 0
3. templates/nginx.conf.j2 - Nginx 配置模板
# {{ ansible_managed }}
user www;
worker_processes {{ nginx_worker_processes | default(ansible_processor_vcpus * 2) }};
error_log /var/log/nginx/error.log {{ nginx_error_log_level | default('warn') }};
pid /var/run/nginx.pid;
events {
worker_connections {{ nginx_worker_connections | default(1024) }};
use epoll;
multi_accept on;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout {{ nginx_keepalive_timeout | default(65) }};
types_hash_max_size 2048;
client_max_body_size {{ nginx_client_max_body_size | default('10M') }};
# Gzip compression
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml application/json application/javascript application/xml+rss application/atom+xml image/svg+xml;
# Virtual host
server {
listen {{ nginx_listen_port | default(80) }};
server_name {{ nginx_server_name | default('localhost') }};
root {{ nginx_web_root }};
index index.html index.htm;
location / {
try_files $uri $uri/ =404;
}
{% if nginx_enable_status | default(false) %}
location /nginx_status {
stub_status on;
access_log off;
allow 127.0.0.1;
deny all;
}
{% endif %}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
{% for vhost in nginx_vhosts | default([]) %}
server {
listen {{ vhost.port | default(80) }};
server_name {{ vhost.server_name }};
root {{ vhost.document_root }};
index index.html index.htm;
}
{% endfor %}
}
4. files/index.html - 静态文件
<!DOCTYPE html>
<html>
<head>
<title>Welcome to {{ ansible_hostname }}</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to {{ ansible_hostname }}</h1>
<p>Server IP: {{ ansible_default_ipv4.address }}</p>
<p>Deployed by Ansible Roles</p>
</body>
</html>
5. vars/main.yml - 角色变量(高优先级)
---
# Nginx 内部变量
nginx_gid: 666
nginx_uid: 666
nginx_web_root: /var/www/html
nginx_worker_processes: auto
nginx_error_log_level: error
6. defaults/main.yml - 默认变量(低优先级)
---
# Nginx 默认变量
nginx_listen_port: 80
nginx_server_name: localhost
nginx_worker_connections: 1024
nginx_keepalive_timeout: 65
nginx_client_max_body_size: 10M
nginx_enable_status: false
nginx_vhosts: []
deploy_index: true
7. meta/main.yml - 元数据
---
galaxy_info:
author: your_name
description: Nginx installation and configuration role
company: your_company
license: MIT
min_ansible_version: 2.9
platforms:
- name: EL
versions:
- 7
- 8
galaxy_tags:
- nginx
- web
- reverse-proxy
dependencies: []
# 可以定义依赖的其他角色
# - { role: common, vars: { common_var: value } }
案例2:NFS 服务角色
目录结构
roles/
└── nfs/
├── tasks/
│ └── main.yml
├── handlers/
│ └── main.yml
├── templates/
│ └── exports.j2
├── vars/
│ └── main.yml
└── defaults/
└── main.yml
tasks/main.yml
---
- name: Install NFS Server
yum:
name: nfs-utils
state: present
- name: Configure NFS Exports
template:
src: exports.j2
dest: /etc/exports
notify: Restart NFS Server
- name: Create www group
group:
name: www
gid: "{{ nfs_gid | default(666) }}"
- name: Create www user
user:
name: www
uid: "{{ nfs_uid | default(666) }}"
group: www
shell: /sbin/nologin
create_home: false
- name: Create shared directory
file:
path: "{{ nfs_share_dir }}"
state: directory
owner: www
group: www
mode: '0755'
- name: Start NFS Server
systemd:
name: nfs-server
state: started
enabled: yes
- name: Check NFS exports
command: exportfs -arv
register: export_result
changed_when: false
templates/exports.j2
# {{ ansible_managed }}
# NFS Exports Configuration
{% for share in nfs_shares %}
{{ share.path }} {{ share.clients }}({{ share.options | default('rw,sync,no_root_squash') }})
{% endfor %}
vars/main.yml
---
nfs_gid: 666
nfs_uid: 666
nfs_share_dir: /data
defaults/main.yml
---
nfs_shares:
- path: /data
clients: "172.16.1.0/24"
options: "rw,sync,all_squash,anonuid=666,anongid=666"
handlers/main.yml
---
- name: Restart NFS Server
systemd:
name: nfs-server
state: restarted
- name: Reload NFS Exports
command: exportfs -arv
五、使用 Roles
1. 在 Playbook 中使用 Roles
基本用法
# site.yml
- hosts: webs
roles:
- nginx
- hosts: nfs
roles:
- nfs
带参数的用法
- hosts: webs
roles:
- role: nginx
nginx_listen_port: 8080
nginx_server_name: www.example.com
nginx_worker_connections: 4096
nginx_enable_status: true
- hosts: nfs
roles:
- role: nfs
nfs_shares:
- path: /data
clients: "172.16.1.0/24"
options: "rw,sync,no_wdelay"
- path: /backup
clients: "10.0.0.0/24"
options: "ro,sync"
混合使用 tasks 和 roles
- hosts: webs
pre_tasks:
- name: 在 roles 之前执行的任务
debug:
msg: "开始部署 Web 服务器"
roles:
- nginx
post_tasks:
- name: 在 roles 之后执行的任务
debug:
msg: "Web 服务器部署完成"
tasks:
- name: 也可以在这里添加额外任务
copy:
src: custom.conf
dest: /etc/nginx/conf.d/custom.conf
2. 角色依赖
在 meta/main.yml 中定义依赖:
---
dependencies:
- { role: common, common_var: "value" }
- { role: epel, when: ansible_os_family == "RedHat" }
- { role: firewall,
firewall_rules:
- { port: 80, proto: tcp, state: enabled }
when: enable_firewall | default(false) }
3. 角色标签
- hosts: webs
roles:
- { role: nginx, tags: ['web', 'nginx'] }
- { role: php, tags: ['web', 'php'] }
- { role: mysql, tags: ['db', 'mysql'] }
执行特定标签:
# 只执行 nginx 角色
ansible-playbook site.yml --tags nginx
# 执行 web 相关的所有角色
ansible-playbook site.yml --tags web
# 跳过特定标签
ansible-playbook site.yml --skip-tags db
六、Roles 进阶应用
案例3:完整的 LNMP 环境
# site.yml
- hosts: webs
roles:
- role: nginx
nginx_listen_port: 80
nginx_server_name: www.example.com
tags: nginx
- role: php
php_version: "7.4"
php_modules:
- php-fpm
- php-mysqlnd
- php-gd
- php-xml
- php-mbstring
tags: php
- role: mysql
mysql_root_password: "{{ vault_mysql_root_password }}"
mysql_databases:
- name: wordpress
mysql_users:
- name: wpuser
password: "{{ vault_wp_password }}"
priv: "wordpress.*:ALL"
tags: mysql
post_tasks:
- name: 测试 PHP 信息
copy:
content: "<?php phpinfo(); ?>"
dest: "{{ nginx_web_root }}/info.php"
案例4:多环境配置
# group_vars/
# ├── dev.yml
# └── prod.yml
# group_vars/dev.yml
nginx_server_name: dev.example.com
nginx_worker_connections: 1024
deploy_index: true
# group_vars/prod.yml
nginx_server_name: www.example.com
nginx_worker_connections: 4096
nginx_enable_status: true
nginx_vhosts:
- { port: 80, server_name: api.example.com, document_root: /var/www/api }
- { port: 80, server_name: blog.example.com, document_root: /var/www/blog }
deploy_index: false
# site.yml
- hosts: "{{ env | default('dev') }}"
roles:
- nginx
执行不同环境:
# 部署开发环境
ansible-playbook site.yml -e env=dev
# 部署生产环境
ansible-playbook site.yml -e env=prod
七、Roles 最佳实践
1. 角色命名规范
-
使用小写字母
-
用下划线连接单词
-
名称要具有描述性
2. 变量命名规范
# 好的命名
nginx_port: 80
mysql_root_password: "{{ vault_mysql_root_password }}"
# 不好的命名
port: 80
pwd: "123456"
3. 目录结构规范
roles/
├── common/ # 基础配置
├── nginx/ # Web 服务
├── php/ # PHP 环境
├── mysql/ # 数据库
├── redis/ # 缓存
├── elasticsearch/ # 搜索引擎
└── monitoring/ # 监控
4. 使用 vault 加密敏感信息
# group_vars/all/vault.yml 加密文件
vault_mysql_root_password: "SuperSecretPassword"
vault_wp_password: "WordPressPassword"
5. 角色文档
每个角色都应该包含 README.md:
# Nginx Role
## 描述
安装和配置 Nginx Web 服务器
## 变量
| 变量名 | 默认值 | 描述 |
|--------|--------|------|
| nginx_port | 80 | 监听端口 |
| nginx_server_name | localhost | 服务器名称 |
| nginx_worker_processes | auto | 工作进程数 |
## 示例
```yaml
- hosts: webs
roles:
- role: nginx
nginx_port: 8080
nginx_server_name: example.com
### 6. 角色测试
```yaml
# test.yml - 测试角色
- hosts: localhost
roles:
- role: nginx
nginx_listen_port: 8080
post_tasks:
- name: 测试 Nginx 是否正常运行
uri:
url: http://localhost:8080
status_code: 200
八、Roles 知识点小结
1. 角色结构
-
tasks/:主要任务定义
-
handlers/:事件处理器
-
templates/:Jinja2 模板
-
files/:静态文件
-
vars/:角色变量(高优先级)
-
defaults/:默认变量(低优先级)
-
meta/:元数据和依赖
-
README.md:文档说明
2. 使用方式
# 基本使用
roles:
- role_name
# 带参数
roles:
- { role: role_name, var: value, tags: tag }
# 条件使用
roles:
- { role: role_name, when: condition }
3. 变量优先级(从低到高)
-
defaults/main.yml -
group_vars/all -
group_vars/组名 -
host_vars/主机名 -
vars/main.yml -
Playbook 中定义的
vars -
命令行传递的变量
-e
4. 常用命令
# 创建新角色
ansible-galaxy init role_name
# 列出已安装角色
ansible-galaxy list
# 安装外部角色
ansible-galaxy install geerlingguy.nginx
# 查看角色信息
ansible-galaxy info geerlingguy.nginx
通过合理使用 Roles,可以将复杂的部署任务模块化,提高代码的可维护性和复用性。建议在实际项目中按照业务功能划分角色,建立标准的角色库。