Ansible Roles #

什么是 Roles? #

Roles 是 Ansible 组织自动化内容的标准方式,将任务、变量、文件、模板等按功能模块化,实现代码复用和共享。

text
┌─────────────────────────────────────────────────────────────┐
│                      Roles 结构                              │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  roles/                                                      │
│  └── nginx/                                                  │
│      ├── tasks/          # 任务                              │
│      ├── handlers/        # 处理器                           │
│      ├── templates/       # 模板                             │
│      ├── files/           # 静态文件                         │
│      ├── vars/            # 变量(高优先级)                  │
│      ├── defaults/        # 默认变量(低优先级)              │
│      ├── meta/            # 元数据/依赖                      │
│      └── README.md        # 文档                             │
│                                                              │
└─────────────────────────────────────────────────────────────┘

角色目录结构 #

标准结构 #

text
roles/
└── nginx/
    ├── defaults/
    │   └── main.yml           # 默认变量(最低优先级)
    ├── files/
    │   ├── index.html         # 静态文件
    │   └── favicon.ico
    ├── handlers/
    │   └── main.yml           # 处理器
    ├── meta/
    │   └── main.yml           # 角色依赖和元数据
    ├── tasks/
    │   ├── main.yml           # 主任务文件
    │   ├── install.yml        # 安装任务
    │   ├── configure.yml      # 配置任务
    │   └── service.yml        # 服务任务
    ├── templates/
    │   ├── nginx.conf.j2      # 配置模板
    │   └── site.conf.j2       # 站点模板
    ├── vars/
    │   └── main.yml           # 角色变量(高优先级)
    ├── library/
    │   └── custom_module.py   # 自定义模块
    ├── module_utils/
    │   └── helper.py          # 模块工具
    ├── tests/
    │   ├── inventory          # 测试清单
    │   └── test.yml           # 测试 Playbook
    └── README.md              # 角色文档

目录说明 #

目录 说明 文件名
defaults 默认变量,最低优先级 main.yml
vars 角色变量,高优先级 main.yml
tasks 任务定义 main.yml
handlers 处理器定义 main.yml
templates Jinja2 模板文件 *.j2
files 静态文件 *
meta 角色依赖和元数据 main.yml
library 自定义模块 *.py
module_utils 模块工具 *.py
tests 测试文件 test.yml

创建角色 #

使用 ansible-galaxy #

bash
# 创建角色骨架
ansible-galaxy init nginx

# 创建角色到指定目录
ansible-galaxy init --init-path ./roles nginx

# 输出
- nginx was created successfully

手动创建 #

bash
# 创建目录结构
mkdir -p roles/nginx/{tasks,handlers,templates,files,vars,defaults,meta}

# 创建必要文件
touch roles/nginx/tasks/main.yml
touch roles/nginx/handlers/main.yml
touch roles/nginx/defaults/main.yml
touch roles/nginx/meta/main.yml

角色示例 #

defaults/main.yml #

yaml
# roles/nginx/defaults/main.yml
---
nginx_user: www-data
nginx_group: www-data
nginx_port: 80
nginx_worker_processes: auto
nginx_worker_connections: 1024
nginx_log_dir: /var/log/nginx
nginx_config_dir: /etc/nginx
nginx_document_root: /var/www/html

nginx_vhosts: []
nginx_upstreams: []

nginx_gzip_enabled: true
nginx_ssl_enabled: false

vars/main.yml #

yaml
# roles/nginx/vars/main.yml
---
nginx_packages:
  - nginx
  - nginx-common

nginx_service_name: nginx

nginx_config_files:
  - nginx.conf
  - mime.types

nginx_log_files:
  - access.log
  - error.log

tasks/main.yml #

yaml
# roles/nginx/tasks/main.yml
---
- name: Include install tasks
  include_tasks: install.yml
  tags: install

- name: Include configure tasks
  include_tasks: configure.yml
  tags: configure

- name: Include vhost tasks
  include_tasks: vhosts.yml
  when: nginx_vhosts | length > 0
  tags: vhosts

- name: Include service tasks
  include_tasks: service.yml
  tags: service

tasks/install.yml #

yaml
# roles/nginx/tasks/install.yml
---
- name: Install Nginx
  apt:
    name: "{{ nginx_packages }}"
    state: present
    update_cache: yes
  when: ansible_facts['os_family'] == 'Debian'

- name: Install Nginx (RedHat)
  yum:
    name: nginx
    state: present
  when: ansible_facts['os_family'] == 'RedHat'

- name: Create nginx user
  user:
    name: "{{ nginx_user }}"
    system: yes
    shell: /sbin/nologin
    create_home: no
  when: nginx_user != 'www-data'

- name: Create directories
  file:
    path: "{{ item }}"
    state: directory
    owner: "{{ nginx_user }}"
    group: "{{ nginx_group }}"
    mode: '0755'
  loop:
    - "{{ nginx_log_dir }}"
    - "{{ nginx_document_root }}"

