When we use ansible we often need to manage remote hosts, those hosts can be bare-metals, VMs, instances running on different clouds and so on. Before we start writing playbooks and tasks (will be covered later) we need to understand what infrastructure we have and how should we manage it, this will have an affect on how our playbooks will be structured. In this part we will talk about the ansible inventory, which is a file that lists the hosts we manage with the ansible playbook, learn how to define host specific variables and cover some configurations that are relevant to the way we talk to our hosts.
The ansible inventory is mostly a list of hosts that we want to manage with ansible. It allows us to easily group a number of hosts under the same name, and define variables for each host/group.
In ansible there are 2 types of inventories:
The simplest inventory is just a file listing the hosts. For example this is a simple inventory that lists 5 hosts with their FQDN:
host1.example.gzaidman.com # dev host
host2.example.gzaidman.com # test
host3.example.gzaidman.com # test
host4.example.gzaidman.com # prod
host5.example.gzaidman.com # prod
** We could also use plain IP addresses, but as a best practice it is recommended to use FQDN or or IP addresses with aliases.
The above could be shortened with ranges:
host1.example.gzaidman.com # dev host
host[2:3].example.gzaidman.com # test
host[4:5].example.gzaidman.com # prod
When we run an ansible playbook with the above inventory, ansible will try to perform each task in the playbook on all the hosts in the inventory.
Having a simple inventory with 5 hosts is not elegant but is manageable, but what if we have 50? 100? 1000?? as our infrastructure grows bigger and the system becomes more complex it is clear that we need a better way to organize our hosts, that’s where inventory groups come into play.
Ansible inventory groups are used to assign a label to a collection of hosts. For example, we can use groups in the above example:
[dev]
host1.example.gzaidman.com
[test]
host[2:3].example.gzaidman.com
[prod]
host[4:5].example.gzaidman.com
a single host can be members of multiple groups and a group can contain child groups with the :children syntax. Let’s say we want to also group the hosts by their location:
[dev]
host1.example.gzaidman.com
[test]
host[2:3].example.gzaidman.com
[prod]
host[4:5].example.gzaidman.com
[england]
host1.example.gzaidman.com
host3.example.gzaidman.com
[finland]
host2.example.gzaidman.com
host4.example.gzaidman.com
[us]
host5.example.gzaidman.com
[europe:children]
england
finland
In ansible there are two default groups that are always created:
To verify that the inventory is ok, we can use:
# ansible HOST/GROUP --list-hosts
ansible canada --list-hosts
Very often we will want to define variables that are specific to a host or a group of hosts.
We can add the variables directly on each host
[test]
host1.example.gzaidman.com listen_port=4321
host2.example.gzaidman.com listen_port=8642
We can also add variables for a group:
[test:vars]
ntp_server=ntp.canada.example.com
ntp_port=4567
proxy=proxy.canada.example.com
Those variables are called host and group variables and they will be available in the playbook on the host. Host and group variables are very common but defining them directly on the inventory file can make it very verbose and hard to read especially when we have a large inventory file. Ansible lets us organize host and group variables on separate files which will make our inventory cleaner and our project more maintainable. We need to create host_vars and group_vars directories, those directories can contain a file with the name of the host/group where we will define all the variables. For example we can take the inventory above, and create:
[gzaidman:example] tree
.
├── group_vars
│ └── test
├── host_vars
│ ├── host1.example.gzaidman.com
│ └── host2.example.gzaidman.com
└── inventory
The variable files should be in yaml syntax only which is a bit different from the above.
[gzaidman:example] cat test
ntp_server: ntp.canada.example.com
ntp_port: 4567
proxy: proxy.canada.example.com
[gzaidman:example] cat host1.example.gzaidman.com
listen_port: 4321
[gzaidman:example] cat host2.example.gzaidman.com
listen_port: 8642
You can also create directories named after your groups or hosts and place variable files in them. Ansible will read all the files in these directories in lexicographical order. An example with the ‘test’ group:
./example/group_vars/test/ntp_settings ./example/group_vars/test/proxy_settings
This can be very useful to keep your variables organized when a single file gets too big, or when you want to use Ansible Vault (covered later) on some group variables.
The inventory can be in the following locations (ordered by precedence):
There are a lot of flags we can set to control the way ansible connects to our hosts. We define does as inventory variables for a specific host/group. For the full list of configurations visit the Docs.
Some of the most common ones are:
To see examples on different inventories go to the docs on:
https://docs.ansible.com/ansible/latest/user_guide/intro_inventory.html#inventory-setup-examples
When working with numerous machines or in an environment where machines come and go very quickly, it can be hard to keep the static inventory files up-to-date. Ansible supports dynamic inventory scripts that retrieve current information from external sources, allowing the inventory to be created in real time based on the current env. These scripts collect information from an external source and create JSON format inventory files.
If the inventory file is executable, then it is treated as a dynamic inventory program and Ansible attempts to run it to generate the inventory. If the file is not executable, then it is treated as a static inventory.
If a dynamic inventory script does not exist for the infrastructure in use, you can write a custom dynamic inventory program. This is a link to the ansible doc for writing a dynamic inventory link. A few things we should keep in mind:
On each ansible project it is recommended to create a configuration file to override the default configurations based on the project requirements. Ansible configuration file is located at /etc/ansible/ansible.cfg, to override some settings we need to create a project configuration file at the project root directory with the same name ansible.cfg. The stock configuration should be sufficient for most project, and you can examine the /etc/ansible/ansible.cfg file to see the default configuration you can override.
The Ansible configuration file consists of several sections, each section is enclosed with ‘[SECTION_NAME]’.
We will talk about two sections that relate to the way ansible connects to hosts.
Some configurations which relate to host management (they can als be overridden at the playbook level):
[defaults]
This is the first section in the file and it sets defaults for Ansible operation.
[privilege_escalation]
Configures how Ansible performs privilege escalation on managed hosts
We can see all the configuration options with the ansible-config list command.
** It’s important to understand that the above options on the default section refer to the initial connections meaning how to connect to the host and the options on the privilege_escalation refer to what to do once you are connected.
The recommended practice is to create an ansible.cfg file in a directory from which you run Ansible commands (meaning option 2). We cab check which configuration file is being used with ansible –version.