第十章:Roles 角色管理
学习使用 Ansible Roles 组织 Playbook,实现代码复用和模块化。
最后更新: 2024-01-24
页面目录
Ansible Roles
Roles 是 Ansible 最强大的组织功能,允许你将 Playbook 分解为可复用、可共享的组件。
Roles 概述
┌─────────────────────────────────────────────────────────────────┐
│ Role 目录结构 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ role_name/ │
│ ├── defaults/ # 默认变量(最低优先级) │
│ │ └── main.yml │
│ ├── files/ # 静态文件 │
│ │ ├── config.conf │
│ │ └── script.sh │
│ ├── handlers/ # 处理器 │
│ │ └── main.yml │
│ ├── meta/ # 依赖关系 │
│ │ └── main.yml │
│ ├── tasks/ # 任务列表 │
│ │ └── main.yml │
│ ├── templates/ # Jinja2 模板 │
│ │ ├── config.conf.j2 │
│ │ └── app.yml.j2 │
│ ├── tests/ # 测试 │
│ │ ├── inventory │
│ │ └── test.yml │
│ └── vars/ # 变量(高于 defaults) │
│ └── main.yml │
│ │
└─────────────────────────────────────────────────────────────────┘
创建 Role
使用 ansible-galaxy
# 创建 role
ansible-galaxy init role_name
# 创建 role 到指定目录
ansible-galaxy init role_name --init-path ./roles/
手动创建目录
mkdir -p roles/nginx/defaults
mkdir -p roles/nginx/files
mkdir -p roles/nginx/handlers
mkdir -p roles/nginx/tasks
mkdir -p roles/nginx/templates
mkdir -p roles/nginx/vars
Role 组件
defaults/main.yml
---
# 默认变量(最低优先级)
# 可以在 playbook 或 inventory 中覆盖
nginx_version: "1.24.0"
nginx_port: 80
nginx_server_name: localhost
nginx_user: www-data
nginx_worker_processes: auto
nginx_worker_connections: 1024
nginx_keepalive_timeout: 65
# 包管理
nginx_packages:
- nginx
# 配置选项
nginx_config_options: []
nginx_sites: []
nginx_remove_default_site: true
# 服务配置
nginx_service_enabled: yes
nginx_service_state: started
vars/main.yml
---
# 角色内部变量(较高优先级)
# 不应被 playbook 覆盖的内部配置
_nginx_os_packages:
Debian: [nginx]
RedHat: [nginx]
CentOS: [nginx]
_nginx_default_conf_dir: /etc/nginx
_nginx_default_conf_path: "{{ _nginx_default_conf_dir }}/nginx.conf"
_nginx_pid_file: /run/nginx.pid
tasks/main.yml
---
# 任务列表
- name: Include OS-specific variables
include_vars: "{{ ansible_os_family | lower }}.yml"
- name: Install Nginx
package:
name: "{{ nginx_packages }}"
state: present
- name: Create nginx directories
file:
path: "{{ item }}"
state: directory
owner: "{{ nginx_user }}"
mode: '0755'
loop:
- /var/cache/nginx
- /var/log/nginx
- /run/nginx
- name: Copy nginx configuration
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: '0644'
validate: nginx -t -c %s
notify: Reload nginx
- name: Copy site configurations
template:
src: "{{ item.template | default('site.conf.j2') }}"
dest: "/etc/nginx/sites-available/{{ item.name }}.conf"
notify: Reload nginx
loop: "{{ nginx_sites }}"
when: nginx_sites | length > 0
- name: Enable sites
file:
src: "/etc/nginx/sites-available/{{ item.name }}.conf"
dest: "/etc/nginx/sites-enabled/{{ item.name }}.conf"
state: link
loop: "{{ nginx_sites }}"
when: nginx_sites | length > 0
- name: Remove default site
file:
path: /etc/nginx/sites-enabled/default
state: absent
when: nginx_remove_default_site | bool
- name: Ensure nginx is running
service:
name: nginx
state: "{{ nginx_service_state }}"
enabled: "{{ nginx_service_enabled }}"
handlers/main.yml
---
- name: Reload nginx
service:
name: nginx
state: reloaded
- name: Restart nginx
service:
name: nginx
state: restarted
templates/
# nginx.conf.j2
user {{ nginx_user }};
worker_processes {{ nginx_worker_processes }};
error_log /var/log/nginx/error.log;
pid {{ nginx_pid_file }};
events {
worker_connections {{ nginx_worker_connections }};
}
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 }};
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
files/
# 静态文件,直接复制到目标主机
# 使用 copy 或 script 模块引用
meta/main.yml
---
# 角色依赖
dependencies:
- role: common
vars:
timezone: Asia/Shanghai
使用 Role
基本用法
# site.yml
---
- name: Deploy web application
hosts: webservers
become: yes
roles:
- nginx
- mysql
- app
带参数使用
# site.yml
---
- name: Deploy web application
hosts: webservers
become: yes
roles:
- role: nginx
vars:
nginx_version: "1.24.0"
nginx_port: 8080
nginx_sites:
- name: myapp
template: myapp.conf.j2
- role: mysql
vars:
db_port: 3307
db_name: myapp_db
- role: app
使用 import_role
tasks:
- name: Include nginx role
import_role:
name: nginx
vars:
nginx_port: 8080
使用 include_role
tasks:
- name: Include role dynamically
include_role:
name: "{{ item }}"
loop:
- nginx
- mysql
- app
Role 依赖
meta/main.yml
---
# 角色依赖关系
# 这些角色会在当前角色之前执行
dependencies:
- role: common
vars:
timezone: Asia/Shanghai
- role: ssl
vars:
ssl_cert_path: /etc/ssl/certs
依赖链
site.yml
├── role: webserver
│ ├── dependencies:
│ │ └── role: common
│ │ └── dependencies: (none)
│ └── tasks/main.yml
└── tasks/main.yml
Role 测试
测试结构
tests/
├── inventory
│ ├── hosts
│ └── group_vars/
│ └── all.yml
└── test.yml
test.yml
---
- name: Test nginx role
hosts: testhosts
become: yes
roles:
- role: nginx
vars:
nginx_port: 80
运行测试
# 使用 molecule 测试
molecule test
# 手动测试
ansible-playbook -i tests/inventory tests/test.yml --syntax-check
ansible-playbook -i tests/inventory tests/test.yml
完整示例:Web 应用 Role
目录结构
roles/
└── webapp/
├── defaults/
│ └── main.yml
├── files/
│ └── init.sh
├── handlers/
│ └── main.yml
├── meta/
│ └── main.yml
├── tasks/
│ ├── main.yml
│ ├── install.yml
│ ├── configure.yml
│ └── deploy.yml
├── templates/
│ ├── app.conf.j2
│ └── systemd.service.j2
└── vars/
└── main.yml
defaults/main.yml
---
webapp_name: myapp
webapp_version: "1.0.0"
webapp_user: www-data
webapp_group: www-data
webapp_home: /opt/{{ webapp_name }}
webapp_port: 8080
webapp_environment: production
webapp_git_repo: ""
webapp_git_version: HEAD
webapp_requirements: []
webapp_service_state: started
webapp_service_enabled: yes
webapp_db_host: localhost
webapp_db_port: 3306
webapp_db_name: myapp
webapp_db_user: myapp
webapp_db_password: ""
webapp_redis_host: localhost
webapp_redis_port: 6379
tasks/main.yml
---
- name: Include install tasks
include_tasks: install.yml
- name: Include configure tasks
include_tasks: configure.yml
- name: Include deploy tasks
include_tasks: deploy.yml
tasks/install.yml
---
- name: Create application user
user:
name: "{{ webapp_user }}"
group: "{{ webapp_group }}"
system: yes
create_home: no
shell: /bin/false
- name: Create application directories
file:
path: "{{ item }}"
state: directory
owner: "{{ webapp_user }}"
group: "{{ webapp_group }}"
mode: '0755'
loop:
- "{{ webapp_home }}"
- "{{ webapp_home }}/config"
- "{{ webapp_home }}/data"
- "{{ webapp_home }}/logs"
- "{{ webapp_home }}/tmp"
- name: Install Python packages
pip:
name: "{{ webapp_requirements }}"
virtualenv: "{{ webapp_home }}/venv"
virtualenv_command: python3 -m venv
when: webapp_requirements | length > 0
tasks/configure.yml
---
- name: Copy configuration file
template:
src: app.conf.j2
dest: "{{ webapp_home }}/config/app.conf"
owner: "{{ webapp_user }}"
group: "{{ webapp_group }}"
mode: '0600'
notify: Restart app
- name: Copy systemd service file
template:
src: systemd.service.j2
dest: /etc/systemd/system/{{ webapp_name }}.service
notify: Reload systemd
- name: Reload systemd
systemd:
daemon_reload: yes
tasks/deploy.yml
---
- name: Clone or update repository
git:
repo: "{{ webapp_git_repo }}"
dest: "{{ webapp_home }}/current"
version: "{{ webapp_git_version }}"
force: yes
accept_hostkey: yes
when: webapp_git_repo | length > 0
notify: Restart app
- name: Set permissions
file:
path: "{{ webapp_home }}"
owner: "{{ webapp_user }}"
group: "{{ webapp_group }}"
recurse: yes
- name: Ensure service is started
service:
name: "{{ webapp_name }}"
state: "{{ webapp_service_state }}"
enabled: "{{ webapp_service_enabled }}"
handlers/main.yml
---
- name: Restart app
systemd:
name: "{{ webapp_name }}"
state: restarted
- name: Reload systemd
systemd:
daemon_reload: yes
下一步
现在你已经掌握了 Roles 的使用。接下来让我们学习常用模块。
👉 常用模块详解