tasks/configure.yml #

yaml
# roles/nginx/tasks/configure.yml
---
- name: Deploy nginx configuration
  template:
    src: nginx.conf.j2
    dest: "{{ nginx_config_dir }}/nginx.conf"
    owner: root
    group: root
    mode: '0644'
    backup: yes
    validate: nginx -t -c %s
  notify: Reload Nginx

- name: Deploy mime types
  copy:
    src: mime.types
    dest: "{{ nginx_config_dir }}/mime.types"
    owner: root
    group: root
    mode: '0644'
  notify: Reload Nginx

- name: Remove default site
  file:
    path: "{{ nginx_config_dir }}/sites-enabled/default"
    state: absent
  when: nginx_remove_default_site | default(true)
  notify: Reload Nginx

tasks/vhosts.yml #

yaml
# roles/nginx/tasks/vhosts.yml
---
- name: Create vhost directories
  file:
    path: "{{ nginx_config_dir }}/sites-{{ item }}"
    state: directory
    owner: root
    group: root
    mode: '0755'
  loop:
    - available
    - enabled

- name: Deploy vhost configurations
  template:
    src: vhost.conf.j2
    dest: "{{ nginx_config_dir }}/sites-available/{{ item.server_name }}.conf"
    owner: root
    group: root
    mode: '0644'
  loop: "{{ nginx_vhosts }}"
  notify: Reload Nginx

- name: Enable vhosts
  file:
    src: "{{ nginx_config_dir }}/sites-available/{{ item.server_name }}.conf"
    dest: "{{ nginx_config_dir }}/sites-enabled/{{ item.server_name }}.conf"
    state: link
  loop: "{{ nginx_vhosts }}"
  when: item.enabled | default(true)
  notify: Reload Nginx

tasks/service.yml #

yaml
# roles/nginx/tasks/service.yml
---
- name: Ensure Nginx is started and enabled
  service:
    name: "{{ nginx_service_name }}"
    state: started
    enabled: yes

handlers/main.yml #

yaml
# roles/nginx/handlers/main.yml
---
- name: Reload Nginx
  service:
    name: nginx
    state: reloaded

- name: Restart Nginx
  service:
    name: nginx
    state: restarted

- name: Validate Nginx config
  command: nginx -t
  changed_when: false

templates/nginx.conf.j2 #

