Mantra Networking Mantra Networking

Ansible: Roles

Ansible: Roles
Created By: Lauren R. Garcia

Table of Contents

  • Overview
  • What are Ansible Roles?
  • Standard Directory Structure
  • Creating a Role with Ansible Galaxy
  • Documenting Roles
  • Using Roles in a Playbook
  • Role Dependencies
  • Best Practices
  • Conclusion

Ansible Roles: Overview, Need, and How They Work

What Is an Ansible Role?

Ansible roles are a core feature within the Ansible automation platform, designed to help you structure, modularize, and reuse your automation code. Think of roles as reusable building blocks that group related configuration tasks, files, variables, templates, and handlers within a standardized directory structure. Each role focuses on a particular function—like installing Apache, configuring system users, or setting up security policies.

Why Should You Care About Ansible Roles?

  • Modularity and Reuse
    Roles allow you to write a piece of automation logic once and reuse it everywhere. This means you can easily share your work across projects or teams, saving time and reducing errors.
  • Maintainability
    With roles, code is organized into clear, logical segments. Making updates to a function (such as adding new features or fixing bugs) is much easier since everything related to that feature is in one place.
  • Team Collaboration
    Organized code is easier to review and collaborate on. By using roles, teams can split up work, review each role independently, and avoid conflicts.
  • Scalability
    As your infrastructure grows in complexity, managing code in a monolithic playbook gets cumbersome. Roles help break up large projects into manageable, scalable chunks.
  • Best Practices
    Using roles encourages practices like documentation, code versioning, and separating configuration logic from data, making your automation projects more reliable and professional.

How Do Ansible Roles Work?

  1. Directory Structure
    Each role has its own directory (e.g., roles/webserver/) and a recommended set of subfolders (for tasks, variables, templates, files, handlers, defaults, meta, etc.). This hierarchical structure makes it easy for Ansible to know where to find logic related to the role.
  2. Including Roles in Playbooks
    • You declare the roles you need within your playbook using the roles: section.
    • Ansible then loads all content (tasks, handlers, variables, etc.) from the relevant role directories automatically, injecting them into the execution flow.
    • Roles can also be brought in dynamically based on certain conditions using the include_role directive for even greater flexibility.
  3. Role Dependencies
    • A role can automatically pull in other roles it depends on via its meta/main.yml file. For example, your webserver role can require the user_setup and common_security roles to run beforehand.
  4. Customization with Variables
    • Roles are built to be flexible: they use variables, which can be overridden from the playbook, inventory, or command line, letting you reuse a single role in different contexts without rewriting code.
  5. Sharing and Publishing
    • Once created, roles can be shared locally or published to platforms like Ansible Galaxy, making it easy to distribute automation logic to the broader community or your team.

In summary, Ansible roles are your toolkit for clean, organized, and scalable automation. By adopting roles, you embrace best practices that make your infrastructure projects easier to develop, maintain, and share—no matter how complex your environment becomes.

What are Ansible Roles?

Ansible roles are a powerful feature designed to help users organize automation content in a modular, reusable, and scalable way. Roles allow you to group related tasks, files, variables, templates, and handlers together, making automation projects easier to maintain and share.

  • Encapsulation of Functionality: Roles bundle all automation logic for a specific function (like installing NGINX, configuring users, or managing firewall rules) inside a single, well-structured directory.
  • Predictable Directory Layout: Each role uses a standardized directory structure. This clear organization drives consistency, simplifies code navigation, and enables sharing code across teams or with the Ansible community.
  • Simplified Reuse and Sharing: By splitting configurations into roles, you can easily reuse them across different environments or projects, and even publish them on platforms (such as Ansible Galaxy).
  • Separation of Concerns: Roles make it easy to keep variables, templates, and task logic for different parts of your automation strictly separated, reducing complexity and chance of conflicts.
  • Declarative Playbook Usage: Once you have defined roles, you simply declare them in your playbook’s roles: section, making the main playbook concise and readable.

In summary: Ansible roles provide a modular architecture for automation workflows, improve reusability, and promote best practices in configuration management.

Standard Directory Structure

The standard directory structure of an Ansible role helps organize related automation tasks and components. This structure is recognized automatically by Ansible, enabling faster development, better readability, and easier reuse.

Here is a step-by-step breakdown of each directory inside a role:

  • tasks/
    Contains the role's primary list of tasks such as installations, configurations, and service restarts. The entry point is always main.yml.
  • handlers/
    Defines handlers that are triggered by tasks using the notify directive. Often used for actions like restarting services.
  • templates/
    Stores Jinja2 template files (e.g., configuration files) that can be dynamically rendered using variables.
  • files/
    Contains static files that can be copied to managed hosts without modification, such as scripts or binaries.
  • vars/
    Holds variables with a higher precedence than defaults. Useful for defining hard-coded role-specific values.
  • defaults/
    Stores default variable values. These have the lowest precedence and are often used for setting safe baseline values.
  • meta/
    Describes metadata about the role, including dependencies on other roles or platforms.
  • library/ (optional)
    Contains custom Ansible modules written in Python or other languages.
  • module_utils/ (optional)
    Includes helper libraries that can be shared between custom modules.
  • lookup_plugins/ (optional)
    Hosts custom plugins used to retrieve data from external sources, such as APIs or databases.

