Ansible Roles: Step-by-Step Guide (2025)

Blog Featured image for a blog with a title - Ansible Roles: Step-By-Step Guide

Ansible Roles: Step-by-Step Guide (2025)

Blog Featured image for a blog with a title - Ansible Roles: Step-By-Step Guide
Categories

Introduction

Ansible roles are a smart way to organize your automation projects. Instead of writing long, messy playbooks, you break everything into smaller, reusable parts called roles. Each role focuses on one task, like installing software, configuring a server, or setting up a firewall. This makes your work cleaner, faster, and easier to understand. Roles come with their own structure: tasks, variables, files, templates, and more. You can reuse the same role in different projects, saving time and avoiding repetition. It’s like building with blocks—just stack what you need. Roles are also great for teamwork. Everyone follows the same format, so it’s easier to collaborate and maintain your code.

Whether you’re working on a small task or a complex setup, roles help keep everything in order. They turn your automation into a well-organized, powerful system. Once you start using Ansible roles, you’ll wonder how you ever managed without them. And if you are new to automation or looking to sharpen your skills, taking an Ansible and Terraform course can help you master the tools and best practices for building scalable, efficient infrastructures.

In this blog, we will discuss the roles of Ansible and why it is useful. We will also explain Ansible role structure and how to create Ansible roles. We will also discuss tips and tricks useful for Ansible roles.

Let us begin by first discussing what Ansible roles really are.

What Are Ansible Roles?

Ansible roles provide a structured framework for organizing your tasks, variables, handlers, templates, and other files. They allow you to reuse and share your Ansible code. In this manner, we are able to reference and invoke them in our playbooks using only a small amount of code, whereas we are able to use a single role in dozens of projects without any need to copy our own code.

Why Are Roles Useful in Ansible?

Many users begin using Ansible to automate monotonous tasks by writing simple playbooks. As the new users automate more and more using playbooks, and their Ansible skills improve, they find themselves constrained when it comes to using only Ansible playbooks. Ansible roles to the rescue!

Roles make sharing code easy because they follow a standard, organized structure. Later, we will have witnessed an illustration on how we can achieve that with Ansible Galaxy.

The organization of our Ansible content in role allows us to have a more manageable structure when compared to using playbooks only. This may not apply to tiny projects but the larger the playbooks to work with the more are our projects.

Finally, organizing our Ansible logic into roles allows us to develop our automation projects into sensible groupings and adhere to the separation of concerns design pattern. Teamwork and speed are also enhanced in that various users have the capability to work on other different roles at the same time without changing the same playbooks.

Why Use an Ansible Role Instead of an Ansible Playbook?

Ansible Roles and Ansible Playbooks are two tools allowing the organization and execution of automation artifacts, whereas each of them has a distinct purpose. The choice to write Ansible Roles or to specify all your tasks within an Ansible Playbook is determined by the use case and depends on Ansible experience.

The majority of automation developers and system administrators start implementing automation content with single playbooks. A playbook is a list of automation actions that is then run against a specific inventory. Tasks may be combined into a play: a set of 1 or more tasks assigned to a certain host and run sequentially. A playbook contains one or more plays, with playbook providing a flexible means of implementing Ansible automation using a single file.

Playbooks are one of the most effective ways of automating using Ansible, but they are not always the optimal way of writing all of your tasks. When your automation becomes more complex and you need to reuse code, you should organize your work into Ansible Roles and call them from your playbooks.

The next example demonstrates how a role, linux-systemr-roles.timesync, is utilised in a playbook. More than 4 tasks would be needed to complete what is done by the single role in this case.

- name: Manage timesync with 3 servers
  hosts: targets
  vars:
    timesync_ntp_servers:
      - hostname: foo.example.com
        iburst: true
      - hostname: bar.example.com
        iburst: true
      - hostname: baz.example.com
        iburst: true
  roles:
    - linux-system-roles.timesync

Below, we have discussed Ansible role structure along with examples for better understanding.

Ansible Role structure

Let’s look at the standard role directory structure. We define a directory of the same name per role. In the inner one, files are organized into subdirectories by their role. You only need to include the directories that you are actually using.

To assist us with quickly creating a well-defined role directory structure skeleton, we can leverage the command ansible-galaxy init <your_role_name>. The ansible-galaxy command is included in Ansible, and no additional package is required to be downloaded.

Now let’s create a test structure for a role named test_role:

ansible-roles git:(master) x ansible-galaxy init test_role

Output: Role test_role was created

This command will generate the following directory structure:

image

