Ansible Roles:模块化组织 Playbook

Ansible Roles 角色管理:结构化组织 Playbook

什么是 Role

Role(角色)是 Ansible 组织 Playbook 的结构化方式,将任务、变量、模板、文件等按照标准目录结构组织,便于复用和管理。Role 是 Ansible 推荐的最佳实践。

Role 目录结构

site.yml
webservers.yml
fooservers.yml
roles/
├── common/
│   ├── defaults/
│   │   └── main.yml
│   ├── files/
│   ├── handlers/
│   │   └── main.yml
│   ├── meta/
│   │   └── main.yml
│   ├── tasks/
│   │   └── main.yml
│   ├── templates/
│   │   └── config.j2
│   ├── tests/
│   │   ├── inventory
│   │   └── test.yml
│   └── vars/
│       └── main.yml
└── webservers/
    └── ...(同上结构)

目录说明

目录 说明
defaults/ 默认变量(优先级最低)
files/ 静态文件(使用 copy 模块复制)
handlers/ Handlers(处理器)
meta/ Role 元信息(依赖关系等)
tasks/ 任务列表
templates/ Jinja2 模板文件
tests/ 测试文件
vars/ 变量(优先级高于 defaults)

创建 Role

使用 ansible-galaxy 创建

# 创建 Role
ansible-galaxy role init myrole

# 创建完整 Role
ansible-galaxy role init --init-path roles myrole

# 创建简化 Role
ansible-galaxy role init --init-path roles myrole --role-skeleton=default

手动创建 Role

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

# 创建任务文件
cat > roles/myrole/tasks/main.yml << EOF
---
- name: Install package
  apt:
    name: "{{ package_name }}"
    state: present

- name: Copy configuration
  template:
    src: config.j2
    dest: /etc/myapp/config.conf
  notify: Restart service
EOF

# 创建 handlers 文件
cat > roles/myrole/handlers/main.yml << EOF
---
- name: Restart service
  service:
    name: "{{ service_name }}"
    state: restarted
EOF

# 创建默认变量
cat > roles/myrole/defaults/main.yml << EOF
---
package_name: myapp
service_name: myapp
config_path: /etc/myapp
EOF

使用 Role

在 Playbook 中使用 Role

---
- name: Apply roles
  hosts: webservers
  become: yes
  
  roles:
    - common
    - nginx
    - mysql

传递变量给 Role

---
- name: Apply roles with variables
  hosts: webservers
  become: yes
  
  roles:
    - role: nginx
      nginx_port: 8080
      nginx_worker_processes: 4
    
    - role: mysql
      mysql_root_password: secret
      mysql_databases:
        - app_db
        - test_db

条件执行 Role

---
- name: Conditional roles
  hosts: all
  become: yes
  
  roles:
    - role: common
    
    - role: docker
      when: ansible_os_family == "Debian"
    
    - role: selinux
      when: ansible_selinux.status == "enabled"

Role 依赖

定义依赖

roles/myrole/meta/main.yml:

---
dependencies:
  - role: common
    version: "1.0"
  
  - role: nginx
    nginx_port: 8080
  
  - src: geerlingguy.docker
    version: "3.0.0"

依赖变量

---
dependencies:
  - role: common
    vars:
      common_timezone: "UTC"
  
  - role: nginx
    vars:
      nginx_port: "{{ my_role_nginx_port }}"

完整示例:Nginx Role

Role 结构

roles/nginx/
├── defaults/
│   └── main.yml
├── handlers/
│   └── main.yml
├── tasks/
│   ├── main.yml
│   ├── install.yml
│   └── configure.yml
└── templates/
    ├── nginx.conf.j2
    └── site.conf.j2

默认变量

defaults/main.yml:

---
nginx_port: 80
nginx_worker_processes: auto
nginx_worker_connections: 1024
nginx_document_root: /var/www/html
nginx_server_name: localhost

Handlers

handlers/main.yml:

---
- name: Reload Nginx
  service:
    name: nginx
    state: reloaded

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

主任务文件

tasks/main.yml:

---
- name: Include install tasks
  include_tasks: install.yml
  tags: ['install']

- name: Include configure tasks
  include_tasks: configure.yml
  tags: ['configure']

tasks/install.yml:

---
- name: Install Nginx (Debian)
  apt:
    name: nginx
    state: present
    update_cache: yes
  when: ansible_os_family == "Debian"

- name: Install Nginx (RedHat)
  yum:
    name: nginx
    state: present
  when: ansible_os_family == "RedHat"

tasks/configure.yml:

---
- name: Ensure document root exists
  file:
    path: "{{ nginx_document_root }}"
    state: directory
    owner: www-data
    group: www-data
    mode: '0755'

- name: Copy Nginx configuration
  template:
    src: nginx.conf.j2
    dest: /etc/nginx/nginx.conf
    owner: root
    group: root
    mode: '0644'
  notify: Reload Nginx

- name: Copy site configuration
  template:
    src: site.conf.j2
    dest: /etc/nginx/sites-available/default
    owner: root
    group: root
    mode: '0644'
  notify: Reload Nginx

- name: Start Nginx
  service:
    name: nginx
    state: started
    enabled: yes

使用 Nginx Role

---
- name: Deploy web servers
  hosts: webservers
  become: yes
  
  roles:
    - role: nginx
      nginx_port: 8080
      nginx_document_root: /var/www/myapp
      nginx_server_name: myapp.example.com
    tags: ['nginx']

Ansible Galaxy

安装第三方 Role

# 安装 Role
ansible-galaxy role install geerlingguy.docker

# 安装多个 Role
ansible-galaxy role install geerlingguy.docker geerlingguy.nginx

# 安装到指定目录
ansible-galaxy role install geerlingguy.docker -p roles/

# 从 requirements.yml 安装
ansible-galaxy role install -r requirements.yml

requirements.yml

---
roles:
  - name: docker
    src: geerlingguy.docker
    version: "3.0.0"
  
  - name: nginx
    src: geerlingguy.nginx
  
  - name: mysql
    src: https://github.com/geerlingguy/ansible-role-mysql.git
    version: master

创建和发布 Role

# 初始化 Role
ansible-galaxy role init myrole

# 构建 Role 归档
ansible-galaxy role build

# 发布 Role(需要 Galaxy 账户)
ansible-galaxy role publish

最佳实践

  • 模块化设计: 每个角色负责单一功能
  • 默认变量: 在 defaults/main.yml 中定义默认值
  • 文档化: 添加 README 说明 Role 用法
  • 版本控制: 使用 Git 管理 Role 版本
  • 依赖管理: 使用 meta/main.yml 管理依赖
  • 测试: 编写测试用例验证 Role 功能

总结

Role 是 Ansible 组织代码的最佳方式,能够大幅提高 Playbook 的可维护性和复用性。通过本文的学习,你已经掌握了 Role 的目录结构、创建方法、使用技巧和依赖管理等知识。合理使用 Role 可以让你的自动化运维更加专业和高效。

发表回复

后才能评论