💡
|
For information on additional Guidelines I require to be applied to my roles, take a look at my Ansible Role Development Guidelines. |
- Introduction to Roles
- Ansible Role Best Practices
- Keep the purpose and function of a role self-contained and focused to do one thing well
- Roles should run with as few parameter variables as possible
- Automate the testing of your roles
- Overcoming the pitfall of Ansible’s Role Variable Precedence
- Ansible Best-Practices
- Know Ansible’s Variable Precedence
Roles…
-
Are self-contained portable units of Ansible automation
-
Are expressed in YAML and bundled with associated assets
-
Are decoupled from assumptions made by plays
-
Reuse and collaboration of common automation workflows & configurations
-
Provide full life-cycle management of a service, microservice or container
-
Provide “De-facto” enforcement of standards and policies
A role should always be more than a single task file.
-
Think about the full life-cycle of a service, microservice or container — not a whole stack or environment.
-
Keep provisioning separate from configuration and app deployment.
-
Roles are not classes or object or libraries - those are programming constructs.
-
Keep roles loosely-coupled — limit hard dependencies on other roles or external variables.
-
Practice convention over configuration.
-
Provide sane defaults.
-
Use variable parameters to modify default behavior.
-
Denote differences between your role’s defaults and the programs' defaults - if exist.
Exhibit A | Exhibit B |
---|---|
# defaults_no_playbook.yml
---
- hosts: webservers
roles:
- role: apache_simple
apache_http_port: 80
apache_doc_root: /var/www/html
apache_user: www-data
apache_group: www-data
- role: apache_simple
apache_http_port: 8080
apache_doc_root: /www/example.com
apache_user: www-data
apache_group: www-data |
# defaults_yes_playbook.yml
---
- hosts: webservers
roles:
- name: apache_simple
- name: apache_simple
apache_http_port: 8080
apache_doc_root: /www/example.com |
-
Use molecule, a testing framework designed to aid in the development and testing of Ansible Roles.
Initially developed by the community, led by John Dewey of Cisco, and adopted by Red Hat as an official Ansible project.
-
Use ansible-lint, a command-line static analysis tool that checks playbooks and roles for identifying behaviour that could be improved. (TIP: ansible-lint can be run as part of your Molecule test runs.)
Initially developed by Will Thames and recently adopted by Red Hat as an official Ansible project.
include_vars
/role-vars have precedence over playbook/inventory-vars.
Therefore, a common tactic to enable a dynamic variable to still be overwritten is to apply one of the following schemes:
Separate File for each Distribution + One Task for each Variable | Single Variables File with No Tasks Pollution by using the benefits of Ansible’s Lazy Interpolation |
---|---|
As used by e.g. geerlingguy |
As used by e.g. jonaspammer, robertdebock |
# in vars/Debian.yml...
__role_var_name: ""
# in tasks/main.yml...
- name: include os-specific vars
ansible.builtin.include_vars: "{{ ansible_os_family }}.yml"
- name: set 'role_var_name' to OS-dependant value (when not already defined)
ansible.builtin.set_fact:
var_name: "{{ __role_var_name }}"
when: role_var_name is not defined |
# in vars/main.yml...
_rolename_os_specific_var:app-name:
Alpine: …
Debian: …
Debian_9: …
rolename_os_specific_var: "{{
_rolename_packages[ansible_distribution ~'_'~ ansible_distribution_major_version]|default(
rolename_packages[ansible_distribution] )|default(
_rolename_packages[ansible_os_family] ) }}" |
-
Use native YAML syntax.
-
Version control your Ansible content.
This way you have an audit trail describing when and why you changed the rules that are automating your infrastructure.
-
Use
command
modules sparingly. Always seek out a module first -
“Name” your plays, blocks and tasks.
It is possible to leave off the ‘name’ for a given task, though it is recommended to provide a description about why something is being done instead. This name is shown when the playbook is run.
-
Use human meaningful names with variables, hosts, etc.
-
Clean up your debugging messages.
Here is the order of precedence from least to greatest (the last listed variables winning prioritization), as seen on Ansible’s Official Documentation on "Using Variables":
-
command line values (for example,
-u user
, these are not variables) -
role defaults (defined in role/defaults/main.yml) (1)
-
inventory file or script group vars (2)
-
inventory group_vars/all (3)
-
playbook group_vars/all (3)
-
inventory group_vars/* (3)
-
playbook group_vars/* (3)
-
inventory file or script host vars (2)
-
inventory host_vars/* (3)
-
playbook host_vars/* (3)
-
host facts / cached set_facts (4)
-
play vars
-
play vars_prompt
-
play vars_files
-
role vars (defined in role/vars/main.yml)
-
block vars (only for tasks in block)
-
task vars (only for the task)
-
include_vars
-
set_facts / registered vars
-
role (and include_role) params
-
include params
-
extra vars (always win precedence)
(1) Tasks in each role will see their own role’s defaults.
Tasks defined outside of a role will see the last role’s defaults.
(2) Variables defined in inventory file or provided by dynamic inventory.
(3) Includes vars added by 'vars plugins' as well as host_vars
and group_vars
which are added by the default vars
plugin shipped with Ansible.
(4) When created with set_facts’s cacheable option, variables will have the high precedence in the play, but will be the same as a host facts precedence when they come from the cache.