Multi Environment Ansible Layout – Part 1
One of the more difficult things about using Ansible is deciding on how to lay things out in the file system.
This is the layout I’ve settled on after a few different tries.
This layout solves the following issue:
-
Multiple environment (development, integration, staging, production)
-
Supports environments living in different AWS accounts
-
Per-environment variables
-
Global variables
-
-
Hybrid inventory (some hosts from AWS, some locally defined)
-
Secrets and variable are managed using smaller scopes
Overview
The layout looks like this:
.
├── ansible.cfg
├── ansible-roles.yml
├── .gitignore
├── inv/
│ ├── 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
├── playbooks/
│ ├── app.yml
│ ├── db.yml
│ ├── Site.yml
│ └── web.yml
├── roles/
│ └── .gitkeep
├── roles-inline/
└── .vault/
└── password
A git repository with the full layout can be found here
The term environment is reserved in Ansible.
I’ve created two new terms to get around this limitation:
-
environ— a "short" term for an environment (akaintorstage). -
environment_long— the longer version of an environment (akaintegrationorproduction).
These are set using the YAML inventory mapping file inv/<environ>/mapping.yml.
Top-Level Files and Folders
-
ansible.cfg— The Ansible configuration file. We make a few changes from the stock file which ships with Ansible.-
roles_path— We add the two folders we’re using for roles into the roles path settingroles_path = roles/:roles-inline/
-
vault_password_file— I set this to avoid having to type the password when using theansible-vaultcommandvault_password_file = .vault/password
-
retry_files_enabled— I find the creation of retry files annoying, so I turn it offretry_files_enabled = False
-
nocows— Some people find the use of thecowsaycommand in the Ansible output annoying. If you agree, set the following:nocows = 1
-
-
ansible-roles.yml— The third-party roles file. This file is used with the commandansible-galaxyto install third-party Ansible roles.ansible-galaxy install -r ansible-roles.yml -p roles/
-
.gitignore— Git ignore file. This file helps us keep secrets and third-party Ansible roles out of our git history. Currently the contents look like this:.vault/ roles/
-
inv/Top-level inventory folder. (more on this later) -
playbooks/— Playbook storage. -
roles/— Storage location for third-party Ansible roles.-
Notice the
.gitkeepfile there, we usegit add -f roles/.gitkeepto override the gitignore file above to keep this empty directory on checkout.
-
-
roles-inline— Where we write Ansible roles which we want to be a part of this git repository. -
.vault— Where we store the password file for theansible-vaultcommand.-
Normally this password file would be ignored in git, I’ve added it so that the
ansible-vaultcommands will work for people using my example layout.
-
Inventory Drill-Down
Tomorrow we’ll cover where the real power for this layout comes from, the inventory!