Ansible Roles

Paul Hill

April 2, 2024 • 12 min read

    Introduction to Ansible Roles

    Ansible is a valuable automation tool that enables IT professionals to manage infrastructure more consistently and efficiently. One of its most practical features is Ansible Roles, which streamline the automation process by organizing tasks, templates, files, and variables into reusable sets.

    What are Ansible Roles?

    Ansible Roles are like toolkits for IT automation. They bundle everything you need to automate specific parts of your IT environment into one package. This makes setting up and managing services or functions much simpler, turning complex automation tasks into manageable, reusable components.

    Take your ansible skills to the next level!

    Want to become an Ansible pro? Then take our course Ansible for Complete Beginners! This course includes video lessons, written articles, quizzes, in-browser IT labs, and AI assistants to help you learn quicker than ever! Click the course below to sign up now!

    Course: Ansible for Complete Beginners

    What is Ansible? Ansible is an easy to learn automation tool that streamlines complex IT tasks with …

    58 Lessons
    6 Quizzes
    8 Labs
    18.5 Hr

    Why Roles Are Useful in Ansible

    Roles organize your automation tasks, making your Ansible playbooks cleaner and more modular. This not only improves readability but also enhances the reusability of your automation logic. Whether you’re dealing with web servers, databases, or complex applications, roles make it easier to share, update, and understand your automation tasks.

    With Ansible Roles, you’re not just scripting; you’re building a scalable automation framework. They allow IT teams to focus on the broader picture of infrastructure management without getting lost in the details.

    Understanding Ansible Roles

    Roles in Ansible are a way of grouping related tasks and other resources together. They are essentially frameworks for fully independent or interdependent collections of variables, tasks, files, templates, and modules.

    The primary goal of roles is to facilitate playbook organization and reusability. This is particularly useful when managing complex playbooks, as roles can be used to break down the configuration into manageable sections.

    A typical role directory structure might look like this:

    • tasks: Contains the main list of tasks to be executed by the role.
    • handlers: Contains handlers, which are tasks that only run when notified by another task
    • defaults: Default variables for the role.
    • vars: Other variables for the role.
    • files: Contains files which can be deployed via this role.
    • templates: Contains templates which can be deployed via this role.
    • meta: Defines some meta data for this role.

    There can be even more folders included in a role directory for more advanced usage of Ansible, like library, module_utils, lookup_plugins. These go beyond the scope of this course but you can learn more about these at the official Ansible documentation if you have a need for such advance configuration.

    Here is a link to Ansibles official docs on Roles if you are curious. Again, probably not needed for 95% of Ansible’s use cases but they do exist so I want you to be aware of them.

    Best Practices for Role Creation

    Creating efficient and reusable roles involves more than just knowing the directory structure. Here are some best practices to follow:

    • Modularity: Design roles to be as modular as possible. A role should do one thing and do it well, without becoming overly complex.
    • Variable Use: Make use of defaults and vars to make your roles customizable and flexible. Remember, default variables can be overridden, so use them for values that you expect might need to be changed.
    • Documentation: Always document your roles. Include comments in your playbooks and README files in your role directories to explain what each role does and how it should be used.
    • Testing: Test your roles thoroughly. Make sure they do what you expect in different environments and with different configurations.
    • Ansible Galaxy: Use Ansible Galaxy for inspiration and as a resource for finding existing roles. It can save you time and effort if there’s already a role that does what you need.

    Understanding and implementing these best practices can significantly enhance the effectiveness and reusability of your Ansible roles. With a solid foundation in role creation, you’ll be well-equipped to tackle more complex automation tasks efficiently.

    Directory Structure and Their Purposes

    1. tasks: This directory contains the main list of tasks to be executed by the role. Tasks are usually defined in a main.yml file. They’re the primary feature of any role, defining what the role will actually do.

      Example of tasks/main.yml:
       ---
       - name: Install Apache server
         apt:
           name: apache2
           state: present
    1. handlers: Handlers are triggered by tasks and are used for things like restarting services. They live in the handlers directory and are typically defined in a main.yml file.

      Example of handlers/main.yml:
       ---
       - name: restart apache
         service:
           name: apache2
           state: restarted
    1. defaults: This directory contains default variables for the role. Variables in defaults/main.yml are the most malleable and can be easily overridden.

      Example of defaults/main.yml:
       ---
       webserver_package: apache2
    1. vars: Variables that are more static and shouldn’t be overridden as easily as those in defaults go into vars/main.yml.

      Example of vars/main.yml:
       ---
       http_port: 80
    1. files: This directory is used for files that need to be transferred to the hosts without modification.

      Example usage: A file named example.txt in the files directory can be directly referenced in tasks.
    2. templates: It contains templates, which are files that Ansible will process with Jinja2 templating to create files dynamically. Templates typically end in .j2. Example usage: A Jinja2 template named index.html.j2 can be used to create a customized index.html file on the host.
    3. meta: This directory is used for metadata like role dependencies. It includes files that define some meta data about the role, such as dependencies on other roles. Example of meta/main.yml:
       ---
       dependencies:
         - { role: common, some_parameter: 3 }

    Understanding Role Execution

    When Ansible executes a role, it automatically loads files from these directories in a specific order. It begins with variables from defaults, then overrides them with anything in vars. Tasks are run next, handlers are notified if needed, files and templates are used as specified in tasks, and finally, any dependencies listed in meta are processed.

    Role Modularity

    Let’s understand how Ansible Roles can simplify your management of your servers. Imagine you have created four roles (without worrying about the code inside of each role):

    • Common Role
      • Updates server and creates a user account
    • Web Server Role
      • Installs and configures an NGINX web server
    • Database Role
      • Installs and configures MySQL
    • Restricted Access Role
      • Only allows certain users and IP addresses to access the server over SSH

    Now imagine you have three servers:

    • Web Server
    • Database Server
    • Management Server

    Ask yourself this, what roles would you apply to each server in your ansible playbook? We can mix and match our roles on these servers as desired. This would prevent us from needing to type the same set of tasks for each server. For example, we could assign the roles to our servers like so:

    Server NameConfigured Roles
    Web ServerCommon, Web Server
    Database ServerCommon, Database Role, Restricted Access
    Management ServerCommon
    Ansible Roles Modular Example

    The common role is used across all three servers, but we still have the ability to add the other roles as needed for each server. As you can see, this versatility allows us to quickly customize

    Creating the Ansible Role Directory Structure

    When setting up a role, it’s standard practice to create a specific directory structure which Ansible expects and uses to locate files and tasks to execute.

    Ansible will look for these folders in the directory where you run the ansible-playbook command. This is why it’s important to run the playbook command in the same directory where you files are located.

    Let’s start by creating the directory structure for our common role. Open your terminal and execute the following commands:

    mkdir -p ~/roles/common/{tasks,handlers,templates,files,vars,defaults,meta}

    For this example, most of these folders will remain empty, but it’s important for you to create them so you know that they exist and you can practice using them later.

    If you want to view our newly created directories in a pretty format, you can install the tree utility like so:

    sudo apt install tree

    This will allow us to run the tree command in our home directory and see our newly created role folders:

    paulh@ansible-controller:~$ tree
    .
    ├── ansible.cfg
    ├── ansible.cfg.example
    ├── first_playbook.yml
    ├── inventory
    └── roles
        └── common
            ├── defaults
            ├── files
            ├── handlers
            ├── meta
            ├── tasks
            ├── templates
            └── vars
    
    9 directories, 4 files

    Make sure your output looks the same as mine as it will be important in future lectures.

    Creating roles with Ansible Galaxy:

    You can also create roles with the Ansible Galaxy utility which is easier but might create files and directories you don’t need:

    ansible-galaxy init common

    That creates a directory like so:

    paulh@ansible-controller:~/roles$ tree common/
    common/
    ├── defaults
    │   └── main.yml
    ├── files
    ├── handlers
    │   └── main.yml
    ├── meta
    │   └── main.yml
    ├── README.md
    ├── tasks
    │   └── main.yml
    ├── templates
    ├── tests
    │   ├── inventory
    │   └── test.yml
    └── vars
        └── main.yml
    
    8 directories, 8 files

    Install Roles with Ansible Galaxy

    Using the Ansible Galaxy Utility for Role Creation

    The Ansible Galaxy utility doesn’t just help in creating roles; it’s also a great resource for finding and using roles created by others. When you’re starting on a new task or project, it’s worth searching through Ansible Galaxy to see if there’s already a role that fits your needs. This can save you time and effort in building something from scratch.

    To find roles in Ansible Galaxy, use the search feature on the Ansible Galaxy website or use the command line tool:

    ansible-galaxy search role_name

    When you find a role you’d like to use, you can easily install it with:

    ansible-galaxy install author.role_name
    

    This command downloads the role to your local Ansible roles directory, making it available for use in your playbooks.

    Adding tasks to our common role:

    If you’re creating a role from scratch, you will want to define the tasks for our role, we can open the main.yml file in your favorite editor:

    nano roles/common/tasks/main.yml

    Add the following content:

    ---
    # tasks file for common
    - name: Update all packages to the latest version
      apt:
        update_cache: yes
        upgrade: dist
      become: yes

    This task ensures that all the packages on the server are updated to their latest versions.

    You will notice we don’t need to define the hosts or prefix out tasks with the tasks directive, instead we just start listing the tasks for this role.

    This is because Ansible already knows (due to the folder structure and file naming) that this is a set of tasks for a particular role.

    Now if I tree my home directory, I now see the following output:

    paulh@ansible-controller:~$ tree
    .
    ├── ansible.cfg
    ├── ansible.cfg.example
    ├── first_playbook.yml
    ├── inventory
    └── roles
        └── common
            ├── defaults
            ├── files
            ├── handlers
            ├── meta
            ├── tasks
            │   └── main.yml
            ├── templates
            └── vars
    
    9 directories, 5 files

    That looks good! We are done adding our task to this role.

    Adding the role to an existing playbook

    No matter if you installed an existing role from Ansible Galaxy or you created your own, it’s time to add that role to our playbook and execute the playbook.

    To get started, you’ll be modifying the playbook located at ~/first_playbook.yml. Open this playbook in a text editor:

    nano ~/first_playbook.yml

    Add the common role to this playbook and remove our previously defined tasks. The playbook should now look like this:

    ---
    - hosts: all
      become: yes
      roles:
        - common

    Notice that we set become to be yes (equivillent to true). This will require the sudo password for each node. We’ll deal with that shortly.

    Here, the playbook is configured to run on all hosts, and it includes the common role which we created in earlier lessons.

    As always, make sure you run the ansible-playbook command from the home directory where we have been creating the role folders and files, where our inventory and ansible.cfg files are located as that is quite important.

    Running the Playbook

    Finally, execute the playbook to apply the common role to your servers. Run the following command:

    ansible-playbook first_playbook.yml

    This command will start the Ansible playbook, applying the common role across all specified hosts. When we execute this playbook, we will see an error output like so:

    Ansible Playbook Error: Missing Sudo Password
    Ansible Playbook Error: Missing Sudo Password

    This error occurs because we haven’t defined our user password yet. You’ll learn about how to securely store passwords with Ansible Vault and become password files later, for now, let’s configure Ansible to simply prompt for the sudo / become password.

    But first, how do we figure out if this is even possible? By reviewing the help files, of course!

    If you run ansible-playbook --help, you will see an option for -K, --ask-become-pass. We could pass this to our command to have Ansible prompt us for the become password.

    ansible-playbook first_playbook.yml --ask-become-pass

    Now that you specify the –ask-become-pass argument, you can now specify the become password for your servers.

    Conclusion

    Ansible roles are powerful tools for simplifying and scaling your automation efforts. By organizing your automation tasks into reusable roles, you can make your playbooks more efficient, easier to manage, and more maintainable. Remember:

    • Roles are essential for structuring your Ansible playbooks.
    • Sharing and reusing roles through Ansible Galaxy enhances the community and your own projects.
    • Before building a new role, check Ansible Galaxy to leverage the community’s work.

    Ansible’s ecosystem thrives on collaboration and sharing. Contributing to it not only helps others but also exposes you to new ideas and approaches to automation.

    To deepen your understanding of Ansible roles and other automation practices, consider signing up for courses available on Server Academy. These courses are designed to help you expand your skills and advance your career in IT automation.

    We’d love to hear about your experiences with Ansible roles. Have you created or used any roles that significantly improved your automation workflows? Share your stories and tips in the comments below.

    Coding and AutomationDevOpsLinux

    Want to improve your IT skillset? Start with a free account and get access to our IT labs!

    Blogpostctadesktop

    Sign up free and start learning today!

    Practice on REAL servers, learn from our video lessons, interact with the Server Academy community!