Roles
A role is a structured, reusable package of tasks, handlers, templates, files, and variables. Roles let you organize automation into modular, shareable units instead of putting everything in one large playbook.
Role Directory Structure
Section titled “Role Directory Structure”roles/ nginx/ tasks/ main.yml # entry point for tasks handlers/ main.yml # handlers (e.g. restart nginx) templates/ nginx.conf.j2 # Jinja2 templates files/ index.html # static files to copy vars/ main.yml # role variables (high priority) defaults/ main.yml # default variables (low priority, easily overridden) meta/ main.yml # role metadata and dependencies README.mdOnly tasks/main.yml is required. All other directories are optional — include only what you need.
What Goes Where
Section titled “What Goes Where”| Directory | Purpose |
|---|---|
tasks/ | The actual work — install packages, copy files, configure services |
handlers/ | Tasks triggered by notify (e.g. restart, reload) |
templates/ | Jinja2 templates rendered with template module |
files/ | Static files copied with copy module |
vars/ | Variables with high precedence (hard to override) |
defaults/ | Variables with low precedence (intended to be overridden by the user) |
meta/ | Role metadata: author, license, dependencies |
Creating a Role
Section titled “Creating a Role”Manual
Section titled “Manual”Create the directory structure yourself:
mkdir -p roles/nginx/{tasks,handlers,templates,defaults,files,meta}With ansible-galaxy
Section titled “With ansible-galaxy”ansible-galaxy role init roles/nginxThis creates the full skeleton with all directories and placeholder files.
Example Role: nginx
Section titled “Example Role: nginx”defaults/main.yml
Section titled “defaults/main.yml”# Easily overridden by the usernginx_port: 80nginx_server_name: localhostnginx_worker_processes: autotasks/main.yml
Section titled “tasks/main.yml”---- name: Install nginx apt: name: nginx state: present update_cache: true
- name: Deploy nginx config template: src: nginx.conf.j2 dest: /etc/nginx/nginx.conf owner: root mode: "0644" notify: Restart nginx
- name: Deploy site config template: src: default-site.conf.j2 dest: /etc/nginx/sites-available/default notify: Reload nginx
- name: Ensure nginx is running service: name: nginx state: started enabled: truehandlers/main.yml
Section titled “handlers/main.yml”---- name: Restart nginx service: name: nginx state: restarted
- name: Reload nginx service: name: nginx state: reloadedtemplates/default-site.conf.j2
Section titled “templates/default-site.conf.j2”server { listen {{ nginx_port }}; server_name {{ nginx_server_name }};
location / { root /var/www/html; index index.html; }}Using a Role in a Playbook
Section titled “Using a Role in a Playbook”roles Keyword
Section titled “roles Keyword”---- name: Configure web servers hosts: webservers become: true roles: - nginx - certbot - myappRoles run before any tasks: in the same play.
With Variables
Section titled “With Variables”roles: - role: nginx vars: nginx_port: 8080 nginx_server_name: myapp.example.cominclude_role (Dynamic)
Section titled “include_role (Dynamic)”Include a role conditionally or within tasks:
tasks: - name: Include monitoring role include_role: name: monitoring when: enable_monitoring | default(true)import_role (Static)
Section titled “import_role (Static)”Imported at parse time (before execution). Conditions apply to every task in the role:
tasks: - name: Import database role import_role: name: postgresql tags: databaseimport_role vs include_role
Section titled “import_role vs include_role”import_role | include_role | |
|---|---|---|
| When resolved | Parse time (static) | Runtime (dynamic) |
when applies to | Every task in the role | The include itself |
| Tags | All role tasks inherit tags | Only the include is tagged |
| Loops | Not supported | Supported |
Use import_role by default; include_role when you need dynamic behavior (loops, conditional inclusion).
Ansible Galaxy
Section titled “Ansible Galaxy”Ansible Galaxy is a community hub for sharing roles and collections.
Install a Role
Section titled “Install a Role”ansible-galaxy role install geerlingguy.dockeransible-galaxy role install geerlingguy.nginxInstalls to ~/.ansible/roles/ by default.
requirements.yml
Section titled “requirements.yml”Pin roles and their versions:
roles: - name: geerlingguy.docker version: "6.1.0" - name: geerlingguy.nginx version: "3.2.0" - name: my-org.custom-role src: git+https://github.com/my-org/custom-role.git version: v1.0.0ansible-galaxy role install -r requirements.ymlCollections
Section titled “Collections”Modern Ansible packages roles and modules into collections:
ansible-galaxy collection install amazon.awsansible-galaxy collection install community.dockerCollections are the preferred distribution method for new content.
Role Dependencies
Section titled “Role Dependencies”In meta/main.yml, declare roles that must run before yours:
---dependencies: - role: nginx vars: nginx_port: 8080 - role: postgresqlWhen you use the myapp role, Ansible automatically runs nginx and postgresql first.
Dependencies are deduplicated — if two roles both depend on nginx, it runs only once (unless allow_duplicates: true is set).
Key Takeaways
Section titled “Key Takeaways”- A role is a directory with
tasks/,handlers/,templates/,defaults/, etc. - Put user-overridable variables in
defaults/(low priority); internal variables invars/(high priority). - Use
ansible-galaxy role initto scaffold,ansible-galaxy role installto pull community roles. - Pin role versions in
requirements.ymlfor reproducible builds. - Use
import_roleby default;include_rolefor dynamic/conditional inclusion. - Declare dependencies in
meta/main.ymlso prerequisite roles run automatically.