Typical skeleton of a role directory:

roles/
  my_role/
    tasks/
      main.yml
    handlers/
      main.yml
    templates/
    files/
    vars/
      main.yml
    defaults/
      main.yml
    meta/
      main.yml
  

This structure allows Ansible to locate and use each component of the role without needing manual inclusion in your playbooks.

Creating a Role with Ansible Galaxy

Ansible Galaxy provides an easy way to initialize a new role with all the required structure and documentation files, saving time and ensuring consistency. Here’s a step-by-step process to create a new role using ansible-galaxy:

  1. Navigate to Your Roles Directory:
    It’s best practice to keep roles organized. Start by creating (if needed) and moving into your roles directory:
    mkdir -p ~/ansible/roles
    cd ~/ansible/roles
  2. Initialize the Role Structure:
    Use the ansible-galaxy command to generate the complete directory skeleton for your new role. Replace myrole with your desired role name:
    ansible-galaxy init myrole
    This will scaffold a new folder called myrole with subdirectories and starter files for tasks, handlers, variables, templates, and more.
  3. Review the Created Structure:
    List the contents to see all generated directories and files:
    ls myrole
    You should see folders like tasks, handlers, defaults, vars, meta, templates, files, and documentation files such as README.md.
  4. Customize the Role:
    Edit the generated files (such as tasks/main.yml) and directories as needed to define the automation logic, variables, templates, and handlers specific to your use case.
  5. Document Your Role:
    Update README.md and meta/main.yml so that others understand the purpose, usage, and requirements of your role.

With these steps, your new role is ready for development, sharing, or integration into your automation projects.

Documenting Roles

Clear and thorough documentation is essential for every Ansible role. Well-documented roles simplify onboarding, promote reuse, and help ensure reliable automation by letting anyone understand the role’s purpose, requirements, and configuration quickly.

  1. Create a README.md File:
    Every role should include a README.md in the root of the role directory. This readme serves as the primary source of information for anyone using or reviewing the role.
  2. Describe the Role’s Purpose:
    Begin with a concise explanation of what the role does. For example:
    # NGINX Role
    Automates the installation and configuration of NGINX web server on target hosts.
          
  3. List Requirements and Dependencies:
    Specify any prerequisites: minimum Ansible version, other required roles, or platforms supported. Example:
    ## Requirements
    - Ansible 2.9 or higher
    - Compatible with Ubuntu 20.04, CentOS 8
    - Requires 'common' role
  4. Document Role Variables:
    Include a table or list describing all variables users can configure, with their default values and descriptions.
    ## Role Variables
    
    | Variable          | Default  | Description                |
    |-------------------|----------|----------------------------|
    | nginx_port        | 80       | HTTP listen port           |
    | nginx_user        | www-data | User for NGINX processes   |
    | nginx_sites       | []       | List of site definitions   |
  5. Provide Example Usage:
    Show users how to call the role in a playbook.
    ## Example Playbook
    
    - hosts: webservers
      roles:
        - role: nginx
          vars:
            nginx_port: 8080
            nginx_sites:
              - server_name: example.com
                root: /var/www/example
          
  6. Mention Any Outputs or Handlers:
    If the role creates outputs, facts, or includes special handlers, list or explain them for the user's reference.
  7. Include License and Author Information:
    End the documentation with license details and who maintains the role.
    ## License
    MIT
    
    ## Author Information
    Maintained by Network Automation Team
          

With clear documentation, roles become easier to use, debug, and share—making your automation projects more robust and collaborative.

Using Roles in a Playbook

Once your roles are defined, there are several methods to incorporate them into your Ansible playbooks. Using roles keeps your playbooks organized and enables modular, reusable automation. Here's a step-by-step overview of how to use roles in playbooks:

  1. Add Roles at the Play Level:
    The most common method is to declare roles under the roles: section of a play. Ansible will run all tasks defined in each role before any further tasks in the playbook.
    ---
    - hosts: webservers
      roles:
        - common
        - nginx
          

    This approach is straightforward and best for static, predictable automation workflows.

  2. Include Roles Dynamically at the Task Level:
    Use include_role within a tasks: section to insert roles dynamically. This is useful if you want to control when and under what conditions a role runs.
    ---
    - hosts: appservers
      tasks:
        - name: Print a message before the role
          ansible.builtin.debug:
            msg: "This task runs before the app role"
    
        - name: Include the app role dynamically
          include_role:
            name: app
    
        - name: Print a message after the role
          ansible.builtin.debug:
            msg: "This task runs after the app role"
          

    You can also pass variables or tags directly when using include_role:

    - name: Include role with specific variables
      include_role:
        name: database
      vars:
        db_port: 5432
      tags: db
          
  3. Use Conditional Role Inclusion:
    Include roles only when certain conditions are met, increasing flexibility.
    - name: Include the logging role only on RedHat systems
      include_role:
        name: logging
      when: ansible_facts['os_family'] == 'RedHat'
          

