Skip to content

Ansible Roles

See roles in Ansible.
Roles are used to organize and reuse playbook content.

Roles are essentially a collection of tasks and their associated resources (variables, templates, handlers, etc.) packaged together for a specific purpose.
The purpose can be something like configuring a web server or setting up a database.

They're somewhat similar to classes in object-oriented programming.

Table of Contents

Role Directory Structure

A role has a predefined structure with specific directories for different types of content.
This is what a typical role looks like:

roles/
└── myrole/
    ├── tasks/           # Contains the main list of tasks to execute
       └── main.yml     # Entry point for tasks
    ├── handlers/        # Contains handlers (triggered by tasks)
       └── main.yml
    ├── templates/       # Contains Jinja2 template files
    ├── files/           # Contains static files to copy to remote machines
    ├── vars/            # Contains variable definitions (static)
       └── main.yml
    ├── defaults/        # Contains default variable definitions (can be overridden)
       └── main.yml
    ├── meta/            # Contains metadata about the role (dependencies, etc.)
       └── main.yml
    └── tasks/main.yml   # Main entry point for the role
* tasks/: Where you define the main tasks for the role.
handlers/: Define handlers that are triggered by notify directive in tasks.
templates/: Store Jinja2 templates for dynamically generating files.
files/: Store static files that can be copied to remote hosts.
vars/: Define variables that are specific to the role.
defaults/: Define default values for variables (lowest precedence).
meta/: Include metadata about the role (like depenencies).


Creating and Using a Role

Creating a Role

You can manually create the directory structure.
You can also use the ansible-galaxy command:

ansible-galaxy init roles/myrole  # Initialize a new role
This will generate the full directory structure for a role named myrole under the roles directory.


Defining Role Tasks

The file roles/myrole/tasks/main.yml is used to define tasks for the role.

- name: Install NGINX
  apt:
    name: nginx
    state: present
    update_cache: yes

- name: Enxure NGINX is started
  service:
    name: nginx
    state: started
    enabled: yes


Using a Role in a Playbook

Use the name of the role in a playbook using the roles key.

- name: Example Playbook play
  hosts: webserver
  roles:
    - myrole
The playbook calls the myrole role.
This runs the tasks and resources defined in the role (roles/myrole).

NOTE: If you have a playbook that you're inheriting roles in (as above), any tasks in that playbook will always happen after roles are executed.
If you need tasks to happen before roles, use pre_tasks instead of tasks.


Where you can Use Roles

  • Playbooks
    - hosts: webservers
      roles:
        - myrole
        - otherrole
    
  • Role dependencies
    • Roles can depend on other roles. Define dependencies in roles/myrole/meta/main.yml
      dependencies:
        - role: common
        - role: firewall
        - role: otherrole
      
  • In the include_role task. You can include roles dynamically in a task.
    - name: Include the myrole role
      include_role:
        name: myrole
    
  • In collections. Roles can be part of an Ansible collection.
    • This can make them easy to distribute and reuse.

Example of Using a Role in Ansible

Directory Structure

This is the directory structure for the example:

myproject/
├── roles/
│   └── nginx/
│       ├── tasks/
│          └── main.yml
│       ├── handlers/
│          └── main.yml
│       ├── templates/
│          └── nginx.conf.j2
│       ├── files/
│       ├── vars/
│          └── main.yml
│       ├── defaults/
│          └── main.yml
│       ├── meta/
│          └── main.yml
├── inventory
└── site.yml

Playbook: site.yml

- hosts: webservers
  roles:
    - nginx
* - Indicates the start of the play.
This will inherit and run all the tasks in the nginx role.
All tasks will be run on the webservers hosts defined in the inventory.yml

Role tasks: roles/nginx/tasks/main.yml

- name: Install NGINX
  apt:
    name: nginx
    state: present

- name: Deploy NGINX configuration
  template:
    src: nginx.conf.j2
    dest: /etc/nginx/nginx.conf
    mode: 0644

- name: Start and Enable NGINX
  service:
    name: nginx
    state: started
    enabled: yes

Basic Role Usage

  • Create a directory called roles:

    mkdir roles
    cd roles
    

  • Then initialize a role:

    ansible-galaxy init <role_name>
    
    Then a bunch of directories are created.
    This can be overwhelming at first but if you just need to run tasks then you only need look at the tasks directory.

  • Look in the <role_name>/tasks/ directory for a file called main.yml.
    Put any tasks you want to run in that file.

  • Then, in your playbook:

    - name: Name of the playbook
      hosts: your-hosts
      roles:
        - role_name
    
    All the tasks in that main.yml file should be run.

If you need to use variables, templates, etc., there are other directories where you put those (like <role_name>/vars for variables).

Using Variables to Assign Roles Dynamically

If you want to assign roles dynamically based on host variables, you can do:

- name: Apply roles based on host variables
  hosts: all
  roles:
    - "{{ assigned_roles }}"

Then, in your inventory:

[web_servers]
web1 ansible_host=192.168.1.10 assigned_roles=["webserver_role"]
web2 ansible_host=192.168.1.11 assigned_roles=["webserver_role"]

[db_servers]
db1 ansible_host=192.168.1.20 assigned_roles=["database_role"]
db2 ansible_host=192.168.1.21 assigned_roles=["database_role"]
* The assigned_roles variable will be used to determine which roles to run on each given host.

Variables with Roles

Specify variables to use inside roles in the role-name/vars/main.yml file.

When defining variables inside a role (roles/role_name/vars/main.yml), those variables will only be available inside the role itself. They will not be accesible in a playbook that calls that roll.

If you need to access variables inside the main playbook, use set_fact or define the variable in either the inventory, the playbook vars section, or a role default.

Example vars/main.yml:

# roles/role-name/vars/main.yml
my_var: "This is the value of the variable"
some_number: 2

These vars will then be available anywhere inside the role role-name:
- tasks/ - handlers/ - templates/ - files/ - meta/

Conditionally Calling Roles

You can set up conditions for roles in playbooks.

To do this, you specify a dictionary inline in the roles section.

roles:
  - role1
  - role2
  - role3
  - { role: role4, when: myvar | default(false) == true }
  - role5
This specifies a condition for the role role4.
The role4 role will only be run when the variable myvar is true. We're using a jinja2 filter to make it default to false if it's not defined.