Thursday, 19 March 2015

Ansible - Sharing Inventories

Recently I needed to share an Ansible inventory with multiple playbooks in different code repos.  I couldn't find a way to do this nicely without writing some new code which I'll share here.

Trisha Gee sums up how I feel about this...  "I'm doing something that no-one else seems to be doing (or talking about). That either means I'm doing something cool, or something stupid."  Perhaps I missed an ansible feature, if so, please let me know!  I am new to it.  If not, perhaps ansible could add support for this.

EDIT 19/7/2015

I'm now of the opinion that this is a bad idea.  Regarding the Trisha Gee quote above - I now know what it was I was doing (hint... not cool).  

I am no longer sharing inventories as now all of our ansible deployment config (except a few roles) are in one git repo.  This same repo holds our inventories so no need for sharing.  If I did have to share them, I'd use git sub modules. 
The solution detailed here is not a good idea, but will leave it here anyway!

EDIT 30/3/2015

Git Sub Modules offer a better alternative...
Not entirely sure (only just learnt about this) but thought I'd share.

Why do I need to share inventories?


We currently describe our architecture using static inventories.  One file per environment.  As per the examples on the ansible docs, we define things like [databases], [webservers] and [applications].  I want all of this in one file and one code repo so that it's all defined in one place.  The project that builds and deploys the web layer is separate to the application layer.  I did consider separating inventories by environment AND layer, e.g. test-web-inventory and test-application-invetory.  However, because the web nodes needs to know about the application nodes and likewise application to database that would lead to duplicating data. 

Why not use a dynamic inventory?


It feels too much too soon.  The architecture is currently quite simple and I don't want to introduce more complexity (and dependencies) into the build and deploy pipeline until I have to.  A flat file is reassuringly simple.  Once the architecture grows and the flat file becomes untenable, then I think it will be time for a dynamic inventory.

How I shared inventories




I put the inventory files within a shared role, that gets assigned to localhost only by the specific playbooks that need it.  That way, once we have installed the playbook's requirements (using ansible-galaxy install), we have the specific version of the inventory files on the file system.  Then we can run our playbooks referencing the freshly retrieved files.

That might sound ugly, but it was that or custom bash scripts that check things out of git.

In more detail


The shared-inventory-role I created looks like this:

├ files
├── dev-inventory
├── test-inventory
├── prod-inventory
├ meta
├── main.yml (standard for describing role)
├ tasks
├── main.yml (do nothing task - maybe not required)

Each -inventory file containing the full inventory that describes that environment.  This role is in it's own git repo.

The playbooks that then import this role (e.g. the playbook for the application servers) do so by referencing it in their requirements.yml file as follows:

- src: ssh://
  scm: git
  version: ac1c49302dffb8b7d261df1c9199815a9590c480
  path: build 

  name: shared-inventory

(note that I can reference a specific version)

Then, when we come to running the playbook, we simply install the playbook's requirements first as follows:

ansible-galaxy install --force -r requirements.yml

This forcefully installs the requirements (i.e. overwrites whatever is currently there) into the build directory.

Then we can apply our playbook with our inventory as follows:

ansible-playbook site.yml -i build/shared-inventory/files/test-env


  • Have I missed a simpler way to do this?
  • Is this a feature that could/should be added to ansible?

No comments:

Post a Comment