Ansible Roles 详解

目录

[一、什么是 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 服务角色)

目录结构

tasks/main.yml

templates/exports.j2

vars/main.yml

defaults/main.yml

handlers/main.yml

[五、使用 Roles](#五、使用 Roles)

[1. 在 Playbook 中使用 Roles](#1. 在 Playbook 中使用 Roles)

基本用法

带参数的用法

[混合使用 tasks 和 roles](#混合使用 tasks 和 roles)

[2. 角色依赖](#2. 角色依赖)

[3. 角色标签](#3. 角色标签)

[六、Roles 进阶应用](#六、Roles 进阶应用)

[案例3:完整的 LNMP 环境](#案例3:完整的 LNMP 环境)

案例4:多环境配置

[七、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 的优势

  1. 模块化:将功能拆分成独立的角色

  2. 可复用:同一个角色可以在不同项目中使用

  3. 易维护:结构清晰,便于团队协作

  4. 标准化:遵循标准的目录结构

  5. 依赖管理:可以定义角色间的依赖关系

二、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. 变量优先级(从低到高)

  1. defaults/main.yml

  2. group_vars/all

  3. group_vars/组名

  4. host_vars/主机名

  5. vars/main.yml

  6. Playbook 中定义的 vars

  7. 命令行传递的变量 -e

4. 常用命令

复制代码
# 创建新角色
ansible-galaxy init role_name
​
# 列出已安装角色
ansible-galaxy list
​
# 安装外部角色
ansible-galaxy install geerlingguy.nginx
​
# 查看角色信息
ansible-galaxy info geerlingguy.nginx

通过合理使用 Roles,可以将复杂的部署任务模块化,提高代码的可维护性和复用性。建议在实际项目中按照业务功能划分角色,建立标准的角色库。

相关推荐
only_Klein1 小时前
Ansible 条件判断与流程控制详解
自动化·ansible
志栋智能13 小时前
AI驱动的系统自动化巡检:重塑IT基石的智慧“守护神”
大数据·运维·人工智能·云原生·自动化
AI架构全栈开发实战笔记17 小时前
AI应用架构师教你:如何用AI自动化数据仓库的测试?
数据仓库·人工智能·ai·自动化
axPpcfNN21 小时前
可直接编译运行 c#解析dxf可读取圆直线弧多段线源码-无封装缩放拖拽 可读取坐标信息 支持多...
ansible
was1721 天前
Python 自动化实践:Typora 自定义上传接口与兰空图床集成
python·自动化·typora·兰空图床
工业HMI实战笔记1 天前
工业机器人HMI:协作机器人的人机交互界面
人工智能·ui·性能优化·机器人·自动化·人机交互·交互
工业HMI实战笔记1 天前
工业HMI色彩规范:4个禁忌+3类场景配色方案
ui·性能优化·自动化·汽车·交互
键盘鼓手苏苏2 天前
Flutter for OpenHarmony:git 纯 Dart 实现的 Git 操作库(在应用内实现版本控制) 深度解析与鸿蒙适配指南
开发语言·git·flutter·华为·rust·自动化·harmonyos
志栋智能2 天前
AI驱动的安全自动化机器人:从“告警疲劳”到“智能免疫”的防御革命
运维·人工智能·安全·机器人·自动化