Role 目录结构与 Ansible Galaxy
核心问题:Playbook 越写越长、各项目重复逻辑越来越多——怎样把 Playbook 组织成可复用的"角色库"?
为什么要用 Role
当你的 Playbook 超过 100 行,或者多个项目需要复用相同配置逻辑时,把代码拆成 Role 是必要的:
| 问题 | Role 如何解决 |
|---|---|
| Playbook 文件太长,难以维护 | 按功能拆分,每个 Role 管一件事 |
| 多个项目重复同样的 Nginx 配置 | 提取为 nginx Role,各项目 import |
| 不同环境的变量覆盖难以管理 | Role 有 defaults/(可覆盖)和 vars/(强制)两级变量 |
| 团队协作时任务职责不清晰 | 按 Role 分工:infra team 写 base Role,dev team 写 app Role |
Role 标准目录结构
roles/
└── nginx/ # Role 名称
├── tasks/
│ ├── main.yml # 任务入口(必须有)
│ ├── install.yml # 安装任务(由 main.yml include)
│ └── configure.yml # 配置任务
├── handlers/
│ └── main.yml # Handler 定义
├── templates/
│ ├── nginx.conf.j2 # Jinja2 模板
│ └── vhost.conf.j2
├── files/
│ └── mime.types # 静态文件(直接 copy)
├── vars/
│ └── main.yml # 强制变量(优先级高,不易被覆盖)
├── defaults/
│ └── main.yml # 默认变量(优先级最低,设计为可覆盖)
├── meta/
│ └── main.yml # Role 元数据、依赖声明
└── README.md
各目录详解
defaults/main.yml — 默认变量
# roles/nginx/defaults/main.yml
# 这里的值是"建议默认值",调用者可以随意覆盖
nginx_port: 80
nginx_user: www-data
nginx_worker_processes: auto
nginx_worker_connections: 1024
ssl_enabled: false
nginx_access_log: /var/log/nginx/access.log
vars/main.yml — 强制变量
# roles/nginx/vars/main.yml
# 这里的值不应该被调用者轻易覆盖(只有 -e 命令行参数能覆盖)
nginx_config_dir: /etc/nginx
nginx_sites_available: /etc/nginx/sites-available
nginx_sites_enabled: /etc/nginx/sites-enabled
tasks/main.yml — 任务入口
# roles/nginx/tasks/main.yml
---
- name: 安装 Nginx
import_tasks: install.yml
tags: [nginx, install]
- name: 配置 Nginx
import_tasks: configure.yml
tags: [nginx, config]
tasks/install.yml
---
- name: 安装 Nginx 软件包
apt:
name: nginx
state: present
update_cache: true
- name: 确保 Nginx 开机自启
systemd:
name: nginx
enabled: true
state: started
tasks/configure.yml
---
- name: 生成 Nginx 主配置
template:
src: nginx.conf.j2
dest: "{{ nginx_config_dir }}/nginx.conf"
owner: root
mode: "0644"
validate: "nginx -t -c %s" # 应用前自动验证语法
notify: 重载 Nginx
- name: 删除默认虚拟主机
file:
path: "{{ nginx_sites_enabled }}/default"
state: absent
notify: 重载 Nginx
- name: 配置虚拟主机
template:
src: vhost.conf.j2
dest: "{{ nginx_sites_available }}/{{ item.domain }}"
loop: "{{ vhosts | default([]) }}"
notify: 重载 Nginx
- name: 启用虚拟主机
file:
src: "{{ nginx_sites_available }}/{{ item.domain }}"
dest: "{{ nginx_sites_enabled }}/{{ item.domain }}"
state: link
loop: "{{ vhosts | default([]) }}"
notify: 重载 Nginx
handlers/main.yml
---
- name: 重载 Nginx
service:
name: nginx
state: reloaded
- name: 重启 Nginx
service:
name: nginx
state: restarted
meta/main.yml — 依赖声明
# roles/nginx/meta/main.yml
galaxy_info:
role_name: nginx
author: myorg
description: "安装并配置 Nginx Web 服务器"
min_ansible_version: "2.14"
platforms:
- name: Ubuntu
versions: ["22.04", "24.04"]
dependencies:
- role: base # 先运行 base Role(安装基础工具)
- role: firewall # 先运行 firewall Role(开放端口)
vars:
open_ports: [80, 443]
使用 Role
# site.yml
---
- name: 配置 Web 服务器
hosts: webservers
become: true
roles:
- role: base # 最简形式
- role: nginx # 使用默认变量
- role: app
vars: # 覆盖 Role 默认变量
app_port: 3000
app_env: production
Ansible Galaxy:公共 Role 仓库
Ansible Galaxy 是官方 Role/Collection 仓库,包含数万个社区 Role。
查找和安装 Role
# 搜索
ansible-galaxy role search nginx
# 查看 Role 详情
ansible-galaxy role info geerlingguy.nginx
# 安装(到默认 ~/.ansible/roles/)
ansible-galaxy role install geerlingguy.nginx
# 安装到项目 roles/ 目录
ansible-galaxy role install geerlingguy.nginx -p roles/
# 安装特定版本
ansible-galaxy role install geerlingguy.nginx,3.2.0
requirements.yml — 依赖清单
团队协作时,统一用 requirements.yml 管理依赖,不把第三方 Role 提交到 Git:
# requirements.yml
---
roles:
- name: geerlingguy.nginx
version: "3.2.0"
- name: geerlingguy.certbot
version: "5.1.0"
- src: https://github.com/myorg/private-role.git
scm: git
version: main
name: myorg.private_role
collections:
- name: amazon.aws
version: "6.5.0"
- name: community.postgresql
version: "3.2.0"
# 安装所有依赖
ansible-galaxy install -r requirements.yml -p roles/
# CI 中执行(忽略已安装版本检查)
ansible-galaxy install -r requirements.yml -p roles/ --force
项目最佳目录结构
myproject/
├── ansible.cfg
├── site.yml # 主入口:import 各 playbook
├── webservers.yml # Web 服务器 Playbook
├── databases.yml # 数据库 Playbook
├── requirements.yml # Galaxy 依赖
├── inventory/
│ ├── production/
│ │ ├── hosts.yml
│ │ ├── group_vars/
│ │ └── host_vars/
│ └── staging/
│ ├── hosts.yml
│ └── group_vars/
├── roles/
│ ├── base/ # 自写:基础工具
│ ├── nginx/ # 自写:Nginx 配置
│ └── app/ # 自写:应用部署
└── playbooks/
├── deploy.yml
└── rollback.yml
常见错误
| 错误 | 原因 | 解决 |
|---|---|---|
role 'nginx' was not found | Role 路径不对 | 检查 roles_path(ansible.cfg)或用绝对路径 |
| 循环依赖:role A 依赖 B,B 依赖 A | meta 依赖设计问题 | 提取公共部分为独立 common Role |
defaults/ 变量被 Inventory 变量覆盖 | 这是设计行为(defaults 优先级最低) | 如果不想被覆盖,放到 vars/main.yml |
| Galaxy Role 与本地 Role 重名 | 命名冲突 | Galaxy Role 用 namespace.role 格式(如 geerlingguy.nginx) |
下一节:Jinja2 模板实战