Ansible is a great tool for automating infrastructure provisioning. It is agentless, which means that you don’t need to install anything on the target machine. It is also very easy to use and has a lot of modules that you can use to automate your infrastructure.

Ansible inventory is a file that contains a list of hosts that Ansible can connect to. It is used to define the hosts that Ansible will connect to and the run the tasks on. This file can be either static i.e. you define the hosts manually or dynamic i.e. you define the hosts using a script. Given below is an example of a static inventory file.

          
              [web] 
16.202.152.100
14.201.142.105
[db]
15.212.122.120

As you can see, we have two groups `[web]` and `[db]` with each group having some IP addresses. The problem with this approach is that if you have a lot of hosts, then it becomes very difficult to manage the inventory file. Also, if you have a dynamic infrastructure where hosts are added and removed frequently, then it becomes even more difficult to manage the inventory file.

In this article, we will learn how to dynamically populate the Ansible inventory with the IP address of EC2 instances.

Tagging EC2 instances

The first step to make it easier to manage the inventory file is to tag the EC2 instances properly. I normally tag the EC2 instances with the following tags at the very least:

          
              Project  =  "web-address.com" 
Component = "{COMPONENT}"
Role = "{Role}"
Name = "{COMPONENT}-{ROLE}-{ENVIRONMENT}"
Environment = "{ENVIRONMENT}"
ManagedBy = "{MANAGED_BY}"

Details of what each tag means:

Having these tags not only makes it easier to manage the inventory file but also makes it easier to manage the EC2 instances themselves e.g. you can easily find all the resources with specific tags, better analyse the cost of the infrastructure, etc.

Dynamic Inventory

There is an Ansible module called `aws_ec2` that can be used to dynamically populate the inventory file with the IP address of EC2 instances. It can get the IP address of EC2 instances based on the tags that we have defined above and give us hostnames that we can use in our playbooks. It has a pretty decent documentation that you can refer to to get an idea of usage but I will go through the usage here:

First, we need to create a yaml file that will contain the configuration for the `aws_ec2` module. The filename must end with `aws_ec2.yml`, e.g. ``csfyi.aws_ec2.yml. The contents of the file should be as follows:

          
            plugin: aws_ec2 
boto_profile: "{{ lookup('env', 'AWS_PROFILE') }}"
regions:
- ap-south-1
filters:
instance-state-name: running
keyed_groups:
- key: tags.get('Component', 'unknown') + "_" + tags.get('Role', 'unknown') + "_" + tags.get('Environment', 'unknown')
separator: ''
- key: tags.get('Component', 'unknown') + "_" + tags.get('Role', 'unknown')
separator: ''

Let's go through the configuration one by one:

Once we have created the configuration file, we can use the `aws_ec2` module to get the list of EC2 instances. We can do this by running the following command:

          
            # Use --list or --graph to get the list of EC2 instances 
ansible-inventory -i csfyi.aws_ec2.yml --list
ansible-inventory -i csfyi.aws_ec2.yml --graph
# Add AWS_PROFILE if you are using multiple profiles in your machine
AWS_PROFILE=csfyi ansible-inventory -i csfyi.aws_ec2.yml --list
# You can also use the following command to get the list of EC2 instances in a specific group
ansible-inventory -i csfyi.aws_ec2.yml --host ap p_api_production

If all goes well, you should see the list of EC2 instances in the output. Now that we have the inventory file ready, we can use it in the `ansible.cfg` file. You should add the following lines to the `ansible.cfg` file:

          
            [defaults]
            # ...
            enable_plugins = aws_ec2
            inventory = ./roadmap.aws_ec2.yml
            # ...
          
      

Now, you can use the host names in your playbooks. For example, if you want to run a playbook on all the EC2 instances in the `app_api_production` group, then you can do the following:

          
            - name: Configure draw.roadmap.sh
            hosts: app_api_production  # Name generated by the aws_ec2 plugin
            become: yes
            become_method: sudo
            gather_facts: no
            roles:
              - { role: base, tags: [ 'base' ] }
              - { role: nginx, tags: [ 'nginx' ] }
          
      

Conclusion

In this article, we learned how to dynamically populate the Ansible inventory with the IP address of EC2 instances. This makes it easier to manage the inventory file and also makes it easier to manage the EC2 instances themselves. I hope you found this article useful.