Summary: Roles can be used both statically (at the play level) or dynamically (within tasks), allowing you to customize the flow of your automation. This makes playbooks more scalable, modular, and maintainable for both simple and complex infrastructure deployments.

Role Dependencies

Many real-world automation tasks require certain prerequisites to be fulfilled before carrying out specialized tasks. Ansible roles support dependencies so you can automatically pull in and execute other roles before running the main role.

  1. Define Dependencies in meta/main.yml:
    Inside your role directory, open or create the meta/main.yml file. This is where you declare dependencies. For example:
    ---
    dependencies:
      - role: common
      - role: database
        vars:
          db_name: myapp
          db_user: myuser
      - role: apache
        vars:
          apache_port: 8080
    

    This configuration ensures that the common, database, and apache roles run before this role, with variables for database and apache passed as shown.

  2. Role Execution Order:
    Dependencies listed in meta/main.yml execute recursively and always before the current role. If listed as dependencies in multiple roles, a role will only be run once per play unless explicit duplicate execution is configured.
  3. Passing Variables to Dependencies:
    Use the vars: key under each dependency to send specific variables to that role when it runs as a dependency.
  4. Advanced: Handling Duplicate Dependencies:
    By default, Ansible avoids running the same dependency role more than once within a play. However, if you need a dependency to run multiple times with different parameters, the dependent role can use the allow_duplicates: true setting in its own meta/main.yml file.
    ---
    allow_duplicates: true
    

Best Practice Tip:
Keep dependencies minimal and related—design your roles to handle one job well, and use dependencies mainly for foundational configuration tasks shared by several roles (such as user setup, package installation, or database bootstrapping).

Best Practices

Adhering to best practices when creating and managing Ansible roles ensures your automation is reliable, maintainable, and scalable. Here’s a step-by-step breakdown of top recommendations:

  1. Keep Roles Focused and Single-Purpose:
    Design each role to handle a specific responsibility (such as installing a service, managing users, or configuring firewalls). This promotes modularity and makes roles easier to reuse and maintain.
  2. Document Thoroughly:
    Always provide a clear README.md for every role. Document the role’s purpose, variables, requirements, platform compatibility, usage examples, and any dependencies.
  3. Minimize Role Dependencies:
    Limit the number of dependencies declared in meta/main.yml. This helps keep roles loosely coupled and easier to test or use independently.
  4. Parameterize with Variables:
    Avoid hardcoding values. Use variables (preferably declared in defaults/main.yml and vars/main.yml) so roles are flexible across different environments.
  5. Structure Roles Consistently:
    Always follow the standard role directory structure. Place files, templates, handlers, defaults, and tasks in their dedicated directories to keep code organized.
  6. Test Your Roles:
    Use testing tools (like Ansible Molecule) to verify that your roles run correctly and reliably on all intended platforms before using them in production.
  7. Version Control Roles:
    Maintain all roles in a source control system (like Git). Tag significant updates and document changes in a changelog or release notes.
  8. Use Tags and Idempotency:
    Assign meaningful tags to tasks and handlers within roles for targeted execution. Ensure all tasks are idempotent—safe to run multiple times without causing issues.
  9. Review and Reuse Community Roles Carefully:
    When importing roles from external repositories or Ansible Galaxy, review them for quality and security before use. Prefer well-maintained and reputable roles.
  10. Encourage Collaboration and Feedback:
    Share roles with your team, welcome contributions, and be open to review. Collaborative development leads to more robust and widely usable roles.

Summary:
By following these best practices, your Ansible roles will be easier to share, audit, and integrate into a wide variety of automation workflows, leading to more predictable and trustworthy infrastructure as code.

Conclusion

Throughout this blog post, we've taken a deep dive into Ansible roles — a key concept for structuring, simplifying, and scaling your automation workflows.

Here’s what we’ve covered:

  • What Ansible Roles Are: Modular, reusable building blocks for automating infrastructure tasks.
  • Standard Directory Structure: A predictable folder layout that keeps your code clean and maintainable.
  • Creating Roles with Ansible Galaxy: A quick way to scaffold new roles properly from the start.
  • Documenting Roles: Essential documentation practices that help others understand and reuse your work.
  • Using Roles in Playbooks: Various methods for statically and dynamically including roles in your Ansible runs.
  • Role Dependencies: How to manage and declare related roles your automation relies on.
  • Best Practices: Design principles and recommendations to help you write roles that are reliable, readable, and collaborative.

Whether you’re a seasoned automation engineer or just starting your Ansible journey, roles are the way to scale your playbooks and keep your infrastructure-as-code organized.

Thanks for reading! If you found this guide helpful, feel free to share it and drop any thoughts or questions in the comments. And don’t forget — the best automation is the one you can trust and reuse. 🔁

Happy automating! 🔧🧠🚀