Advanced Ansible Playbooks Roles and Dependencies

By Raman Kumar

Updated on Aug 29, 2024

In this tutorial, we'll explain advanced Ansible playbooks roles and dependencies on Ubuntu 24.04 server. 

Ansible is a powerful tool that allows you to manage and configure systems at scale. As your playbooks grow in complexity, maintaining readability and reusability becomes crucial. This is where roles and dependencies come into play. By structuring your playbooks with roles and managing dependencies efficiently, you can create robust, scalable, and maintainable automation scripts. This tutorial will guide you through the process of creating and managing complex Ansible playbooks using roles, dependencies, and dynamic includes.

Introduction to Ansible Roles

Ansible roles are a way to group tasks, variables, files, handlers, and other Ansible elements into reusable units. Roles help you break down complex playbooks into smaller, more manageable pieces. This not only improves readability but also enhances reusability across different projects.

Key Components of a Role:

  • Tasks: The actions to be performed.
  • Handlers: Triggered actions, usually in response to tasks.
  • Variables: Parameters that can be passed into roles.
  • Files and Templates: Static files and Jinja2 templates to be used within tasks.
  • Defaults and Vars: Default and predefined variable values.

Creating Your First Ansible Role

To create an Ansible role, you can use the ansible-galaxy command:

ansible-galaxy init my_role

This command generates a directory structure like this:

my_role/
├── defaults
│   └── main.yml
├── files
├── handlers
│   └── main.yml
├── meta
│   └── main.yml
├── tasks
│   └── main.yml
├── templates
├── tests
│   ├── inventory
│   └── test.yml
└── vars
    └── main.yml

Explanation:

  • tasks/main.yml: The primary task file where you define what the role will do.
  • handlers/main.yml: Contains handlers, which are tasks triggered by other tasks.
  • meta/main.yml: Defines metadata for the role, including dependencies.
  • defaults/main.yml: Default variables for the role.
  • vars/main.yml: Variables that are used in the role.
  • files and templates: Directories for files and Jinja2 templates.

Structuring Playbooks with Roles

Using roles in your playbooks is straightforward. Here's an example of how to structure a playbook to include roles:

---
- name: Setup Web Server
  hosts: web_servers
  roles:
    - { role: common }
    - { role: webserver }

- name: Setup Database Server
  hosts: db_servers
  roles:
    - { role: common }
    - { role: database }

Explanation:

  • common: A role that contains tasks common to both web and database servers.
  • webserver: A role specifically for configuring web servers.
  • database: A role specifically for configuring database servers.

Managing Role Dependencies

Role dependencies allow you to specify which roles must be applied before the current role. Dependencies are defined in the meta/main.yml file of the role:

dependencies:
  - { role: common, some_var: some_value }
  - { role: another_role }

In this example, common and another_role will be executed before the role where this dependency is defined.

Using Dynamic Includes

Dynamic includes allow you to include tasks, handlers, or other playbooks based on conditions. This is particularly useful when you need to execute different tasks based on the environment or other variables.

---
- name: Include tasks based on condition
  include_tasks: "{{ item }}"
  with_items:
    - "tasks/setup.yml"
    - "tasks/configure.yml"
  when: some_condition

In this example, the tasks in setup.yml and configure.yml will be included and executed only if some_condition is true.

Best Practices for Ansible Playbook Organization

  • Use Roles for Reusability: Break down your playbooks into roles to enhance modularity and reusability.
  • Leverage Role Dependencies: Define dependencies in the meta/main.yml to ensure the correct order of execution.
  • Use Dynamic Includes Wisely: Include tasks dynamically based on conditions to handle complex scenarios.
  • Keep Variables Organized: Use defaults, vars, and group_vars to manage variables efficiently.
  • Document Your Roles: Clearly document what each role does, including input variables and outputs.

Create an Ansible Playbook

To create an Ansible playbook that installs the Nginx web server and MySQL database using roles and dependencies, you'll need to define two separate roles: one for Nginx and one for MySQL. Then, you'll create a playbook that applies these roles, taking advantage of dependencies.

Prerequisites

Before you begin, make sure you have the following:

  • An Ubuntu dedicated server or KVM VPS (or multiple servers) where you want to install Docker.
  • Ansible installed on your control machine.
  • Basic Linux command knowledge.
  • We have used Ubuntu 24.04 OS for host and target servers

Step 1: Create the Role for Nginx

First, create the Nginx role:

ansible-galaxy init nginx

Populate the nginx/tasks/main.yml file with the following tasks to install and configure Nginx:

nano nginx/tasks/main.yml

Add following content:

# nginx/tasks/main.yml
---
- name: Install Nginx
  apt:
    name: nginx
    state: present
  become: yes

- name: Ensure Nginx is running
  service:
    name: nginx
    state: started
    enabled: yes

Save and exit the file.

Step 2: Create the Role for MySQL

Next, create the MySQL role:

ansible-galaxy init mysql

Populate the mysql/tasks/main.yml file with the following tasks to install and configure MySQL:

nano mysql/tasks/main.yml

Add following content

# mysql/tasks/main.yml
---
- name: Install MySQL Server
  apt:
    name: mysql-server
    state: present
  become: yes

- name: Ensure MySQL is running
  service:
    name: mysql
    state: started
    enabled: yes

Save and exit the file.

Step 3: Define Role Dependencies

To manage dependencies, let's assume that the mysql role depends on some common tasks, such as installing prerequisites. Create a common role:

ansible-galaxy init common

Populate the common/tasks/main.yml file with tasks that are common across roles:

nano common/tasks/main.yml

Add following content

# common/tasks/main.yml
---
- name: Update APT cache
  apt:
    update_cache: yes
  become: yes

- name: Install basic packages
  apt:
    name:
      - curl
      - vim
      - git
    state: present
  become: yes

Save and exit the file.

Now, define the mysql role's dependencies in mysql/meta/main.yml:

nano mysql/meta/main.yml

Add following content

# mysql/meta/main.yml
---
dependencies:
  - role: common

This ensures that the common role is executed before the mysql role.

Step 4: Create the Playbook

Finally, create the main playbook that applies these roles:

nano site.yml

Add following content

# site.yml
---
- name: Install Nginx and MySQL
  hosts: web_servers
  become: yes
  roles:
    - nginx
    - mysql

Step 5: Define Inventory

You can define your inventory file to specify the web_servers group:

nano inventory

Replace the following IP address with your server's IP addresses. Add following content:

# inventory
[web_servers]
server1 ansible_host=192.168.1.10
server2 ansible_host=192.168.1.11

Save and exit the file

Step 6: Run the Playbook

To run the playbook, use the following command:

ansible-playbook -i inventory site.yml

Summary

  • Nginx Role: Installs and configures the Nginx web server.
  • MySQL Role: Installs and configures the MySQL database, with a dependency on the common role.
  • Common Role: Handles tasks common to all roles, such as updating the APT cache and installing basic packages.
  • Playbook: Applies the nginx and mysql roles to the web_servers group.

This structure ensures that your playbooks are modular, reusable, and easy to maintain. Each role is independent and can be reused across different playbooks, making your automation scripts more scalable and organized.

Conclusion

Creating and managing complex Ansible playbooks using roles, dependencies, and dynamic includes can significantly improve the organization and reusability of your automation scripts. By following the best practices outlined in this tutorial, you'll be well on your way to mastering advanced Ansible playbook structures, making your automation processes more efficient and maintainable.

This guide should help you get started with advanced Ansible playbook structuring, ensuring your scripts are both powerful and maintainable.