Ansible is an open source configuration management tool. It’s simple use makes it very popular, but being a simple tool does not limit its usage. Ansible can be used for simple automation tasks, but also for complex provisioning and orchestration.In this post we are going to show you some best practice steps you should in consideration when using Ansible. We are assuming you have some basic concepts of Ansible, if not, you can check our previous post here with instruction on how to get started with Ansible.
One of the first things you have to start with, is the directory structure and layout.
The default layout should be something similar to below:
– production and staging are our inventory files. It’s always a good practice to keep the production and staging host in separate files…having them in one file can get messy.
– group_vars and host_vars are used for assigning variables to specified group of hosts or single host.
– library and module_utils are used for any custom module or module_utils
– filter_plugin is used for custom filter plugins.
– site.yml is the master playbook
– webserver.yml and dbserver.yml are playbooks for the web and db servers tiers taken for example in this demo. You can also have other tiers, depending on what you are provisioning
– roles is the directory where all the roles are stored.
– roles/common the directories inside roles directory, like common, represent the roles. This means that everything inside of the common directory, is part of the common role.
Structure inside a role:
tasks/main.yml : this is where the task of the role are specified
handlers/main.yml : handlers file
templates/ : files to be used with the template resource
files/ : files to be used with the copy and script resource
vars/main.yml : variables associated with this role
defaults/main.yml : default lower priority variables for this role
meta/main.yml : role dependencies
library/ : custom modules for this role
module_utils/ : custom module_utils for this role
lookup_plugins/ : custom plugins for this role
If you plan on maintaining your playbooks, you need to keep the name consistency between your inventories,roles,plays, variables, etc. For example, use the name of the role to separate variables in each group. Let’s say you are installing Apache and PHP on your web servers. You can separate the variables used for each of them, group_vars/webservers/apache.yml and group_vars/webservers/php.yml.
As mentioned above, you should keep your staging or testing environment separate from you production environment by using different inventory files. Using the -i flag, you can choose on which inventory to run the tasks. Testing your playbooks before running them in production is always a good idea.
There is a high chance that you might end up using passwords or certificates in your playbooks. Having to store them in plain text files, is always not a good idea. Ansibles offers ansible-vault which can be used to encrypt sensitive data. Instead of using plain text files, you store your sensitive data in encrypted files. When running the playbooks, you need to use a flag, –ask-vault-pass or –vault-password-file, which will then decrypt the files(in memory only). The only drawback of this is that at the moment you can only use one password for encrypting your files.
Use version control on all you playbooks. Keep your files in a git server, so you will commit when you have changes. This will ensure you have an audit trail describing why and when changes were done to your playbooks.
Modules before run commands
Run commands like command and shell modules enable the user to execute shell command on the hosts. At first this may seem convenient but on the long run it’s always suggested to use the modules when possible. Running you tasks with shell command may work the first time, but there high chances that it will fail a second time, when something exist, like an error. Also having the built in modules can make it easier and help you with getting the idempotency of the playbooks.
Idem-potency means running the same playbook different times on the same host, and expecting the same results. These means, that after you run your playbook the first time on a host and all changes are done, the second time, the playbook should return everything green and make no changes. There some ideas to start when trying to archive idem-potency.
Always use built modules instead of run commands when is possible as explained above.
Always use the same inputs
The argument force:no can be used on some modules to make sure the task is run only once. This means that if you are using a template, and want it copied only once if not existence, this will ensure that the second time it will not be copied.
When forced to use the command or shell tasks, always use the argument creates. Otherwise, the tasks will be considered as “changed” .