Introduction
Ansible is a powerful configuration management system used to configure and manage infrastructure and applications in a variety of environments. While Ansible provides easy-to-read syntax, flexible workflows, and powerful tools, managing large numbers of hosts can be challenging if they differ depending on the deployment environment and functionality.
In this tutorial, we'll discuss some strategies for using Ansible to work with multi-stage deployment environments. Typically, the requirements for different stages lead to different quantities and different configurations of components. For example, memory requirements for a development server may differ from those for staging and production environments, and it is important to have explicit control over how the variables that represent those requirements take precedence. In this article, we'll discuss some of the ways to abstract these differences and some of the constructs that Ansible provides to encourage configuration reuse.
Incomplete strategies for managing multistage environments with Ansible
While there are several ways to manage environments in Ansible, Ansible itself does not offer a better solution. Rather, it provides many constructs that can be used to manipulate environments and allows the user to choose.
Approach, which we demonstrate in this guide is based on a group of variables Ansible and multiple registers ( Inventories ). However, there are several other strategies worth considering. We'll look at some of these ideas below and find out why they can be problematic when implemented in complex environments.
If you'd like to get started with the recommended Ansible strategy, skip to the section on using Ansible groups and multiple registries.
Relying solely on group variables
, Ansible . , . Ansible . . . :
- (, dev, stage, prod . .)
- (-, . .)
- (NYC, SFO . .)
. , - () ( ) - ( ).
, Ansible . , , , , Ansible .
Ansible . Ansible , , , . , .
Ansible , [groupname: children]
. . , .
. , environment
, dev
, stage
, prod
. , environment
dev
. , functions
, web
, database
loadbalancer
.
, . , , environments
functions
. .
, . , , :
, :
. . . [function:children] web database loadbalancer region [region:children] nyc sfo environments [environments:children] dev stage prod
, , region
function
. , environments
, . , dev
, nyc
web
, , , dev
.
. , . Ansible , . .
Ansible-,
Ansible , , vars_files
include_vars
. Ansible plays , . vars_files
, include_vars
.
, group_vars
, .
, group_vars
:
group_vars/dev
--- env: dev
group_vars/stage
--- env: stage
group_vars/web
---
function: web
group_vars/database
---
function: database
vars
, . vars. group_vars
, include_vars
.yml.
, server_memory_size
vars
. , , , . , - :
vars/dev.yml
--- server_memory_size: 512mb
vars/prod.yml
--- server_memory_size: 4gb
vars/web.yml
--- server_memory_size: 1gb
vars/database.yml
--- server_memory_size: 2gb
playbook, vars
, group_vars
. , .
vars_files
:
example_play.yml
---
- name: variable precedence test
hosts: all
vars_files:
- "vars/{{ env }}.yml"
- "vars/{{ function }}.yml"
tasks:
- debug: var=server_memory_size
, server_memory_size
var/web.yml
var/database.yml
:
ansible-playbook -i inventory example_play.yml
Output. . . TASK [debug] ******************************************************************* ok: [host1] => { "server_memory_size": "1gb" # value from vars/web.yml } ok: [host2] => { "server_memory_size": "1gb" # value from vars/web.yml } ok: [host3] => { "server_memory_size": "2gb" # value from vars/database.yml } ok: [host4] => { "server_memory_size": "2gb" # value from vars/database.yml } . . .
, :
example_play.yml
---
- name: variable precedence test
hosts: all
vars_files:
- "vars/{{ function }}.yml"
- "vars/{{ env }}.yml"
tasks:
- debug: var=server_memory_size
playbook , :
ansible-playbook -i inventory example_play.yml
Copy
Output. . . TASK [debug] ******************************************************************* ok: [host1] => { "server_memory_size": "512mb" # value from vars/dev.yml } ok: [host2] => { "server_memory_size": "4gb" # value from vars/prod.yml } ok: [host3] => { "server_memory_size": "512mb" # value from vars/dev.yml } ok: [host4] => { "server_memory_size": "4gb" # value from vars/prod.yml } . . .
include_vars
, , :
--- - name: variable precedence test hosts: localhost tasks: - include_vars: file: "{{ item }}" with_items: - "vars/{{ function }}.yml" - "vars/{{ env }}.yml" - debug: var=server_memory_size
, Ansible , . , , .
, vars_files
include_vars
, , , . group_vars
, vars
. . , Ansible group_vars
.
, . playbook , . Playbook . , ansible
-, .
Ansible:
, . Ansible , .
— , . , , . group_vars
.
:
. ├── ansible.cfg ├── environments/ # Parent directory for our environment-specific directories │ │ │ ├── dev/ # Contains all files specific to the dev environment │ │ ├── group_vars/ # dev specific group_vars files │ │ │ ├── all │ │ │ ├── db │ │ │ └── web │ │ └── hosts # Contains only the hosts in the dev environment │ │ │ ├── prod/ # Contains all files specific to the prod environment │ │ ├── group_vars/ # prod specific group_vars files │ │ │ ├── all │ │ │ ├── db │ │ │ └── web │ │ └── hosts # Contains only the hosts in the prod environment │ │ │ └── stage/ # Contains all files specific to the stage environment │ ├── group_vars/ # stage specific group_vars files │ │ ├── all │ │ ├── db │ │ └── web │ └── hosts # Contains only the hosts in the stage environment │ ├── playbook.yml │ └── . . .
, . (hosts
) group_vars
.
. web
db
. . , , , . group_vars
.
. , , . -, . .
, , — . . — Ansible . all
group_vars
all
.
, , . , . .
- . (environments
). :
cd environments
touch 000_cross_env_vars
group_vars
, all
all
. :
cd dev/group_vars mv all env_specific mkdir all mv env_specific all/
, :
cd all/ ln -s ../../../000_cross_env_vars .
, :
. ├── ansible.cfg ├── environments/ │ │ │ ├── 000_cross_env_vars │ │ │ ├── dev/ │ │ ├── group_vars/ │ │ │ ├── all/ │ │ │ ├── 000_cross_env_vars -> ../../../000_cross_env_vars │ │ │ │ └── env_specific │ │ │ ├── db │ │ │ └── web │ │ └── hosts │ │ │ ├── prod/ │ │ ├── group_vars/ │ │ │ ├── all/ │ │ │ │ ├── 000_cross_env_vars -> ../../../000_cross_env_vars │ │ │ │ └── env_specific │ │ │ ├── db │ │ │ └── web │ │ └── hosts │ │ │ └── stage/ │ ├── group_vars/ │ │ ├── all/ │ │ │ ├── 000_cross_env_vars -> ../../../000_cross_env_vars │ │ │ └── env_specific │ │ ├── db │ │ └── web │ └── hosts │ ├── playbook.yml │ └── . . .
, 000_cross_env_vars
, .
ansible.cfg
. .
-, ansible
ansible-playbook
. :
ansible -i environments/dev -m ping
, :
ansible -m ping
-, . . , , -i
.
, ansible.cfg
. /etc/ansible/ansible.cfg
.
. ansible.cfg
. /etc/ansibile/ansible.cfg
, . /etc/ansible/ansible.cfg
/etc/ansible
, .
nano ansible.cfg
, . , hosts:
[defaults] inventory = ./environments/dev
-i
. - -i
, .
In this article, we explored the flexibility Ansible provides for managing your hosts in multiple environments. This allows users to apply many different strategies to handle variable priority when the host is a member of multiple groups, but the ambiguity and lack of official guidance can be a problem for you. As with any technology, the best fit for your organization will depend on your use cases and the complexity of your requirements. The best way to find a strategy that's right for you is to experiment. Share your use case and approach in the comments below.