One of the main purposes of why the humanity developed machines, and computational systems in general, was to avoid doing repetitive and simple tasks that would consume time; time that could be spent making progress in other tasks that do require a complex thinking that only a human being may do.
The funny thing is that the machines and the computational systems have brought their own repetitive and simple tasks, so, in a way, we have just traded one repetitive task for another. Tasks like the maintenance of a big machine, a computer software update or even cleaning the files from your smartphone are repetitive tasks for the 21th century. For these repetitive tasks we have also develop machines and systems that would help you to save time. There are machines that clean up and fix other machines autonomously, almost all the software updates are automatically installed and there are apps that delete your unused smartphone files every once in a while.
Working with web development is full of repetitive tasks that, amazingly, a lot of people still do manually. In some companies, they even have a person whose labor is to do the same things over and over again. Tasks like updating the code on the server after a sprint has been finished, installing or updating system packages, configuring services like apache or nginx or even deleting unused instances are tasks that are very similar every time they are executed so they could be automatized; but they are not.
Here is where ansible appears. According to their documentation
Ansible is an IT automation tool. It can configure systems, deploy software, and orchestrate more advanced IT tasks such as continuous deployments or zero downtime rolling updates.
In order to use ansible, you just need to have installed python on your server machine (ansible is a python package) and an ssh key to connect to it. Then, you may start executing your own ansible playbooks.
By writing an ansible playbook, that will be explained later, you set the desired state for your server. Notice that you do not establish a set of tasks to be executed every time, like a conventional computer language, but you describe a server state that ansible will ensure everytime the playbook is executed.
Lets illustrate this with an example. Consider the following playbook taken from the official documentation:
- name: ensure apache is at the latest version
yum: name=httpd state=latest
- name: write the apache config file
template: src=/srv/httpd.j2 dest=/etc/httpd.conf
- restart apache
- name: ensure apache is running (and enable it at boot)
service: name=httpd state=started enabled=yes
- name: restart apache
service: name=httpd state=restarted
Here, you may see tasks and handlers. First, let’s discuss tasks. As you may see, each task has a descriptive name in order to know what it its objective. There are several type of tasks for ansible; there are tasks for package managers as yum or apt; there are also tasks for services, for files, etc.
The first task of the example, ensure apache is at the latest version, updates the apache version to its latest but only, and this is where ansible shows its power, if it needs to be updated. If apache is already updated, ansible does not execute this task, why would it if the task would do nothing? Thanks to this behavior, ansible avoids waisting time in redundant or unnecessary tasks executions.
Let’s continue, the second task, write the apache config file, is a template task; this allow ansible to copy a file to a destination inside the server. The file is not a file, it is a template, that uses Jinja2 to render its content so it may be dynamic. We are not going to explore this topic on this blog post, but it is one of the main and most important features that ansible offers. Like the previous task, if the file already exists with the content the user intends to copy there, ansible does not execute this tasks; why would it copy an already existing file?
But here appears an extra factor, the handlers. As you may see, this task has a notify argument. This argument informs ansible that the handler restart apache should be notified if this task is executed. We will explore this in a moment, first let’s finish with the tasks.
The last task, ensure apache is running (and enable it at boot), checks the apache service state and starts it if it is not running. If the service is already running, the task is skipped.
Now, lets get back to the handlers. As you may see, the restart apache handler is very similar to the ensure apache is running (and enable it at boot) task. The only difference is that one checks that the apache service is running and the other one restarts the service. So, why is one a task and the other one a handler? it is because you always need to check that the apache service is running, but you do not need to restart the service every time something happens on the server.
The main difference between tasks and handlers is that ansible always checks if the tasks should be executed; it checks the state described by the task and executes it depending on it. On the contrary, ansible checks the state described by the handlers only if a handler has been notified. Else, the handler is skipped.
Let’s go back to the example, the handler restart apache will only be executed if the tasks write the apache config file, is executed, the apache configuration file changes and the notification for the handler is sent. Else, the handler will not be executed; and it makes sense, I do want to restart the apache service if the apache configuration file changes in order to apply the modifications but I do not want to restart it if the file is the same one after the execution has been finished.
There are two important considerations for the handlers. The first one, they will always be executed at the end of the process, once all the tasks have finished. The other one is that every handler will be executed only one time even if it has been notified more than once.
This has been just a quick view of all the power ansible has to offer. One of the main advantages is that it reduces the human mistakes to zero because, once you have develop your playbook, you are sure that the server will always have the desired state and you do not have to worry to forget to perform a task on it. The other main advantage is that ansible, thanks to its inventory system, allows you to use the same playbook with different servers and with different servers considerations with no too much extra effort.
Along with the inventory system, ansible also has a roles system. It allows you to create sets of tasks that may be reused across different playbooks. It even has a library called ansible galaxy where you may download other people roles and other ansible content. I will write about ansible roles on another entry.
Here at swapps we have saved a lot of time automatizing our server developments and we have created our own continuous integration application, https://deploycloud.io/. Thanks to it, we are able to focus on what really matters while deploycloud handles all the repetitive tasks; saving us time and money.