Ansible looks for a main.yml file (or main.yaml) within these subdirectories to load its content. You can add other YAML files into certain directories. As an example, you may partition your tasks as distinct YAML files by some property.

  • defaults include default values for variables of the role. Here we define some sane default variables, but they have the lowest priority and are usually overridden by other methods to customize the role.
  • files contain static and custom files that the role uses to perform various tasks.
  • handlers are triggered by tasks of the role.
  • meta Includes metadata information for the role, its dependencies, the author, license, available platform, etc.
  • tasks can be executed by the role. This part could be considered similar to the task section of a playbook.
  • templates contain Jinja2 template files used by tasks of the role. (Read more about how to create an Ansible template.
  • tests include configuration files related to role testing.
  • vars contains variables defined for the role. Variables defined in vars/main.yml have a high precedence and will override variables defined in defaults/main.yml.

There is another directory that the ansible-galaxy init command does not automatically create, but which is mentioned in the official Ansible docs, and which you can find useful to have in some scenarios, and that is the library directory. We specify in it any custom modules and plugins that we have implemented and are used by the role. Last but not least, we also get a preconfigured README.md file that we can complete with details and helpful information about our role.

Let us now discuss how you create Ansible roles.

Creating Ansible Roles – Step by Step

Refactoring an Ansible playbook into a role is a common tactic. To do that we need to break down the various sections of a playbook and organize them into an Ansible role with the directories we have just seen in the previous section.

This section will discuss an example of the creation of the new role to install and configure a basic Nginx web server. To run along you should have VirtualBox, Ansible, and Vagrant installed on the local machine.

Ansible searches for referenced roles in common paths like the orchestrating playbook’s directory, the roles/ directory, or the configured roles_path configuration value. It can also be customized to set a path.

When referring to a role:

- hosts: all
  roles:
    - role: "/custom_path/to/the/role"

We use the ansible-galaxy init command to create the initial directory structure of a role called webserver contained within a parent directory called roles. For this example, we can delete the tests directory as we will not be using it. However, we will discover how to use all the rest of the directories, in our demo.

The final structure of our role looks like this:

image 1

First, let’s define the most fundamental part which is, its tasks. Head to the tasks directory and edit the main.yml file.

roles/webserver/tasks/main.yml

---
# tasks file for webserver

- name: Update and upgrade apt
  ansible.builtin.apt:
    update_cache: yes
    cache_valid_time: 3600
    upgrade: yes
 
- name: "Install Nginx to version {{ nginx_version }}"
  ansible.builtin.apt:
    name: "nginx={{ nginx_version }}"
    state: present
 
- name: Copy the Nginx configuration file to the host
  template:
    src: templates/nginx.conf.j2
    dest: /etc/nginx/sites-available/default
- name: Create link to the new config to enable it
  file:
    dest: /etc/nginx/sites-enabled/default
    src: /etc/nginx/sites-available/default
    state: link
 
- name: Create Nginx directory
  ansible.builtin.file:
    path: "{{ nginx_custom_directory }}"
    state: directory
 
- name: Copy index.html to the Nginx directory
  copy:
    src: files/index.html
    dest: "{{ nginx_custom_directory }}/index.html"
  notify: Restart the Nginx service

In this case, we set following few tasks updating operating system, installing Nginx web server and advancing a basic-custom configuration to demonstrate with it.

In our next step, we go to the defaults directory, where we can create defaults values of variables used in the tasks. In the event that these variables do not have a different definition, they will get absorbed and consumed by the role, but they are in general designed to be simply overwritten.

---
# defaults file for webserver
nginx_version: 1.18.0-0ubuntu1.3
nginx_custom_directory: /var/www/example_domain

Next up, in our vars directory we set values with a somewhat more important precedence that we do not intend to override on the play level. We are overriding the default variable which defines the custom directory of Nginx here.

roles/webserver/vars/main.yml

roles/webserver/defaults/main.yml

---
# vars file for webserver
nginx_custom_directory: /home/ubuntu/nginx

We specify any handler which is activated by our tasks in the handlers directory. We have one of these tasks and it contains such a keyword as notify because we need to be able to use our Restart the Nginx service worker.

roles/webserver/handlers/main.yml

---
# handlers file for webserver
- name: Restart the Nginx service
  service:
    name: nginx
    state: restarted

Under the templates directory, we are making use of a Jinja2 template file that our Nginx configuration uses to generate the required Nginx custom directory value by using one of our already defined variables.

roles/webserver/templates/nginx.conf.j2

server {
        listen 80;
        listen [::]:80;
        root {{ nginx_custom_directory }};
        index index.html;
        location / {
                try_files $uri $uri/ =404;
        }
}

We will create a root directory called files which contains a static file index.html which will act as our static demonstration webpage.

roles/webserver/files/index.html

<html>
 <head>
   <title>Hello from Ngnix </title>
 </head>
 <body>
 <h1>This is our test webserver</h1>
 <p>This Nginx web server was deployed by Ansible.</p>
 </body>
</html>

The meta directory is utilized in order to add metadata and information about the role. One also places here any role dependencies of other roles.

roles/webservers/meta/main.yml

galaxy_info:
  author: Ioannis Mosutakis
  description: Installs Nginx and configures a minimal test webserver
  company: ACME Corp
  license: Apache-2.0
  role_name: websercer
 
  min_ansible_version: "2.1"
 
 # If this is a Container Enabled role, provide the minimum Ansible Container version.
 # min_ansible_container_version:
 
 #
 # Provide a list of supported platforms, and for each platform a list of versions.
 # If you don't wish to enumerate all versions for a particular platform, use 'all'.
 # To view available platforms and versions (or releases), visit:
 # https://galaxy.ansible.com/api/v1/platforms/
 #
  platforms:
  - name: Ubuntu
    versions:
      - bionic
      - focal
 
  galaxy_tags:
    - nginx
    - webserver
    - development
    - test
 
dependencies: []
 # List your role dependencies here, one per line. Be sure to remove the '[]' above,
 # if you add dependencies to this list

Lastly, we update the README.md file accordingly. The generated file that comes with the ansible-galaxy init command has numerous hints and advice on how to fill this out neatly.

roles/webserver/README.md

Role Name
=========
 
Role Name
=========
 
This is a role created for demonstration purposes that configures a basic nginx webserver with a minimal configuration.
 
Requirements
------------
 
Any prerequisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required.
 
* Ansible
* Jinja2
 
Role Variables
--------------
 
A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well.
 
### defaults/main.yml
Default nginx installation variables.
 
* nginx_version: Specific version of nginx to install
* nginx_custom_directory: Custom directory for nginx installation
 
### vars/main.yml
Here we define variables that have high precedence and aren't intended to be changed by the play.
 
* nginx_custom_directory: Custom directory for nginx installation
 
Dependencies
------------
 
A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles.
 
Example Playbook
----------------
 
Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:
 
   - hosts: all
     become: true
     roles:
       - webserver
 
License
-------
 
Apache-2.0
 
Author Information
------------------
 
Ioannis Moustakis

Let us now look at an example where Ansible roles are used.

An Example for Using Ansible Roles

- hosts: all
  become: true
  roles:
    - webserver

After establishing all the required components of our role, we should start using it in plays. The available reference of a role at the play level by the use of the roles option is the most obvious and conventional:

In this case, every role identified in our playbook will be run before performing any other tasks identified in the play.

This is a test play to test our new webserver role. Let’s go ahead and execute this play. To follow along, run the vagrant up command at the very top directory of this repository to generate our intended remote host.

Once, All the tasks have been completed successfully. Let us as well confirm that our Ngnix web server is set up properly.

To log into our demo Vagrant host, use the command vagrant ssh host1. Then run systemctl status nginx system to make sure that Nginx service is active. Lastly, enter the command curl localhost to test whether the web server can react to the custom page we had created.

In case of play level, we may override the role’s default variables or pass other keywords, such as tags, when using the roles option. All roles have tags of Ansible used on all tasks.

- hosts: all
 become: true
 roles:
   - role: webserver
     vars:
       nginx_version: 1.17.10-0ubuntu1
     tags: example_tag

Here, we override the default variable nginx_version with another version.

Apart from defining roles at the play level with the roles option, we can use them also at the tasks level with the options include_role dynamically and import_role statically. We can use them when we want to execute our role tasks in a particular, and possibly non chronological, order. In this, roles move in consecutive order in which they are written in plays.

- hosts: all
  tasks:
    - name: Print a message
      ansible.builtin.debug:
        msg: "This task runs first and before the example role"
 
    - name: Include the example role and run its tasks
      include_role:
        name: example
 
    - name: Print a message
      ansible.builtin.debug:
        msg: "This task runs after the example role"
  
    - name: Include the example_2 role and run its tasks in the end
      include_role:
        name: example_2

See the official docs to gain finer control over the order in which you execute tasks in your role.

Although a role may be defined several times, Ansible will perform it only once. Sometimes we may like to run a role several times with different parameters. By passing different set of parameters to the same roles, it is now possible to execute the role multiple times.

Example of executing the role test three times:

- hosts: all
  roles:
    - role: test
      message: "First time"
    - role: test
      message: "Second time"
    - role: test
      message: "Third time"

Sharing Roles with Ansible Galaxy

Ansible Galaxy Ansible Galaxy is an online public, open-source repository of Ansible roles. We can search, download and use any of the shared roles there and take advantage of its community power. We have been already using its client, ansible-galaxy, which is part of Ansible and offers a framework to adding well structured roles.

Ansible Galaxy lets you search through the available roles and use them to save time on developing everything by scratch. At every role it is possible to view its code repository, documentation even rating given by other users. Always vet a roles code repository before running it. This is so that you can verify its safety and ascertain behavior. A blog post on How to rate the community Ansible roles can be found here. Interested in Galaxy? See its official documentation page.

In order to download and install a role using Galaxy command executes the following command: ansible-galaxy install. The installation command needed to execute the role is available on Galaxy most of the time. As an example, consider this role instating a PostgreSQL server.

Install the role with:

$ ansible-galaxy install geerlingguy.postgresql

Then use it in a playbook while overriding the default role variable postgresql_users to create an example user for us.

---
- hosts: all
  become: true
  roles:
    - role: geerlingguy.postgresql
      vars:
        postgresql_users:
          - name: xyz

Tips & Tricks Useful for Ansible Roles

Below, we have discussed some of the tricks that are useful for Ansible Roles.

  • Always use descriptive names for your roles, tasks, and variables instead of generic ones. Write down the purpose and the intent of your roles and identify any variables that the user must define. It would be wise to set sane defaults, so that you reduce your roles to the minimum, so that users can be onboarded fast.
  • Never place secrets and sensitive data in your roles’ YAML files. The play should deliver secret values during the execution time as a variable, but should certainly not be stored in any code repository.
  • Initially, one may be inclined to create a role that does a lot. As an example, we might establish a role that installs several components, which is an anti-pattern. As much as you can, attempt to utilize the separation of concerns design paradigm and divide your roles depending on various functionalities or technical parts.
  • You should always look to see how loosely coupled your roles are and how many dependencies you add.
  • To control the execution order of roles and tasks, use the import_role or Include_role tasks instead of the classic roles keyword.
  • Group your tasks into separate task files when it makes sense, so as to be clearer and organized.

Frequently Asked Questions

Q1. How to create roles of Ansible?

You can create roles of Ansible using the following 6-step guide

Step 1: Create the Ansible role folder.

Step 2: Create the Ansible role using Ansible Galaxy.

Step 3: Define the Ansible role default variable.

Step 4: Create a motd template.

Step 5: Create the role task.

Step 6: Create an Ansible Playbook to use the role.

Q2. What are Ansible handlers in Roles?

Ansible Handlers are a type of task that are only run when they are “notified” by another task. Handlers are defined in your Ansible roles or playbooks.

Q3. When to use roles of Ansible?

Use the roles of Ansible for larger or more complex projects. Roles simplify the use of Ansible Playbooks, instead of having a large playbook that includes all tasks, handlers, and templates.

Q4. What is Ansible rulebook?

Rulebooks are used for a special feature called Event-Driven Ansible. It is used to perform IT actions in an event-driven automation model.

Q5. What is an Ansible role vs playbook?

A playbook is a list of tasks to run. A role is a bundle of tasks and files packaged together for reuse. You call roles from inside a playbook.

Conclusion

The Ansible roles ensure automation is predictable, quick and less maintenance work. They assist with decomposing complicated tasks and dividing them into reusable and structured components, which increases transparency and team coordination. Whether you’re installing software, configuring servers, or managing services, roles let you organize your work efficiently and avoid repetition. Using and sharing community roles are also easy using Ansible Galaxy. Through best practices, roles emerge as potent building blocks, any automation project. Once you start using roles, you will write cleaner playbooks and manage your automation projects with greater ease.

Get in touch

Blog
Looking For Networking Training- PyNetLabs

Popular Courses

Automation

(FRESHERS / EXPERIENCED)

Network Expert

Automation

(FRESHERS / EXPERIENCED)

Network Expert

Automation

(FRESHERS / EXPERIENCED)

Network Expert

Automation

(FRESHERS / EXPERIENCED)

Network Expert

Automation

(FRESHERS / EXPERIENCED)

Network Expert

Leave a Reply

Your email address will not be published. Required fields are marked *