Ansible best practices
Ansible is quite popular configuration management tool, and it is gaining more popularity with frequent inclusion of new modules which are helping ansible to evolve both as a configuration management tool and infrastructure provisioning tool. Ansible eases the life of a system administrator and Devops engineer provided they follow the best practice, because a solution is not a good solution until it solves the
problem in-hand efficiently.
If you have worked with ansible, you would have experienced few noticeable things:
- Easy to setup
- Simplicity
- Re-usability
- Well documented modules
More and more IT companies are using Ansible for automation, but without ansible good practices you might find yourself stuck as the project grows.
I would like to discuss few good practices that i always follow:
The project structure:
A elegant and well structured project in ansible will aid you if you are working on different projects.
Typical structure will look like:
project/
group_vars/
all/
allvars.yml
webservers/
apache.yml
database/
postgresql.yml
inventories/
dev_inventory.ini
prod_inventory.ini
playbook.yml
Inventory File:
Ofcourse having a inventory that is well defined will give you a upper hand. We always need different environments (test, develop, production, etc.). A useful way to manage environments is to have several inventories. For example below inventory
[development]
dev.something.io
10.30.78.1
10.30.78.2
#defining vars for development group
[development:vars]
ansible_host: 192.168.1.4
ansible_user: dev
ansible_pass: pass
ansible_port: 2244
[api:children]
development
Which allows you to execute the following playbook against the inventory file:
playbook.yml
—
hosts: api
become: true
tasks:
-name: Installing api
By running the following command
ansible-playbook playbook.yaml -i dev_inventory.ini
Role:
Working with only playbooks and stuffing all the code and variables there will become cumbersome after some point You will soon feel the need make things simpler by using roles. With roles you can segregate the vars, templates, playbooks and place them where they belong. For example for a three tier infrastructure you can have three roles:
webserver
middleware
database
Each role can then have its playbook, template, varibales etc.
Variables:
The variables are great, they allow us to use the code simply by changing some values. Ansible offers different ways of using variables. A project grows quite a lot and with time they get bigger, if we use the variables here and there it will soon become painful. That is why it is a good practice to keep all variables in one place, which is in group_vars. Naming role specific variables with prefix also helps during debugging and searching the origin of the same variable later. Example naming the variables DB_PORT instead of just PORT.
Passwords and certificates encryption:
It is not good practice to put passwords in plain text either in playbooks or as variable files. Using ansible-vault to encrypt sensitive data is recommended. Later to decrypt the file, only vault password is required.
ansible-vault create host_vars
New Vault password:
Confirm New Vault password:
Use asserts:
Validating the parameters before using them is also an excellent practice to set up. By doing such checks, you have the opportunity to fail earlier in order processing. Example:
tasks:
- name: "Validate value is > 0"
assert:
that:
- "{{ value | int }} > 0"
msg: "'value' must be > 0, it is \"{{value}}\""
Use tags:
Using tags can drastically reduce the run time of your playbook or role because it will run only the chunk of code that you wanted. It gives you more control since you can filter certain tasks and execute only them. On command line, ansible gives you two options to select or to ignore the tags during execution by using -t/–tags or –skip-tags. Example:
someplaybook.yml
---
- hosts: all
become:true
tasks:
- name: Install package
yum: name=httpd state=present update_cache=yes
tags:
- install
- name: Fetch some files
fetch:
src: /var/lib/jenkins
dest: /tmp/bckup/
tags:
- backup
Now, suppose you want to install only package, you can select the install tag which will tell ansible to run only this task.
ansible-playbook someplaybook.yml --tags "install"
Similarly, if you want to run a task only to backup jenkins, you can run
ansible-playbook someplaybook.yml --tags "backup"
OR
ansible-playbook someplaybook.yml --skip-tags "install"
Use ansible-lint for code evaluation:
ansible-lint provides the means to evaluate your roles and playbooks before actually executing them. However, you need to install ansible-lint before using it. Ansible docs suggest two ways to install this.
. Using pip : pip install ansible-lint
. By source : pip install git+https://github.com/ansible/ansible-lint.git
Configuring ansible-lint is fairly simple, it uses .ansible-lint from the working directory or can be explicitly specified by -c switch -c /directory/file. Example :
- hosts: web
become: true
tasks:
- name: ensure nginx latest version is present
yum: name=nginx state=latest
- name: modify the config file
template:
src: /tmp/nginx.conf
dest: /etc/nginx/nginx.conf
Running ansible-lint nginx.yml will output:
ansible-lint nginx.yml
[403] Package installs should not use latest
nginx.yml:5
Task/Handler: ensure nginx latest version is present
ansible-lint accept list of playbook or list of roles directories as parameter. Any role that is part of playbook will also gets evaluated.
Testing with Molecule:
You can’t be confident on the ansible roles and playbooks you created until you know it is going to work as intended, one way of making sure is to run test on the role you have developed. Molecule is a tool developed in python which can be used to test roles. When you run molecule test it executes different kind of test like syntax check, linting, unit tests and ensuring idempotence.
Initialization of molecule is done by for a role is done by:
molecule init --role-name apache
This will create a directory with name molecule inside your role apache/molecule. The directory structure will look something like:
molecule/
└── default
├── Dockerfile.j2
├── INSTALL.rst
├── molecule.yml
├── playbook.yml
├── tests
│ └── test_default.yml
└── verify.yml
Two important files are molecule.yml and playbook.yml. molecule.yml is molecule configuration file and playbook.yml is the file that actually invokes your role. Inside tests directory you can define your test files that will be used for unit testing.
Leave a Reply
Be the First to Comment!