Friday, 20 May 2016

Inverting Ansibe execution flow. The Pull Mode

In most cases,  where I've seen Ansible being implemented to automate ops taks is using the Push mode. On this approach, playbooks start running from a given host where Ansible is set. The Ansible host is gonna interpret the tasks and apply   "pushing" them to all target hosts through SSH.
What is maybe unnoticed when start playing with It, is the fact that the same results can be achieved by using a totally different flow, the Pull Mode.

There isn't much about It on the official documentation, but the idea is pretty simple.Instead of pushing playbooks to  the target hosts, using pull mode you can make target host "pull" them from a given repository.  By doing this, there is no need to have a single machine playing the ansible-host role, in this scenario, this responsibility is spread on the machines on the datacenter..
There is nothing special in order to get It running.Both, Pull and Push will be available after following the installing steps available here.
Lets say I want to deploy the application I build here using the Pull mode in all my cluster machines. After having Ansible properly installed  on the target hosts, the following command should be raised:

This command will connect on Github and download the entire repository locally. After doing this, Ansible will look for a file named as Local.yml. This file should contains all tasks, or a reference to the ones who have them in order to perform  a playbook.
An interesting approach is to make the target hosts pull the remote repository times to times. By doing this, changes will be applied on all target machines asynchronously and in background as soon they are available on the repository.That could be quite interesting when talking about provision hundreds or thousands of machines. This mode will scale much better than the Push mode. This can be achieved by just setting a cron job.  and calling a script that encapsulates the pull command described before, like this:

The Pull mode can be useful also to  change application configuration more dynamically. By using tags, I can update the log4j config as soon they hit the remote repository:

As we can see, there are a range of scenarios where the Pull mode can be useful. BTW, It could be a bit more flexible by letting the user specify which playbook to run (It only look or a file named as Local.yml, something different  than that is gonna produce an error).  Users need also be careful when sending code to repository when using this feature. Code badly written can break an entire datacenter without you notice.


Sunday, 1 May 2016

Organizing Automation - Ansible Roles

When talking about automation, Ansible is definitely one of the most simple and easy to use frameworks. It has a pretty low learning curve due Its comprehensive DSL, which is easy to understand. You also don't need to install anything on the server that will be provisioned (agent less architecture), which makes the setup simple. Everything looks great when the provisioning process has only two or three script files, but as soon you add more functionalities ,there will be some issues to deal with:

  • Reuse: there are certain provisioning tasks that are common to all servers, how to organise them in a such way they can be reused easily?
  • Organisation: similar as any programming code, without maintenance and good engineering practices,  the provisioning process will be difficult to maintain and understand. Naming,  modules organisation, conventions are all aspects that needs to be taken into account.

Ansible Roles

Ansible Roles are conventions that as a programmer you need to follow in order to achieve good level of reuse and modularisation. These conventions were added on version 1.2  and before this, the way to achieve better level of reuse was separating scripts into different files and including them on other scripts you want to reuse.
The documentation is very sparse when describing how Roles work, but the idea is pretty simple. Using Roles, you will be able to automatically load tasks, variables, files and handlers when provisioning a server or a group of them. 
Lets look to an example, here I'm provisioning a Java application service. The server to run this application will need to have the following roles:

The role common is a role that any server in my infrastructure will need to have (reuse), which in this case is have JDK installed. The other role is called service, which is basically the things needed to run the service run the service Itself.

Ansible will automatically look for a directories called commons and service inside the main directory roles and execute all steps defined for them.
For the role service, we have:

  • vars

  • tasks

  • handlers

  • files: All files used on tasks will loaded from there.
There is still more directories that can be defined like templates and defaults. They aren't  present on this example but are still useful. This is the full working example that provision a server that is able to run this Java application.

Using roles is great because they are expressive. Working with them properly you will be able to say what a given server is, which is much more declarative than just use the include directives. The directory conventions are good to define patterns to the whole team follow since day one and reuse achieved by defining very granular roles that can be set on different play books.