Tricks Of The Trades

Ansible – Inventory Concepts (2)

Pinterest LinkedIn Tumblr

After outlining the initial installation and setup process in Ansible – Installing and Running (1) I’m continuing in this post with a more precise look at how to handle the main hosts file. Specifically how to lay it out and add host variables or group variables to the mix. Dynamic inventory assets and development/production inventory layouts are not covered here and only alluded to or linked to.

Lastly splitting up the variable types and their definitions into their own YAML files is briefly introduced in the final step, and works best for more complex network hierarchies.


1 – Hosts Inventory File

As shown in “Ansible – Installing and Running (1)” Ansible operates by working simultaneously with multiple hosts in your infrastructure. It’s preferred way of doing this is to allocate hosts into different groups inside of the inventory file – /etc/ansible/hosts

  1. $ ls /etc/ansible/
  2. ansible.cfg hosts hosts.orig roles

This file is completely configurable and can be expanded or broken up into multiple inventory files.

  1. $ sudo vim /etc/ansible/hosts

There’s a special form of inventory in Ansible known as dynamic inventory that refers to inventory files or asserts that get pulled down from the cloud, or other server-side sources. This is not covered in this post, however.


2 – Hosts and Groups

As seen in the first post, the INI style formatting for an Ansible hosts file looks similar to this:

/etc/ansible/hosts

  1. [webservers]
  2. webremote.one.ip.address
  3. webremote.two.ip.address
  4. webremote.three.ip.address
  5. [dbservers]
  6. dbremote.one.ip.address
  7. dbremote.two.ip.address
  8. dbremote.three.ip.address

Square brackets [ ] contain a group name which is used to decide what systems you are controlling at what times and for what purpose. This makes it possible to apply actions to specific nodes/hosts as and when necessary.

Also systems (nodes/hosts) can be attributed under more than one group if needed, so in the snippet above one of the example nodes could be both a web server and a database server, added to both group entries in the file.

The hostnames can also be domain names instead of raw IP addresses if preferred, and when adding a large numbers of hosts if the domain names follow a similar numerical pattern, you can use ranges of numbers instead of adding them all individually.

/etc/ansible/hosts

  1. [webservers]
  2. www[01:50].example.com

Lastly, hosts that run on non-standard SSH ports i.e. not 22 must have their custom SSH port numbers inserted after the hostname separated by a colon.

For example:

webremote.one.ip.address:3675

Or instead defined through host/group variables (see next step).


3 – Host and Group Variables

Variables in the inventory file(s) are set on a host basis or group basis. There are many of these inbuilt variables on offer to the user when constructing the file.

Here is an example of two host variables, that explicitly tell Ansible to use SSH as the connection type, with a set username:

/etc/ansible/hosts

  1. [webservers]
  2. webremote.one.ip.address ansible_connection=ssh ansible_user=username
  3. webremote.two.ip.address ansible_connection=ssh ansible_user=username
  4. webremote.three.ip.address ansible_connection=ssh ansible_user=username
  5. [dbservers]
  6. dbremote.one.ip.address ansible_connection=ssh ansible_user=username
  7. dbremote.two.ip.address ansible_connection=ssh ansible_user=username
  8. dbremote.three.ip.address ansible_connection=ssh ansible_user=username

Note: username would be replaced by the actual Ansible user on these hosts in the above.

In the first post on Ansible I laid out these host variables and the file formatting differently, by using:

  • An “empty” name for the hosts – server-name-1
  • A host variable that then gives this name an IP address to refer to – ansible_host=remote.one.ip.address
  • Another host variable with the specific username like in the previous example – ansible_user=username
  • Then a final host variable that holds the custom SSH port to use when connecting to this host – ansible_port=3980

Here is what the layout looked like for this file:

/etc/ansible/hosts

  1. [servers]
  2. server-name-1 ansible_host=remote.one.ip.address ansible_user=username ansible_port=3980
  3. server-name-2 ansible_host=remote.one.ip.address ansible_user=username ansible_port=3980
  4. server-name-3 ansible_host=remote.one.ip.address ansible_user=username ansible_port=3980

Group variables allow extra options and settings like in the above to be applied to an entire group at once. Instead of having to set the same variables for each host when the value of the variables is the same.

These are defined by creating a new set of square brackets [ ] that contain the group name you wish to apply the variables to, followed by a tag that consists of a : and the term vars .

