Using DNS as an Ansible dynamic inventory
If you’re using Ansbile as your System Configuration tool (and you should, cause it’s awesome) you will inevitably reach the point where you have to define your inventory.
Introduction to the Inventory
The inventory (or “hosts” file) is list of host names that you want to manage using Ansible. The hosts can be grouped in INI-style sections. The default location is /etc/ansible/hosts.
It’s a plain text file which means you can use your favorite text editor to update it from time to time. If you have a project in which you keep your Ansible plays you can also add your hosts file in your project and refer to it when calling Ansible in your terminal. You might even put this in source control if you’re in a sharing mood.
This works very well if your a small team with a small fixed set of hosts to manage. However, if you want to scale, for instance by using Virtual Machines you might not want to manually keep track of your dynamic hosts.
Using a Dynamic Inventory
To solve this issue, Ansible has the ability to include a Dynamic Inventory. A dynamic inventory is a script that is called by Ansible which returns a JSON array of hosts. The Ansible documentation includes some examples for AWS EC2 and OpenStack, but if you’re not using the world’s most popular cloud service, you may need to get your hands dirty.
Jan-Piet Mens wrote a great article on how you can create a dynamic inventory with a database and provided some examples on how the JSON response looks like.
You could use this example to create a website or small application in which you can manage your dynamic servers. However, it does require you to host/maintain an additional tool only to manage your inventory.
For those who, like me, want to keep it simple I’d like to offer an alternative approach by leveraging the existing, mature and proven system for managing host names: DNS.
Using a Dynamic Inventory with TXT records
You are probably familiar with DNS as the service that translates your common domain name (like www.google.com) to the more obscure IP address that computers use to communicate.
Although this is very useful, DNS can actually do much more. It has a long list of features including the ability to add TXT records to your domain name in which you can store meta-data that can be used in machine interaction. One of the more common uses of the TXT record is Sender Policy Framework (SPF), an anti-spam measure.
As most providers will allow you to programmatically update your DNS records using an API, the TXT records are also viable for creating a dynamic Ansible inventory with additional meta-data (like sections or host variables).
Using multiple TXT records
The beauty of using DNS is that it allows multiple TXT records for the same (sub)domain. So you can add an unlimited number of hosts in your DNS system with their Ansible meta-data and store them in a single DNS domain for quick reference.
DNS record caching
It keeps getting better if you take into account that DNS already has a global network which is geared towards performance. DNS is a distributed system in which each node retrieves and caches the requested output. This will allow you to maintain your dynamic inventory on a global scale without creating to much burden on your DNS server.
Using DNS Dynamic Inventory with Ansible
Now that we have established that DNS is a great system for maintaining your dynamic host information, let’s see how we can turn it into a dynamic inventory for Ansible.
If you use the “ — inventory” switch when calling Ansible, you can provide the path to a directory which includes inventory files. Ansible will automtically run any executable script in that directory to see if provides the JSON output describing a dynamic inventory.
Using the following NodeJS script, you can read the information from your TXT record and provide the JSON output that Ansible requires:
This script will query the DNS server for the value of the TXT record associated with “host._ansible.yourdomain.com”.
It expects to retrieve a string-based value of:
“hostname=web-host-01.yourdomain.com;sections=webserver,boston”
The second TXT record might be:
“hostname=db-host-01.yourdomain.com;sections=database,atlanta”
The script will parse these TXT records and output the following JSON:
{ “webserver”: { “hosts”: [ “web-host-01.yourdomain.com” ] }, “boston”: { “hosts”: [ “web-host-01.yourdomain.com” ] }, “database”: { “hosts”: [ “db-host-01.yourdomain.com” ] }, “atlanta”: { “hosts”: [ “db-host-01.yourdomain.com” ] }
Now you only need to create a script that updates your DNS when provisiong or decommissioning a server, by either adding or removing the TXT record for that specific host.
I hope this has given you new insights on how to manage your dynamic IT infrastructure using Ansible. Please share your thoughts in the comments!