This blog post introduces roles and other relevant features in Ansible.
In the previous article, we covered grouping and tags to target specific nodes and tasks and several useful modules for managing files, services, and users. As we make use of these features and manage configurations for larger projects with more moving parts, playbooks inevitably become long. Hence, in this article, we will discuss roles and other features that allow us to organize tasks and handle flexible configurations.
Roles
In Ansible, roles can bundle different tasks and other relevant components into
separate directories and assign them to different hosts. The following shows how roles
can be assigned to hosts in the root main.yaml file.
- host: all
become: true
roles:
- base
- host: web_servers
become: true
roles:
- web_servers
- host: db_servers
become: true
roles:
- db_serversThe tasks for a role can be organized in the main.yaml file within the <role_name>/tasks
subdirectory of the roles directory. For example, we can define tasks for installing
Apache and PHP packages for a web_servers role, as shown below.
- name: install apache and php
package:
name:
- "{{ apache_package }}"
- "{{ php_package }}"
state: latest
update_cache: yesThe main.yaml file in the tasks directory is called a taskbook. This is because we only define tasks and
do not specify hosts, become, or other fields typically used in a playbook.
When executing ansible-playbook main.yaml, the tasks defined in the taskbook for the
roles assigned to the hosts are executed as if they were defined in the root playbook.
Host Variables & Handlers & Templates
The above task for the web_server role utilizes templating functionality that can replace
host variables. In the previous article, we defined the values of host variables in the
inventory file, but we can alternatively define host variables in a <host>.yaml file
within the host_vars directory for better organization, as shown below.
apache_package: httpd
php_package: phpWe can also use notify instead of register so that any change made in at least one
task with notify can properly trigger another task. The task that receives notification
from notify is called a handler, and notify uses the handler's name instead of a variable.
- name: restart_apache
service:
name: "{{ apache_name }}"
state: restartedHandlers can be organized in the main.yaml file within the <role_name>/handlers subdirectory,
as shown above. Tasks defined within the same role can trigger a handler using notify: restart_apache.
Moreover, we can use templates for host variables in other files as well by employing the
template module, as shown below.
- name: generate ssh_config file from template
tags: ssh
template:
src: "{{ ssh_template_file }}"
dest: /etc/ssh/sshd_config
owner: root
group: root
mode: 0644
notify: restart_sshThe ssh_template_file is one of the host variables, whose value can be the name of a template
file in the roles/base/templates directory (a full path is not required when the template is
defined within the role). The ssh_config template can use variables like {{ ssh_users }}
and replace them with the values of the corresponding host variables.
boostrap.yaml
host_vars
main.yaml
roles/
├── base/
│ ├── handlers
│ ├── tasks
│ └── templates
...The above is one potential file structure for managing infrastructure configurations of large projects using Ansible, making use of the features we have discussed. The file structure and features should be chosen based on the project's requirements.
Conclusion
In this article, we discussed roles and other relevant features for organizing various components of Ansible. Ansible files should be managed with Git/GitHub and other DevOps tools like Terraform for proper version control and CI/CD. There are other useful modules and features available, so I highly recommend exploring them.
Resources
- Ansible. n.d. Ansible Documentation. Ansible Community Documentation.
- Learn Linux TV. 2020. Getting started with Ansible. YouTube.