jinja2
{# roles/nginx/templates/nginx.conf.j2 #}
# Nginx configuration
# Managed by Ansible

user {{ nginx_user }};
worker_processes {{ nginx_worker_processes }};
pid /run/nginx.pid;
error_log {{ nginx_log_dir }}/error.log;

events {
    worker_connections {{ nginx_worker_connections }};
}

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    
    {% if nginx_gzip_enabled %}
    gzip on;
    gzip_types text/plain text/css application/json application/javascript;
    {% endif %}
    
    {% for upstream in nginx_upstreams %}
    upstream {{ upstream.name }} {
        {% for server in upstream.servers %}
        server {{ server }};
        {% endfor %}
    }
    {% endfor %}
    
    include {{ nginx_config_dir }}/conf.d/*.conf;
    include {{ nginx_config_dir }}/sites-enabled/*;
}

meta/main.yml #

yaml
# roles/nginx/meta/main.yml
---
galaxy_info:
  author: Your Name
  description: Nginx web server installation and configuration
  company: Your Company
  license: MIT
  min_ansible_version: '2.9'
  platforms:
    - name: Ubuntu
      versions:
        - focal
        - jammy
    - name: Debian
      versions:
        - bullseye
        - bookworm
    - name: EL
      versions:
        - '7'
        - '8'
        - '9'
  galaxy_tags:
    - web
    - nginx
    - server

dependencies: []

使用角色 #

基本使用 #

yaml
# site.yml
---
- hosts: webservers
  become: yes
  roles:
    - nginx

传递变量 #

yaml
# site.yml
---
- hosts: webservers
  become: yes
  roles:
    - role: nginx
      vars:
        nginx_port: 8080
        nginx_worker_processes: 4
        nginx_vhosts:
          - server_name: example.com
            port: 80
            root: /var/www/example

条件执行 #

yaml
# site.yml
---
- hosts: all
  become: yes
  roles:
    - role: nginx
      when: "'webserver' in group_names"
    
    - role: mysql
      when: "'database' in group_names"

使用标签 #

yaml
# site.yml
---
- hosts: webservers
  become: yes
  roles:
    - role: nginx
      tags:
        - web
        - nginx

include_role #

yaml
# site.yml
---
- hosts: webservers
  become: yes
  tasks:
    - name: Include nginx role
      include_role:
        name: nginx
      vars:
        nginx_port: 8080
      when: install_nginx | default(true)

import_role #

yaml
# site.yml
---
- hosts: webservers
  become: yes
  tasks:
    - name: Import nginx role
      import_role:
        name: nginx

角色依赖 #

定义依赖 #

yaml
# roles/webapp/meta/main.yml
---
dependencies:
  - role: nginx
    nginx_port: 80
    nginx_vhosts:
      - server_name: "{{ app_domain }}"
        root: "{{ app_root }}"
  
  - role: php
    php_version: "8.1"
  
  - role: mysql
    when: app_needs_database | default(true)

依赖顺序 #

text
执行顺序:

1. 依赖角色(按定义顺序)
   ├── nginx
   ├── php
   └── mysql

2. 当前角色
   └── webapp

3. 处理器(按触发顺序)

避免循环依赖 #

yaml
# 错误示例 - 循环依赖
# roles/nginx/meta/main.yml
dependencies:
  - role: ssl

# roles/ssl/meta/main.yml
dependencies:
  - role: nginx

# 这会导致循环依赖错误

Ansible Galaxy #

什么是 Ansible Galaxy? #

Ansible Galaxy 是 Ansible 角色的社区仓库,可以分享和下载角色。

安装角色 #

bash
# 从 Galaxy 安装
ansible-galaxy install geerlingguy.nginx

# 安装指定版本
ansible-galaxy install geerlingguy.nginx,v3.1.0

# 从 Git 安装
ansible-galaxy install git+https://github.com/geerlingguy/ansible-role-nginx.git

# 从文件安装多个角色
ansible-galaxy install -r requirements.yml

requirements.yml #

yaml
# requirements.yml
- src: geerlingguy.nginx
  version: "3.1.0"

- src: geerlingguy.mysql
  version: "4.0.0"

- src: https://github.com/user/ansible-role-custom
  name: custom-role

- src: git+https://github.com/user/ansible-role-app.git
  version: main
  name: app

发布角色 #

bash
# 登录 Galaxy
ansible-galaxy login

# 导入角色
ansible-galaxy import username role_name

# 从 GitHub 自动导入
# 在 Galaxy 网站上连接 GitHub 账户

角色最佳实践 #

1. 使用 defaults 定义可覆盖变量 #

yaml
# roles/nginx/defaults/main.yml
nginx_port: 80                    # 用户可覆盖
nginx_user: www-data              # 用户可覆盖
nginx_config_dir: /etc/nginx      # 通常不需要覆盖

2. 使用 vars 定义内部变量 #

yaml
# roles/nginx/vars/main.yml
nginx_packages:                   # 内部使用,不建议覆盖
  - nginx
  - nginx-common

3. 模块化任务文件 #

yaml
# roles/nginx/tasks/main.yml
---
- include_tasks: install.yml
- include_tasks: configure.yml
- include_tasks: vhosts.yml
- include_tasks: service.yml

4. 使用标签 #

yaml
# roles/nginx/tasks/main.yml
---
- include_tasks: install.yml
  tags: install

- include_tasks: configure.yml
  tags: configure

- include_tasks: service.yml
  tags: service

5. 提供完整的 README #

markdown
# roles/nginx/README.md
# Ansible Role: Nginx

Installs and configures Nginx web server.

## Requirements

- Ubuntu 20.04/22.04 or Debian 10/11
- Ansible 2.9+

## Role Variables

| Variable | Default | Description |
|----------|---------|-------------|
| nginx_port | 80 | Nginx listen port |
| nginx_user | www-data | Nginx user |
| nginx_worker_processes | auto | Number of worker processes |

## Dependencies

None

## Example Playbook

```yaml
- hosts: webservers
  roles:
    - role: nginx
      nginx_port: 8080

License #

MIT

text

### 6. 编写测试

```yaml
# roles/nginx/tests/test.yml
---
- hosts: localhost
  remote_user: root
  roles:
    - nginx
  vars:
    nginx_port: 8080
    nginx_vhosts:
      - server_name: test.local
        root: /var/www/test

完整项目示例 #

text
project/
├── ansible.cfg
├── inventory/
│   ├── hosts
│   ├── group_vars/
│   │   ├── all.yml
│   │   └── webservers.yml
│   └── host_vars/
│       └── web1.yml
├── roles/
│   ├── common/
│   │   ├── tasks/
│   │   │   └── main.yml
│   │   └── defaults/
│   │       └── main.yml
│   ├── nginx/
│   │   ├── tasks/
│   │   ├── handlers/
│   │   ├── templates/
│   │   ├── defaults/
│   │   └── meta/
│   └── webapp/
│       ├── tasks/
│       ├── templates/
│       ├── defaults/
│       └── meta/
├── playbooks/
│   ├── site.yml
│   ├── webservers.yml
│   └── databases.yml
└── requirements.yml
yaml
# playbooks/site.yml
---
- hosts: all
  become: yes
  roles:
    - common

- hosts: webservers
  become: yes
  roles:
    - nginx
    - webapp

- hosts: databases
  become: yes
  roles:
    - mysql

下一步 #

现在你已经掌握了 Roles 角色,接下来学习 常用模块 了解 Ansible 内置模块的详细用法!

最后更新:2026-03-29