When put together using a group named “webservers” this makes – [webservers:vars]

The variables you want to apply to the group are then listed on separate lines – an example of all of this is shown in the below code snippet:

/etc/ansible/hosts

  1. [webservers]
  2. webremote.one.ip.address
  3. webremote.two.ip.address
  4. webremote.three.ip.address
  5. [webservers:vars]
  6. ansible_user=username
  7. ansible_port=3980
  8. ntp_server=ntp.example.com
  9. proxy=proxy.example.com
  10. [dbservers]
  11. dbremote.one.ip.address
  12. dbremote.two.ip.address
  13. dbremote.three.ip.address
  14. [dbservers:vars]
  15. ansible_user=username
  16. ansible_port=3980
  17. ntp_server=ntp.example.com
  18. proxy=proxy.example.com

4 – Groups of Groups

There’s a further way of making “groups out of groups” by using the :children tag. These can have group variables applied to them too by using the same method in the last step. To do this extra grouping, a new group name is created then suffixed with the :children tag which will contain the original groups defined.

Such as here:

/etc/ansible/hosts

  1. [webservers-one]
  2. webremote.one.ip.address
  3. webremote.two.ip.address
  4. webremote.three.ip.address
  5. [dbservers-one]
  6. dbremote.one.ip.address
  7. dbremote.two.ip.address
  8. dbremote.three.ip.address
  9. [cluster-one:children]
  10. webservers-one
  11. dbservers-two

To add group variables to this new group of a group, the new name is added to yet another group with the standard :vars tag.

Like at the bottom of this code snippet:

/etc/ansible/hosts

  1. [webservers-one]
  2. webremote.one.ip.address
  3. webremote.two.ip.address
  4. webremote.three.ip.address
  5. [dbservers-one]
  6. dbremote.one.ip.address
  7. dbremote.two.ip.address
  8. dbremote.three.ip.address
  9. [cluster-one:children]
  10. webservers-one
  11. dbservers-two
  12. [cluster-one:vars]
  13. ansible_user=username
  14. ansible_port=3980
  15. ntp_server=ntp.example.com
  16. proxy=proxy.example.com

The concept of grouping groups into more groups can theoretically go on indefinitely. Another level of grouping is added below to demonstrate:

/etc/ansible/hosts

  1. [webservers-one]
  2. webremote.one.ip.address
  3. webremote.two.ip.address
  4. webremote.three.ip.address
  5. [dbservers-one]
  6. dbremote.one.ip.address
  7. dbremote.two.ip.address
  8. dbremote.three.ip.address
  9. [cluster-one:children]
  10. webservers-one
  11. dbservers-two
  12. [cluster-one:vars]
  13. ansible_user=username
  14. ansible_port=3980
  15. ntp_server=ntp.example.com
  16. proxy=proxy.example.com
  17. [webservers-two]
  18. webremote.one.ip.address
  19. webremote.two.ip.address
  20. webremote.three.ip.address
  21. [dbservers-two]
  22. dbremote.one.ip.address
  23. dbremote.two.ip.address
  24. dbremote.three.ip.address
  25. [cluster-two:children]
  26. webservers-two
  27. dbservers-two
  28. [cluster-two:vars]
  29. ansible_user=username
  30. ansible_port=3980
  31. ntp_server=ntp.example.com
  32. proxy=proxy.example.com
  33. [all-clusters:children]cluster-one
  34. cluster-two

More realistically this could be seen in terms of grouping local data-centre hosts into regions and then into a country wide group.


5 – Multiple Inventory Files

The singular /etc/ansible/hosts file is fine for smaller more contained network setups, but the preferred practice in Ansible is not to store variables in the main hosts inventory file. At least when dealing with larger more complex layouts of hosts, or bigger networks.

Host and group variables ideally when handling large scale setups should be stored in individual files. Files that are relative to the main inventory file.

As an example any group variables defined in the below file:

  1. /etc/ansible/group_vars/webservers.yml

Will apply to any hosts located in the webservers group. These variable files are written in YAML.

Similarly, any host variables defined in:

  1. /etc/ansible/host_vars/server-name-1.yml

Are applied to the host named server-name-1 from the original hosts file.

Further segmentation and organization of the host/inventory files is followed but not covered in this post, see Multistage Environments with Ansible for more information on how this is done.


A future third post on Ansible will describe the modules in place that can be run as part of a playbook, or as ad-hoc based commands.

Write A Comment