I have written many Ansible Roles in my career. But when I talk about the “Best Practice of writing an Ansible Role” half of them were non-considerable. When I started writing Ansible Roles, I wrote them with a thought as to just complete my task. This thought made me struggle as a “DevOps Guy” because of this practice I just have to write each and every Ansible Role again and again when needed. Without the proper understanding about the Architecture of Ansible Role, I was incapable of enjoying all the functionality which I could have used to write an Ansible Role where I was just using “command” and “shell” modules.
Advantages of Best Practices
- Completing the task using Full Functionality.
- Vandalized Architecture helps to create Ansible roles as Utilities which can be used further using different values.
- Applying best practices helps you to learn new things every day.
- Following “Convention Over Configuration” makes your troubleshooting much easier.
- Helps you to grow your Automation skills.
- You don't have to worry about the latest version or change in values ever.
I can talk about the Advantages of best practices continuously but you should understand it after using them. So now, Let's talk about “How to apply them”.
First, we will understand the complete directory structure on Ansible Role:
- Defaults: The default variables for the role are been stored here inside this directory. These variables have the lowest priority.
- Files: All the static files are being stored here which are used inside the role.
- Handlers: All the handlers are being used here not inside the Task directory. And automatically called upon from here.
- Meta: This directory contains the metadata about your role regarding the dependencies which are being required to run this role in any system, so it will not be run until the dependencies inside it are not been resolved.
- Tasks: This directory contains the main list of the tasks which needs to be executed by the role.
- Vars: This directory has high precedence than defaults directory and can only be overwritten by passing them On the command line, In the specific task or In a block.
- Templates: This directory contains the Jinja to template inside this. Basically, all the dynamic files are being stored here which can be variablized.
Whitespace and Comments
Generous use of whitespace and breaking things up is really appreciated. One very important thing is the use of comments inside your roles so that someone using your role in future could be able to easily understand it properly.
Learn YAML format properly and use of indentation properly inside the document. Sometimes, when running the role gives the error for Invalid Syntax due to bad indentation format. And writing in proper Indentation makes your role look beautiful.
Always Name Tasks
It is possible to leave off the ‘name’ for a given task, though it is recommended to provide a description about something is being done instead. This name is shown when that particular task is being run.
Use version control. Keep your roles and inventory files in git and commit when you make changes to them. This way you have an audit trail describing when and why you changed the rules that are automating your infrastructure.
Variable and Vaults
Since the variable contains sensitive data, so It is often easier to find variables using grep or similar tools inside the Ansible system. Since vaults obscure these variables, It is best to work with a layer of Indirection. This allows Ansible to find the variables inside the unencrypted file and all sensitive variables come from an encrypted file.
The best approach to perform is to start with a group_vars subdirectory containing two more subdirectories inside it naming “Vars” and “Vaults”. Inside “Vars” directory define all the variable including sensitive variables also. Now, copy those sensitive variables inside “Vault” directory while using the prefix “vault_*” for the variables. Now you should adjust the variables in the “Vars” to point the matching “vault_*” variables using jinja2 syntax and ensure that vault file is vault encrypted.
Roles for multiple OS
Roles should be written in a way that they could be run on multiple Operating systems. Try to make your roles as generic as you can. But if you have created a role for some specific kind of operating system or some specific application, then try to explicitly define that inside the role name.
Single role Single goal
Avoid tasks within a role which are not related to each other. Don’t build a common role. It’s ugly and bad for readability of your role.
- Use a module if available
- Try not to use command or shell module
- Use the state parameter
- Prefer scalar variables
- Set default for every variable
- If you have multiple roles related to each other than try to create a common variable file for all of them which will be called inside your playbook
- Use “copy” or “template” module instead of “lineinfile” module
- Make role fully variablized
- Be explicit when writing tasks. Suppose, If you are creating a file or directory then rather defining src and destination, try to define owner, group, mode etc.
- Create a Role which could be used further.
- Create it using proper modules for better understanding.
- Do proper comments inside it so that it would be understood by someone else also.
- Use proper Indentation for the YAML format.
- Create your Role variables and also secure them using vault.
- Create Single role for Single goal.