Four reference files covering: - ansible.md — core commands, ansible.cfg, key settings - ansible-inventory.md — static/dynamic inventory, directory layout - ansible-variables.md — 22-level precedence, scoping, merge behavior - ansible-roles.md — structure, defaults vs vars, dependencies
212 lines
5.7 KiB
Markdown
212 lines
5.7 KiB
Markdown
# Ansible Roles
|
|
|
|
> Reusable, self-contained units of automation with a standard directory structure.
|
|
|
|
## Role Directory Structure
|
|
|
|
```
|
|
roles/
|
|
└── nginx/
|
|
├── defaults/
|
|
│ └── main.yml # Low-precedence defaults (user overrides these)
|
|
├── vars/
|
|
│ └── main.yml # High-precedence vars (internal to role)
|
|
├── tasks/
|
|
│ └── main.yml # Entry point for tasks
|
|
├── handlers/
|
|
│ └── main.yml # Handlers triggered by notify
|
|
├── templates/
|
|
│ └── nginx.conf.j2 # Jinja2 templates
|
|
├── files/
|
|
│ └── index.html # Static files for copy module
|
|
├── meta/
|
|
│ └── main.yml # Dependencies, galaxy metadata
|
|
└── README.md
|
|
```
|
|
|
|
All directories are optional — include only what the role needs.
|
|
|
|
### What Goes Where
|
|
|
|
| Directory | Purpose | Precedence |
|
|
|-------------|--------------------------------|-------------|
|
|
| `defaults/` | Default variable values | **Lowest** — meant to be overridden |
|
|
| `vars/` | Internal role variables | **High** — not easily overridden |
|
|
| `tasks/` | Main task list | Entry point: `tasks/main.yml` |
|
|
| `handlers/` | Restart/reload triggers | Run once at end of play |
|
|
| `templates/` | Jinja2 files (`.j2`) | Referenced as `template: nginx.conf.j2` |
|
|
| `files/` | Static files | Referenced as `copy: src=index.html` |
|
|
| `meta/` | Role deps, platform info | Processed before role tasks run |
|
|
|
|
## Creating a Role
|
|
|
|
```bash
|
|
# Scaffold with ansible-galaxy
|
|
ansible-galaxy role init roles/nginx
|
|
|
|
# Minimal manual structure
|
|
mkdir -p roles/nginx/{tasks,defaults,templates,handlers,meta}
|
|
```
|
|
|
|
## Using Roles
|
|
|
|
### In a Playbook
|
|
|
|
```yaml
|
|
# site.yml
|
|
- hosts: webservers
|
|
roles:
|
|
- nginx # simple
|
|
- role: nginx # with params
|
|
vars:
|
|
nginx_listen_port: 8080
|
|
- role: nginx # conditional
|
|
when: install_nginx | bool
|
|
- role: nginx # tagged
|
|
tags: [web, nginx]
|
|
```
|
|
|
|
### With `include_role` / `import_role`
|
|
|
|
```yaml
|
|
tasks:
|
|
# Static import — processed at parse time
|
|
- import_role:
|
|
name: nginx
|
|
|
|
# Dynamic include — processed at runtime (supports loops/conditionals)
|
|
- include_role:
|
|
name: "{{ item }}"
|
|
loop:
|
|
- nginx
|
|
- certbot
|
|
```
|
|
|
|
| | `import_role` | `include_role` |
|
|
|---|---|---|
|
|
| When parsed | Playbook load | Runtime |
|
|
| Tags/when | Applied to all tasks inside | Applied to include itself |
|
|
| Loops | Not supported | Supported |
|
|
| Handlers | Visible globally | Scoped to include |
|
|
|
|
## Role Dependencies
|
|
|
|
```yaml
|
|
# roles/nginx/meta/main.yml
|
|
dependencies:
|
|
- role: common
|
|
- role: firewall
|
|
vars:
|
|
firewall_allowed_ports:
|
|
- 80
|
|
- 443
|
|
```
|
|
|
|
Dependencies run **before** the role's own tasks. Duplicate dependencies are skipped unless `allow_duplicates: true` is set.
|
|
|
|
## Example Role: nginx
|
|
|
|
```yaml
|
|
# roles/nginx/defaults/main.yml
|
|
nginx_listen_port: 80
|
|
nginx_worker_processes: auto
|
|
nginx_server_name: "_"
|
|
nginx_root: /var/www/html
|
|
nginx_access_log: /var/log/nginx/access.log
|
|
```
|
|
|
|
```yaml
|
|
# roles/nginx/tasks/main.yml
|
|
- name: Install nginx
|
|
apt:
|
|
name: nginx
|
|
state: present
|
|
update_cache: true
|
|
|
|
- name: Deploy configuration
|
|
template:
|
|
src: nginx.conf.j2
|
|
dest: /etc/nginx/nginx.conf
|
|
owner: root
|
|
group: root
|
|
mode: "0644"
|
|
notify: Reload nginx
|
|
|
|
- name: Enable and start nginx
|
|
service:
|
|
name: nginx
|
|
state: started
|
|
enabled: true
|
|
```
|
|
|
|
```yaml
|
|
# roles/nginx/handlers/main.yml
|
|
- name: Reload nginx
|
|
service:
|
|
name: nginx
|
|
state: reloaded
|
|
```
|
|
|
|
## Splitting Tasks
|
|
|
|
```yaml
|
|
# roles/nginx/tasks/main.yml
|
|
- import_tasks: install.yml
|
|
- import_tasks: configure.yml
|
|
- import_tasks: service.yml
|
|
|
|
# Conditional platform tasks
|
|
- import_tasks: debian.yml
|
|
when: ansible_os_family == "Debian"
|
|
- import_tasks: redhat.yml
|
|
when: ansible_os_family == "RedHat"
|
|
```
|
|
|
|
## Project Layout with Roles
|
|
|
|
```
|
|
ansible-project/
|
|
├── ansible.cfg
|
|
├── site.yml # Master playbook
|
|
├── webservers.yml # Play for web tier
|
|
├── dbservers.yml # Play for db tier
|
|
├── inventory/
|
|
│ ├── hosts.yml
|
|
│ ├── group_vars/
|
|
│ └── host_vars/
|
|
├── roles/
|
|
│ ├── common/ # Shared baseline
|
|
│ ├── nginx/
|
|
│ ├── postgresql/
|
|
│ └── requirements.yml # Galaxy dependencies
|
|
└── collections/
|
|
└── requirements.yml # Collection dependencies
|
|
```
|
|
|
|
```yaml
|
|
# roles/requirements.yml
|
|
- src: geerlingguy.docker
|
|
version: "6.1.0"
|
|
- src: geerlingguy.certbot
|
|
```
|
|
|
|
```bash
|
|
ansible-galaxy install -r roles/requirements.yml -p roles/
|
|
```
|
|
|
|
## Gotchas
|
|
|
|
- `defaults/` is for users to override; `vars/` is for role internals — mixing them up breaks precedence
|
|
- Handlers run at end of play, not after each task — use `meta: flush_handlers` if needed mid-play
|
|
- Role names must be valid Python identifiers (no hyphens) when used as variable namespaces
|
|
- `import_role` makes role tasks visible to `--list-tasks`; `include_role` does not
|
|
- Dependencies declared in `meta/` run every time the role is referenced unless deduplicated
|
|
- Template paths are relative to `templates/` — use `nginx.conf.j2`, not `templates/nginx.conf.j2`
|
|
- File paths in `copy` are relative to `files/` — use `index.html`, not `files/index.html`
|
|
|
|
## See Also
|
|
|
|
- `ansible` — core commands and ansible.cfg
|
|
- `ansible-variables` — how defaults/ vs vars/ fits into precedence
|
|
- `ansible-inventory` — inventory structure for role-consuming projects
|