A Comprehensive Guide to Scaling Ansible on AWS using Dynamic Inventory

A Comprehensive Guide to Scaling Ansible on AWS using Dynamic Inventory

This tutorial provides an example of a static Ansible inventory and explains how to convert it into a dynamic one. It also provides instructions on how to prepare the equipment and materials, export the logistics, and troubleshoot any issues that may arise. Solutions to troubleshoot issues encountered during the first-time implementation of a dynamic inventory are also provided.

Ansible is one of the most well-known tools for infrastructure engineers to manage and maintain infrastructure, particularly for IT automation. It became my go-to resource when I was a novice System Engineer six years ago, and it remains relevant to this day.

The first time I worked with Ansible was to maintain a small cluster of Hadoop servers. For 1-10 servers, I was able to manage them using the static inventory below:

#sample-for-demo-purpose

[web]
192.168.1.1
192.168.1.2

[api]
192.168.2.1
192.168.2.2

[payment]
192.168.3.1
192.168.3.1

The text above provides an example of a static Ansible inventory, which defines hosts in a .ini-like file format. However, managing 100, 1,000, or even 1 million instances can be challenging. That's why it's necessary to convert your static inventory into a dynamic one. The process is relatively straightforward to implement.

Requirements

To complete this tutorial, you need to meet the following requirements:

  • AWS IAM Access with minimal access to your instance list and details

  • EC2 Instances running on top of AWS

  • Python virtualenv installed on your device

  • Internet connection (it's impossible to function in today's world without the Internet)

Prepare the Equipment and Materials

You can't begin the battle without a fully loaded gun, so let's prepare the arsenal first. Create a script to generate your inventory from AWS.

  • ec2.py EC2 external inventory script

  • ec2.ini Ansible EC2 external inventory script settings

    Above scripts were created by the Ansible community. For a faster process, simply clone this repository from my GitHub account:

    https://github.com/muhx/devops-starter

Export the logistics

To ensure the code above functions as intended, we need to export some environment variables. This won't impact any existing environments, so feel free to proceed with confidence.

~ export AWS_ACCESS_KEY_ID=<your_aws_access_key_id>
~ export AWS_SECRET_ACCESS_KEY=<your_aws_secret_access_key>

Next, you need to install certain pip packages to run Ansible and its scripts. I recommend using virtualenv to maintain a clean environment.

~ virtualenv venv
~ source venv/bin/activate
~ cd to/my/cloned/github/repository
~ pip install -r ansible/requirements.txt

Next, you must set the ANSIBLE_INVENTORY and EC2_INI_PATH environment variables to associate them with Ansible.

~ export EC2_INI_PATH=/path/to/my/cloned/github/repository/ansible/inventory/ec2.ini
~ export ANSIBLE_INVENTORY=/path/to/my/cloned/github/repository/ansible/inventory/ec2.py

First, run the script to ensure it is already executable by applying the chmod +x command to the ec2.py file. Then, execute the following command:

~ ./path/to/my/cloned/github/repository/ansible/inventory/ec2.py

When everything is working as we planned before, the output should look like this:

...
"tag_Name_my_instance_1": [
    "192.168.155.53"
  ],
  "tag_Name_my_instance_2": [
    "192.168.235.48"
  ],
  "tag_Name_my_instance_3": [
    "192.168.12.223"
  ],
  "tag_Name_my_instance_4": [
    "192.168.14.83"
  ],
  "tag_Name_my_instance_5": [
    "192.168.106.144"
  ],
  "tag_Name_my_instance_6": [
    "192.168.210.60"
  ],
...

This means that your code is working. Now, test your dynamic inventory with Ansible by running the command above.

~ ansible -m ping tag_Name_my_instance_1 -u your_ssh_user

Additionally, the anticipated output should be:

192.168.155.53 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

Your first dynamic inventory is now ready for implementation, allowing you more time to rest.

Troubleshooting

The first-time implementation of this dynamic inventory led me to encounter some issues. The solutions are provided below:

Python can’t read the configurations

[WARNING]:  * Failed to parse /.../.../.../.../ansible/inventory/ec2.py with script plugin: Inventory script (/.../.../.../.../ansible/inventory/ec2.py) had an execution
error: Traceback (most recent call last):   File "/.../.../.../.../ansible/inventory/ec2.py", line 155, in <module>     import boto ImportError: No module named boto[WARNING]:  * Failed to parse /.../.../.../.../ansible/inventory/ec2.py with ini plugin: /.../.../.../.../ansible/inventory/ec2.py:3: Error parsing host definition ''''': No
closing quotation[WARNING]: Unable to parse /.../.../.../.../ansible/inventory/ec2.py as an inventory source[WARNING]: No inventory was parsed, only implicit localhost is available[WARNING]: Could not match supplied host pattern, ignoring: all[WARNING]: provided hosts list is empty, only localhost is available[WARNING]: Could not match supplied host pattern, ignoring: tag_Name_my_instance_1[WARNING]: No hosts matched, nothing to do

This means that your Python interpreter is reading from the system. Set the PYTHONPATH to point to your virtual environment's packages.

~ export PYTHONPATH=/.../.../.../venv/lib/python2.7/site-packages

Script can’t read ElasticCache clusters

When you run the ec2.py script for the first time, some users encounter a problem like:

ERROR: "Forbidden", while: getting ElastiCache clusters

To eliminate this problem, uncomment the following line inside the ec2.ini file.:

#elasticache = False