Multi Environment Ansible Layout – Part 2: The Inventory
In yesterday’s post I did an overview of the Ansible repository layout.
Today, we’re gonna dive into the
inv/ (inventory) folder.
. ├── group_vars/ │ ├── all/ │ │ ├── 10-global-secrets.yml │ │ └── 10-global-variables.yml │ ├── integration/ │ │ ├── 10-integration-secrets.yml │ │ └── 10-integration-variables.yml │ └── production/ │ ├── 10-production-secrets.yml │ └── 10-production-variables.yml ├── host_vars/ │ └── backup.example.com/ │ └── 10-ansible.yml ├── int/ │ ├── ec2.ini │ ├── ec2.py -> ../.shared/ec2.py │ ├── group_vars -> ../group_vars/ │ ├── host_vars -> ../host_vars/ │ ├── localhost -> ../.shared/localhost │ └── mapping.yml ├── prod/ │ ├── ec2.ini │ ├── ec2.py -> ../.shared/ec2.py │ ├── group_vars -> ../group_vars/ │ ├── host_vars -> ../host_vars/ │ ├── localhost -> ../.shared/localhost │ └── mapping.yml └── .shared/ ├── ec2.py └── localhost
Reminder about terms
As I mentioned in yesterday’s post, there are two new variables/terms I’ve created for the environments:
environ— a "short" term for an environment (aka
environment_long— the longer version of an environment (aka
We create a single location for
group_vars in the
inv/ folder, this folder should contain subfolders one for
all/ where the global variables end up, and one per environment, using the value of the
This folder may also contain per-ansible-group folders (aka
Each of these per-environment folders can contain either Ansible variable files (YAML format), or an Ansible-Vault secret files.
I like to add numbering to them so that things sort properly on includes.
Also, spread your variables out. Don’t use a single file for the environment’s variables. I like to use a single file per "app" This makes maintaining much easier (esp with ansible-vault encrypted files).
Same thing goes for the
One folder per host.
I often use this for a one-host exception to an Ansible connection setting (changing connection host or user for example).
environ inventory folders
Next, you’ll notice there’s a per
environ (aka short name) folder for each environment.
This is where we tell Ansible which environment we are using
ansible-playbook -i inv/int playbooks/site.yml
To make this layout work each per-environ folder contains a symlink to a single source for the
localhost inventory files.
You find these in the
This reduces the places we have to make changes if we update either file.
Each per-environ folder has it’s own separate copy of the
ec2.ini configuration file.
This file is used to configure the dynamic inventory script specific to each environment.
Also we symlink
host_vars into this folder to make sure it’s in the place ansible expects it to be.
ec2.ini configuration file
To have my dynamic inventory script return just the hosts related to the inventory for each environment I setup some filters in the
regions = all regions_exclude = us-gov-west-1, cn-north-1
If you limit this to just the regions in which you have resources the execution time for
ec2.py goes down considerably.
instance_filters = tag:environ=int
When I create instances in AWS I mark the instance with a tag related to its environment.
instance_filters to get just the resources tagged with
environ set to
In a later blog post I’ll show you how to use Boto profiles to automatically use the proper AWS credentials for each environment.
This is where most of the heavy lifting occurs.
Here is an example of a
--- all: vars: environ: int environment_long: integration children: integration: integration: children: web: app: db: web: children: tag_ServerClass_web: app: children: tag_ServerClass_app: db: children: tag_ServerClass_app:
vars section at the top properly sets the variables
It also puts all of the groups into the
integration group in the second section.
Each individual dynamic instance (which is tagged in AWS with the
ServerClass tag) gets put into its proper group as well (see the
db groups above).
This is how the dynamic hosts from EC2 inventory end up with proper "clean" names.