Organizing Ansible

While we’ve been using Ansible for almost a year at Kinetic Cafe, I’ve been spending a lot more time with it at a personal level. A big part of it is that I tend to really like being familiar with the tools that my team uses at work and the other is because I actually have a lot of home and cloud servers running because I tend to like being familiar with the tools that the team uses at work. Ansible’s strength stems from the idea that you can ssh to a server and perform a series of tasks based on modules already built for you. At it’s core are concepts like inventories, roles, handlers, dependencies and variables but then allows users to use it in many different ways within that structure. However, this flexibility lead to chaos when I started to use it so I took some time organizing Ansible in a meaningful way for my home infrastructure.

Repository

I actually split up my repository into 2 parts. One is the overall project repository and the other is a git sub-module for the roles directory. The roles directory is a repository that is shared with all my other projects and is also publicly available on bitbucket. I organize my repositories around my projects. For instance, the one that I’m working on is called “Home” where I organize things like my main Domain server, Virtual Machine servers, media server and NAS server.

Directory structure

Roles

I have a very strong opinion on how roles should work in Ansible and it differs from Austin Ziegler’s who is a colleague of mine whom I have deep respect for. I approach roles the same way as an “old school” code library. Each role, like a code library, organizes functions into groups. Within each group, there will be specific functions that will be accessible as tasks. The format that I organize my groups are prefixed with a functional group followed by a name (i.e. os-ubuntu-base to depict that this role is meant for operating systems and the operating system in this case is Ubuntu). For each role, there will be a readme.md file to describe the purpose of that particular role. Austin and I agree in terms of overall approach which is to depend on roles as much as possible. Where we defer is how atomic should those roles be. For instance, if I were to install Ruby on Rails, I would have three roles for that machine – the os (which is Ubuntu in my case), the language (which is ruby in this case) and then the framework (which is rails in this case). For Austin, there would likely be multiple roles which would include the os, the networking setup, . I personally struggled with the level of granularity because I felt that it would become harder to manage over time and I personally didn’t see the pragmatic value of it when using it in my own personal environments.

Inventory

I separated out inventory as a separate directory because I wanted an easy way to identify where my inventories were. Practically speaking, you would create an inventory for each environment. For my home infrastructure, I would likely only have one inventory file and this would likely remain at the project root level and default to the Ansible standard hosts file.

Files

We’d store all of the common files here that are specific to your project and aren’t accessible via the internet. An example here would be the public ssh key for users that I want to install on the machine. Files that are commonly used for every install regardless of environment or company should be stored within the role system.

Group Variables

One of the very nice things about the inventory concept in Ansible is that it allows you to organize your inventory into groups and they could have parent-child relationships between the groups. This ability enables you to inherit variables from the parent groups which allows you to better separate between application variables specific to your project and/or company versus application variables specific to the deployment environment.

Host Variables

Host variables are machine specific information is stored. The key things that I typically put in here would be things like the actual DNS name of the machine, the network devices as well as IP addresses. These are then used to set up the machine as well as apps that have to point to machine specific settings.

Play books

Play books aren’t directory structures but are how Ansible scripts are run. My playbook are extremely lightweight and primarily consist of roles. Play books have to be run from the root level of the directory. Ideally, there shouldn’t be too many play books to run.

Hopefully this is a good start for those who are thinking about playing around with Ansible. I’ll continue updating the shared roles library that I created as it’s still in its infancy and have a lot more work left to do on it.