Introduction to Ansible Roles
Definition and Overview
Ansible is a popular tool used in IT automation, and within Ansible, a "role" holds a crucial place. An Ansible Role is essentially a way to bundle automation tasks, handlers, default variables, and other assets together. It acts like a blueprint, allowing users to reuse, share, and manage automation structures with ease. By using Ansible Roles, tasks become modular and more straightforward, promoting reusability and simplicity in defining complex configurations and automations.
Importance and Use Cases
The concept of the "Ansible Role" becomes highly valuable when you need to manage complex systems or workflows. Roles are indispensable for organizing and modularizing code into reusable units. They help in breaking down complex tasks into simpler, more manageable pieces, thus making the automation workflows less cluttered and more understandable.
Use cases of Ansible Roles are vast, ranging from configuring system prerequisites and managing users to deploying applications and ensuring that specific services are running on servers. Due to the modular nature of roles, they can be easily shared across different projects, promoting code reuse and consistency.
Architecture and Components
An "Ansible Role" is structured carefully, containing several components or directories, each holding specific types of content. Key components include:
Tasks
: The main list of tasks that the role will execute.Handlers
: Contains handlers, which may be used by this role or even outside this role.Defaults
: Default variables for the role.Vars
: Other variables for the role.Files
andTemplates
: Contains files or templates which can be deployed by this role.
Setting Up Ansible Roles
Prerequisites
Before diving into the setup of Ansible Roles, there are certain prerequisites you need to ensure:
- Ansible Installation: Ensure that Ansible is installed on the system where you plan to set up roles.
- Basic Knowledge: Having basic knowledge of YAML syntax, as Ansible Roles will involve working with YAML files.
- Access Privileges: Necessary access privileges to create and manage files and directories on the system.
Directory Structure
Ansible Roles have a predefined directory structure, which helps in organizing the content and making the role modular and reusable. Here’s how a general directory structure for Ansible Roles looks like:
role_name/ defaults/ files/ handlers/ meta/ tasks/ templates/ vars/
Each directory has a specific purpose in the role, and understanding these directories is crucial for managing and customizing Ansible Roles effectively.
Initialization
To initialize or create a new Ansible Role, you can use the ansible-galaxy init
command, followed by the role name. For example:
ansible-galaxy init my_role
This command will create a new directory with the name my_role
, populating it with the necessary directories and files based on the default structure.
Creating Ansible Roles
We have covered this in more detail under Ansible roles directory structure
Role Directories and Files
As mentioned, Ansible Roles consist of several directories. Here’s a brief on what to put where:
Tasks
: List of tasks to execute. These are the main actions of the role.Handlers
: Contains handlers that can be triggered by tasks.Defaults
: Contains default variables.Vars
: Contains other variables.Files
andTemplates
: Files or templates that the role deploys.
Task Definition
Tasks are the fundamental actions that an Ansible Role performs. A task could be anything from installing a package, starting a service, or copying a file. Here is an example of defining tasks in Ansible Roles:
# role_name/tasks/main.yml
---
- name: Install nginx
apt:
name: nginx
state: present
Handlers
Handlers are special types of tasks in Ansible Roles, triggered when notified by another task. For example:
# role_name/handlers/main.yml
---
- name: Restart nginx
service:
name: nginx
state: restarted
Default Variables
Variables allow for flexibility and customization in Ansible Roles. Default variables are defined in the defaults
directory and can be overridden. For example:
# role_name/defaults/main.yml
---
nginx_port: 80
Using Ansible Roles
Including Roles in Playbooks
Ansible Roles are designed to be reusable components in your automation workflows. To leverage the functionalities defined in roles, you include them in playbooks. Here is how you can incorporate Ansible Roles within a playbook:
---
- hosts: web_servers
roles:
- role: nginx_role
In this example, the playbook is assigned to run on web_servers
, and it includes an Ansible Role named nginx_role
.
Role Dependencies
Roles can depend on other roles, meaning one role can invoke another. Defining dependencies is crucial for managing complex workflows where tasks are interrelated. Dependencies are typically listed in the meta/main.yml
file inside the role directory.
# meta/main.yml
dependencies:
- role: common
In this snippet, the Ansible Role has a dependency on another role named common
, which would be executed first.
Passing Variables to Roles
Variables make Ansible Roles highly customizable. When using a role in a playbook, you can pass variables to it to modify its behavior.
---
- hosts: web_servers
roles:
- role: nginx_role
vars:
nginx_port: 8080
This playbook executes the nginx_role
, passing a variable that sets the Nginx port to 8080.
Ansible Galaxy
Ansible Galaxy is a repository for sharing Ansible Roles. It’s a community-driven platform where you can find, reuse, and share roles, enhancing productivity and collaboration in managing automation tasks with Ansible Roles.
Installing and using Roles on Ansible Galaxy
1. Searching for Roles
Begin by exploring available roles on the Ansible Galaxy website.
You can search for roles by keywords, tags, or author, and filter the results according to your needs.
2. Installing Roles
Once you find a role that suits your needs, you can install it directly from the command line using the ansible-galaxy
command.
ansible-galaxy install username.role_name
Replace username
and role_name
with the appropriate values. This command downloads and installs the role to your system, making it available for use in your playbooks.
3. Using Installed Roles in Playbooks
After installing the role, you can utilize it in your playbooks. Include the role name in your playbook’s roles section.
---
- hosts: your_host
roles:
- username.role_name
Ensure that the hosts
section correctly targets the hosts where you want the role to be applied.
4. Customizing Roles with Variables
You might need to customize the role according to your specific needs. Look for variables that the role author has made available for customization.
---
- hosts: your_host
roles:
- role: username.role_name
vars:
var_name: value
Replace var_name
and value
with the specific variable names and values you want to customize.
5. Executing the Playbook
Run the playbook using the ansible-playbook
command, and the role will be executed on the targeted hosts.
ansible-playbook your_playbook.yml
Submitting Roles to Ansible Galaxy
Submitting your Ansible Roles to Ansible Galaxy involves several steps to ensure that your role is well-prepared, documented, and easily accessible to other users. Here’s a detailed breakdown with sample commands to guide you through the process:
1. Prepare Your Role
Ensure your role adheres to Ansible’s best practices. Structure your role correctly with meaningful names, organized tasks, handlers, and variables.
2. Create a GitHub Repository
Ansible Galaxy integrates with GitHub. Create a repository for your role on GitHub.
git init ansible-my-role cd ansible-my-role git remote add origin https://github.com/your-username/ansible-my-role.git
3. Create a README.md
File
Include a README.md
in your repository to provide essential information, usage instructions, and examples for your role.
4. Create a meta/main.yml
File
This file should include metadata about your role, such as the description, author information, platforms, and dependencies.
---
galaxy_info:
author: your_name
description: Your role description
license: MIT
min_ansible_version: 2.4
platforms:
- name: Ubuntu
versions:
- bionic
galaxy_tags:
- web
- nginx
dependencies: []
5. Push Your Role to GitHub
Commit your role files and push them to your GitHub repository.
git add . git commit -m "Initial commit" git push -u origin master
6. Submit Your Role to Ansible Galaxy
- Go to Ansible Galaxy.
- Log in and click on “Add Content”.
- Choose "GitHub" as the source and select your repository.
- Import your role by selecting the repository you want to import.
7. Version Your Role
It’s good practice to create versions of your role. Use git tags to mark versions, and then push these tags to your GitHub repository.
git tag 1.0.0 git push origin 1.0.0
In Ansible Galaxy, new versions will be detected automatically, and users can choose specific versions of your role to install.
Parameterization and Variable Usage in Ansible Roles
1. Role Parameters
Role parameters allow you to pass values into your Ansible Roles, making your roles more dynamic and reusable. You define these variables outside of the role, and they modify how the role behaves.
For example:
---
- hosts: web_servers
roles:
- role: my_role
var1: value1
var2: value2
In this playbook, var1
and var2
are passed as parameters to my_role
.
2. Variable Scopes and Precedence
Variables in Ansible can be defined in multiple places, and they follow a specific order of precedence. For instance, variables defined within a playbook have higher precedence over those defined in roles.
Example:
- Role Default:
# roles/my_role/defaults/main.yml
---
var_name: default_value
Playbook:
# playbook.yml
---
- hosts: web_servers
roles:
- role: my_role
var_name: playbook_value
In this example, var_name
would take the value playbook_value
because it is defined in the playbook and has higher precedence over the role’s default value.
3. Dynamic Inclusions
Dynamic inclusions allow you to conditionally include tasks or roles based on the value of variables or facts.
# playbook.yml
---
- hosts: web_servers
roles:
- role: "{{ ansible_os_family | lower }}"
In this playbook, the role included will depend on the operating system of the target hosts because of the use of the ansible_os_family
fact.
Sharing and Reusing Ansible Roles
Ansible Roles can be shared across multiple projects, promoting code reuse. Place the role in a directory accessible by different projects or use a tool like Ansible Galaxy.
Version control systems like Git can be used to manage your Ansible Roles, making collaboration easier. You can track changes, create branches, and accept merge requests to improve the roles.
Example:
Initialize a Git Repository:
git init my_role
Commit Your Role:
git add . git commit -m "First commit"
Push to a Remote Repository:
git remote add origin <repository-url> git push -u origin master
Advanced Topics in Ansible Roles
1. Conditional Inclusions in Ansible Roles
Conditional inclusions allow you to conditionally include tasks or roles in your playbook based on certain conditions such as variables or facts.
# playbook.yml
---
- hosts: servers
roles:
- role: database
when: ansible_facts['os_family'] == "Debian"
In this example, the database
Ansible Role is only applied to hosts where the operating system family is Debian.
2. Loops and Iterations in Ansible Roles
Loops in Ansible Roles allow you to execute tasks multiple times, iterating over a list of items. This feature is incredibly powerful for managing repetitive tasks in a concise manner.
Example:
# roles/web/tasks/main.yml
---
- name: Ensure multiple packages are installed
ansible.builtin.package:
name: "{{ item }}"
state: present
loop: "{{ packages }}"
In this snippet from an Ansible Role, a loop is used to install multiple packages. The variable packages
contains a list of packages to be installed.
3. Error Handling in Ansible Roles
Error handling is crucial for managing the execution flow of your playbooks. You can manage errors effectively within Ansible Roles by using certain parameters such as ignore_errors
or failed_when
.
# roles/web/tasks/main.yml
---
- name: Try to start the service
ansible.builtin.service:
name: my_service
state: started
ignore_errors: yes
In this Ansible Role task, the ignore_errors
parameter is set to yes. This means that even if starting the service fails, the playbook execution will continue.
Example 1: Ansible roles example to update /etc/motd
Step 1: Create ansible role - motd
- To create ansible role, use
ansible-galaxy init <role_name>
to create the role directory structure. - We will create the role inside our
<project>/roles
directory i.e.~/base/roles/motd
- Don't put sensitive information in the role, but in the local playbooks or Ansible Vault instead
[ansible@controller ~]$ mkdir roles [ansible@controller ~]$ cd roles
Next use ansible-galaxy init
command to create ansible role. We will create motd
role:
[ansible@controller roles]$ ansible-galaxy init motd - motd was created successfully
Create ansible role command was successful. You can use tree command to list the ansible role directory structure for motd
:
[ansible@controller roles]$ tree motd
motd
├── 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
As you see all the directories which we discussed in our last article for ansible role are created
Step 2: Create ansible tasks
Now we know we want to update /etc/motd
file using ansible playbook roles so we must create tasks so we will use the main.yml
file present inside tasks
folder
[ansible@controller motd]$ cat tasks/main.yml --- # tasks file for motd - name: copy motd file template: src: templates/motd.j2 dest: /etc/motd owner: root group: root mode: 0444
We have defined the template path and destination detail to update /etc/motd
Step 3: Create ansible template
Next we will create the template content which will be used to update /etc/motd
in our ansible roles examples. I will create a new template file under templates
directory using some variables:
[ansible@controller motd]$ cat templates/motd.j2 Welcome to {{ ansible_hostname }} This file was created on {{ ansible_date_time.date }} Go away if you have no business being here Contact {{ system_manager }} if anything is wrong
Step 4: Create ansible variables
We will use defaults
folder to define custom variables which is used in our template file templates/motd.j2
.
[ansible@controller motd]$ cat defaults/main.yml
---
# defaults file for motd
system_manager: admin@golinuxcloud.com
Step 5 : Remove unwanted directories (Optional)
This step is completely optional. In this ansible roles example we will not use other directories so we are deleting them. After deleting the additional directories you can use tree
command to list the directory structure of motd
roles
[ansible@controller motd]$ rm -rf handlers tests vars [ansible@controller motd]$ tree . ├── defaults │ └── main.yml ├── files ├── meta │ └── main.yml ├── README.md ├── tasks │ └── main.yml └── templates └── motd.j2 5 directories, 5 files
Step 6: Create ansible role playbook
Now after you create ansible role structure, we need a playbook file which will deploy the role to our managed hosts. I will create my playbook file motd-role.yml
under base
project directory.
[ansible@controller base]$ cat motd-role.yml --- - name: use motd role playbook hosts: server1.example.com user: ansible become: true roles: - role: motd system_manager: admin@golinuxcloud.com
As you see I have only provided the roles
information and no other tasks are specified in the playbook file.
Step 7: Deploy ansible playbook roles
After we create ansible role from scratch and playbook file, we will next deploy our ansible playbook roles to execute the motd
role on our managed host.
[ansible@controller base]$ ansible-playbook motd-role.yml PLAY [use motd role playbook] *********************************************************************************** TASK [Gathering Facts] ****************************************************************************************** ok: [server1.example.com] TASK [motd : copy motd file] ************************************************************************************ changed: [server1.example.com] PLAY RECAP ****************************************************************************************************** server1.example.com : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
In the ansible roles example our ansible deployment was successful.
Step 8: Verification
After ansible playbook deployment, verify the task status on your managed host which for us is server1.example.com
[root@server1 ~]# cat /etc/motd Welcome to server1 This file was created on 2020-02-01 Go away if you have no business being here Contact admin@golinuxcloud.com if anything is wrong
So the content from our motd
file is updated properly on server1
at /etc.motd
.
Example 2: Configure Virtual Hosting with Ansible Role
This is our second ansible roles example. This play will be operated on server2.example.com
and we are going to use "vhost
" role for the operation.
Step 1: Create Ansible Role - vhost
We will use our existing ~/base/roles/<rolename>
project to create ansible roles directory structure using "vhost
" role
[ansible@controller base]$ cd roles/
To create ansible role vhost
use ansible-galaxy init <rolename>
command as shown below:
[ansible@controller roles]$ ansible-galaxy init vhost - vhost was created successfully
You can use tree
command to check the structure of the vhost
directory:
[ansible@controller roles]$ tree . └── vhost ├── defaults │ └── main.yml ├── files ├── handlers │ └── main.yml ├── meta │ └── main.yml ├── README.md ├── tasks │ └── main.yml ├── templates ├── tests │ ├── inventory │ └── test.yml └── vars └── main.yml 9 directories, 8 files
Step 2: Create ansible tasks
- In the
main.yml
inside tasks folder we define the tasks to be performed - Install httpd using yum module
- Start and enable the httpd service using the service module
- Next source the
vhost.conf.j2
file to destination using template module available under templates directory
[ansible@controller base]$ cat roles/vhost/tasks/main.yml --- # tasks file for vhost - name: install http yum: name: httpd state: latest - name: start and enable httpd service: name: httpd state: started enabled: true - name: install vhost config file template: src: vhost.conf.j2 dest: /etc/httpd/conf.d/vhost.conf owner: root group: root mode: 0644
Step 3: Create ansible handlers
In roles we separate tasks
with ansible handlers. So in this ansible roles example in handlers/main.yml
we instruct ansible to restart httpd
once the tasks
are done
[ansible@controller base]$ cat roles/vhost/handlers/main.yml --- # handlers file for vhost - name: restart_httpd service: name: httpd state: restarted
Step 4: Create ansible template
Below is our virtual host configuration using variables under templates
folder. The variables will be auto filled on destination names.
[ansible@controller base]$ cat roles/vhost/templates/vhost.conf.j2 # {{ ansible_managed }} <VirtualHost *:80> ServerAdmin webmaster@{{ ansible_fqdn }} ServerName {{ ansible_fqdn }} ErrorLog logs/{{ ansible_hostname }}-error.log CustomLog logs/{{ansible_hostname }}-common.log common DocumentRoot /var/www/vhosts/{{ ansible_hostname }}/ <Directory /var/www/vhosts/{{ ansible_hostname }}> Options +Indexes +FollowSymlinks +Includes Order allow,deny Allow from all </Directory> </VirtualHost>
Step 5: Remove unwanted directories (Optional)
Now similar to our ansible roles example for motd
, we will remove our unwanted directories.
[ansible@controller vhost]$ rm -rf defaults files tests vars
Next you can use tree
command to list the remaining directories of vhost
role.
[ansible@controller vhost]$ tree
.
├── handlers
│ └── main.yml
├── meta
│ └── main.yml
├── README.md
├── tasks
│ └── main.yml
└── templates
4 directories, 4 files
Step 6: Create post execution tasks
Also we have added post_tasks
to copy index.html
from localhost
to destination on managed host (server2.example.com
) under /var/www/html/<hostname>/
So we will create an index.html
on the localhost
which we want to be copied to the destination with our playbook:
[ansible@controller base]$ mkdir -p files/html [ansible@controller base]$ echo "Welcome to this host" >> files/html/index.html [ansible@controller base]$ cat files/html/index.html Welcome to this host
Step 7: Create ansible role playbook
Now after you create ansible role structure, we need a playbook file which will deploy the role to our managed hosts. I will create apache-vhost.yml
playbook file under the base
project directory.
[ansible@controller base]$ cat apache-vhost.yml --- - name: create apache vhost hosts: server2.example.com ## Execute on this host only become: true ## Perform tasks as root user roles: - vhost post_tasks: - name: install contents from local file copy: src: files/html/ dest: "/var/www/vhosts/{{ ansible_hostname }}" changed_when: true ## This is to forcefully mark a change notify: restart_httpd ## Execute the handler with the name restart_httpd
Step 8: Deploy ansible playbook roles
After we create ansible role from scratch and playbook file, we will next deploy our ansible playbook roles to execute the vhost
role on our managed host.
[ansible@controller base]$ ansible-playbook apache-vhost.yml PLAY [create apache vhost] ************************************************************************************** TASK [Gathering Facts] ****************************************************************************************** ok: [server2.example.com] TASK [vhost : install http] ************************************************************************************* ok: [server2.example.com] TASK [vhost : start and enable httpd] *************************************************************************** ok: [server2.example.com] TASK [vhost : install vhost config file] ************************************************************************ changed: [server2.example.com] TASK [install contents from local file] ************************************************************************* changed: [server2.example.com] RUNNING HANDLER [vhost : restart_httpd] ************************************************************************* changed: [server2.example.com] PLAY RECAP ****************************************************************************************************** server2.example.com : ok=6 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
So looks like our ansible playbook roles has successfully executed. We can verify the same by running ansible ad-hoc
commands
-include: <path/of/handler/main.yml>
to manually execute the file.Step 9: Verification
To check if httpd
service is active on our managed host server2.example.com
[ansible@controller base]$ ansible server2.example.com -a 'systemctl is-active httpd' server2.example.com | CHANGED | rc=0 >> active
As we see the service active
, we can also check the output of vhost.conf
which we had populated. Execute the below command using the controller node
[ansible@controller base]$ ansible server2.example.com -a 'cat /etc/httpd/conf.d/vhost.conf'
server2.example.com | CHANGED | rc=0 >>
# Ansible managed
<VirtualHost *:80>
ServerAdmin webmaster@server2.example.com
ServerName server2.example.com
ErrorLog logs/server2-error.log
CustomLog logs/server2-common.log common
DocumentRoot /var/www/vhosts/server2/
<Directory /var/www/vhosts/server2>
Options +Indexes +FollowSymlinks +Includes
Order allow,deny
Allow from all
</Directory>
</VirtualHost>
Frequently Asked Questions (FAQs)
What are Ansible Roles and why are they important?
Ansible Roles are reusable and portable units of automation, used to organize tasks, handlers, default variables, and metadata. They are significant for simplifying complex playbooks and facilitating code reuse, allowing users to share pre-configured setups and automations, thereby enhancing productivity and consistency in automation strategies.
How do I create and structure an Ansible Role?
To create an Ansible Role, use the ansible-galaxy init
command followed by the name of the role. Structuring involves organizing configurations and tasks into directories such as tasks
, handlers
, templates
, and vars
. Each directory contains a main.yml
file where specific components of the role are defined, ensuring modularity and organization in role definitions.
How can I use variables within Ansible Roles?
Variables in Ansible Roles offer dynamic capabilities and are usually defined within the defaults
or vars
directory of the role. You can also pass variables to roles directly within playbooks, offering flexibility in customizing role behaviors based on variable values.
How do Ansible Roles interact with Ansible Galaxy?
Ansible Roles can be shared and reused through Ansible Galaxy, a community hub for sharing automation content. You can upload your roles to Ansible Galaxy or install and utilize roles shared by others, promoting collaboration, and code reuse in the Ansible community.
How are conditional statements applied in Ansible Roles?
Conditional statements in Ansible Roles, like when
, allow for the execution of tasks based on the evaluation of specified conditions. They enable dynamic inclusion of tasks, roles, or handlers, based on variables, facts, or any conditional logic, making the roles more versatile and adaptable to different scenarios.
How can loops be implemented in Ansible Roles?
Loops can be applied in tasks within Ansible Roles using loop-related directives like loop
or with_items
. They allow for the iterative execution of tasks over lists or sequences, facilitating repetitive task management with more concise and manageable code.
What strategies are available for error handling in Ansible Roles?
Error handling in Ansible Roles involves using parameters like ignore_errors
or implementing blocks with rescue
and always
sections. Such strategies ensure controlled execution flow, allowing for the management of task failures or errors gracefully, enhancing role reliability and robustness.
How do I manage role dependencies in Ansible?
Role dependencies can be managed by defining them in the meta/main.yml
file of a role or directly within a playbook. Defining dependencies ensures that requisite roles are executed in the correct order, maintaining coherence in role interactions and executions.
Summary
Creating, managing, and optimizing Ansible Roles are pivotal in leveraging the full potential of Ansible’s automation capabilities. Here’s a concise overview of the important aspects discussed:
- Introduction to Ansible Roles: Understanding the fundamental concepts, such as the definition, architecture, and importance of roles, sets a strong foundation for working with Ansible Roles.
- Setting Up and Creating Ansible Roles: Knowing how to initialize and structure the roles, including the organization of directories and files, is crucial for building functional roles.
- Utilizing Ansible Roles: Incorporating roles within playbooks, managing role dependencies, and passing variables enhance the reusability and functionality of roles.
- Ansible Galaxy: Learning the intricacies of Ansible Galaxy for installing, using, and submitting roles is essential for community collaboration and role sharing.
- Parameterization and Variable Usage: Mastery of parameters and variables, including their scopes and precedence, makes roles dynamic and adaptable.
- Sharing and Reusing Ansible Roles: Implementing best practices for sharing and reusing roles across projects through version control and collaboration tools improves code consistency and teamwork.
- Advanced Topics: Delving into advanced concepts like conditional inclusions, loops, and error handling allows for the creation of more robust and error-resistant roles.
For an in-depth understanding and exploration of Ansible Roles, refer to the official documentation:
- Ansible Roles Documentation
- Ansible Galaxy Documentation
- Ansible Best Practices
- Ansible Variables
- Ansible Error Handling
What's Next
Next in our Ansible Tutorial we will learn about Ansible Vaults
very simple and clear thank you.
In your playbook there is no handler restart task was executed , I think you missed the notify after the copy, Please check once
Thank you for highlighting this, I may have overlooked the output. I have updated the article with additional NOTE
creation of vhosts directory on target not mentioned anywhere how will it create /var/www/vhosts
Thanks a lot it had really helped me to get a view on ansible roles easily
yes, very simple and clear.