Scaffolding or structuring your Ansible projects mean that not only do you have a sane way understanding how your projects are put together but you can also look at being able to re-use and extend your DevOps projects.
In the below example I share the tree structure of general Ansible projects and how I use .gitmodules
to pull in community and custom roles for managing projects.
$ tree -a -L 3
.
├── ansible.cfg
├── CHANGELOG.md
├── .gitlab-ci.yml
├── .gitmodules
├── git-submodules.sh
├── inventory
│ ├── group_vars
│ │ └── group1
│ │ ├── vars.yml
│ │ └── vault
│ ├── host_vars
│ │ └── host1.example.com
│ │ ├── vars.yml
│ │ └── vault
│ │ └── host2.example.com
│ │ ├── vars.yml
│ │ └── vault
│ └── inventory
├── LICENCE.md
├── playbooks
│ └── ping.yml
├── README.md
├── roles
│ ├── geerlinguy.java
│ │ ├── defaults
│ │ ├── .gitignore
│ │ ├── LICENSE
│ │ ├── meta
│ │ ├── molecule
│ │ ├── README.md
│ │ ├── tasks
│ │ ├── templates
│ │ ├── .travis.yml
│ │ └── vars
│ └── willhallonline.acme_sh
│ ├── defaults
│ ├── .gitignore
│ ├── LICENSE
│ ├── meta
│ ├── molecule
│ ├── README.md
│ ├── tasks
│ ├── .travis.yml
│ └── vars
└── vars
└── vars.yml
ansible.cfg
fileI like to be able to change my ansible.cfg
for each project as required (my preference is to use Mitogen but it doesn’t work via Jump hosts very well). Largely I keep the basic setup of ansible.cfg
with a few small adjustments to accomodate the directory structure. I usually place these at the end of the [defaults]
section.
ansible.cfg
Example...
inventory = ./inventory/inventory
roles_path =./roles
host_key_checking = False
retry_files_enabled = False
remote_user = ansible
gathering = smart
strategy_plugins = /usr/lib/python2.7/site-packages/ansible_mitogen/plugins/strategy
strategy = mitogen_linear
As you can see there a a few changes. I adjust the location of roles and inventory, set retry_files_enabled
and host_key_checking
as False, set remote_user
as ansible
and finally add in Mitogen (if you are not using Mitogen you can comment this out).
The first level is really the basic project setup for any code project. I normally like to be explicit with regards to the file format (I like having file extensions) so I use the *.md extension where possible. This gives us the:
As I mainly use GitLab CI for testing then I include a .gitlab-ci.yml
file however, if you are working with other CI tools then use them (.travis.yml
or .circle-ci.yml
). For general CI work I normally look at using yamllint
on every *.yml
file which means that the
The directory structures I normally use are based around 5 years of experience using Ansible. We want to be able to separate generally our inventory, roles, and playbooks. I normally also place a vars directory although looking through some live projects I can see that I barely ever use it unless the project is really a single use project.
inventory
DirectoryAnsible does allow an amount of flexibility with the use of files, however, I normally like to keep all inventory files inside the same directory. As the inventory/inventory
file does not have linting and therefore I do not put an extension on it.
host_vars
and group_vars
DirectoryThe host vars and group vars are the main location for all variables with regards to projects, these are normally separated inside the host_var
directory with the {{ inventory_hostname }}
, however, this can change when loading local hosts of hosts via a VPN.
Inside the directories I keep a vars.yml
and vault
files. These serve as all of the variables for the playbooks that are being run. Obviously I use Ansible Vault for encryption of any secure credentials and normally decrypt on runtime with a password --ask-vault-pass
.
Keeping vars.yml
separate enabled you to be able to lint the directories whilst also enabling easy changing of details.
roles
DirectoryInside the roles
directory I normally keep a mix of both community and custom roles. Ideally they are all version controlled elsewhere and pulled in using .gitmodules
. And updated with $ git submodule update --remote
.
In the example tree above, I use both have used both the willhallonline.acme_sh
and the geerlinguy.java
role. As they have been cloned from github, I use a {github-username}.{role-name}
structure for the roles. This not only means that the roles are relatively well understood, but that you can relatively easily include them inside playbooks.
.gitmodules
for Ansible Roles[submodule "roles/geerlingguy.java"]
path = roles/geerlingguy.java
url = https://github.com/geerlingguy/ansible-role-java.git
[submodule "roles/willhallonline.acme_sh"]
path = roles/willhallonline.acme_sh
url = https://github.com/willhallonline/ansible-role-acme_sh.git
This can be deployed easily with the included git-submodules.sh
script that I include find out more about Scripting the adding of Git Submodules.
playbooks
DirectoryI try to keep the playbooks
directory flat, putting descriptive names for the playbooks. A playbook I try to keep everywhere is a simple ping playbook which will confirm connection.
ping.yml
Playbook---
- hosts: all
tasks:
- ping:
Hopefully this helps with future structuring of Ansible projects and do let me know if you think I could do some changes.
Connect on LinkedIn. Follow me on Twitter. Grab the RSS Feed