Find the right AMI everytime: Make your AWS application work in any region

March 28, 2019 by Sean Cavanaugh

Ansible-Blog-Right-AMI-Everytime

With over 170 Amazon Web Services (AWS) modules, including 60 specifically for Elastic Compute Cloud (EC2), Ansible makes it easy to provision and manage AWS resources. Are you using resources on AWS and looking to diversify across regions to facilitate high availability and disaster recovery? Are you concerned about how Ansible handles differences among EC2 regions? This post will help you build Ansible Playbooks that operate smoothly across regions using the ec2_ami_facts module. In our example, we’ll spin up Red Hat Enterprise Linux instances in AWS.

To spin up an Amazon Machine Image (AMI), you must know the image’s ImageID, a unique identifier for that specific image. AMI ImageIDs use a human-unfriendly hex string to catalog the AMI. For example, ami-c998b6b2. Unfortunately AMI ImageIDs are unique per region, which means the ImageID for Red Hat Enterprise Linux in us-east-1 (Virginia) is not the same as the ImageID for the identical image in us-east-2 (Ohio). Some cloud operators use AWS CloudFormation templates, which include a catalog of AMI ImageIDs for every region, to make their deployment model work across regions. While this can work, it is a bit inflexible, needs constant maintenance of the CloudFormation template, and may work in one region but not in another.

We ran into this challenge when we created our free Red Hat Ansible Automation Workshops. We spin up multiple workshops daily on AWS, in multiple regions around the world. These automation workshops are built for Ansible, by Ansible, with Ansible. We drink our own champagne (or eat our own dog food, if you prefer that metaphor). Everything done with the workshops is written with Ansible Playbooks, and anyone with access to these playbooks can deploy the workshop resources, in any region. All you need is your own AWS account. To achieve this region-agnostic deployment model we use the ec2_ami_facts module to find the correct AMI ImageID every time, in any region. Let’s dive into finding the correct AMI instance.

First, determine the Owner ID for the image you want to use by looking at the AWS console. For example, if I click on the AMI ID link for the RHEL 7.4 image, I see: 

image5

Once you know the AMI’s Owner, you can use the AWS CLI to figure out the correct ImageID with this command:

[sean@ansible ~]$ aws ec2 describe-images --owners 309956199498 --filters 'Name=name,Values=RHEL-7.4*GA*' 'Name=state,Values=available' --output json | jq -r '.Images | sort_by(.CreationDate) | last(.[]).ImageId'

My setup defaults to us-east-1 because I have a default region set in my AWS config file:

[sean@ansible ~]$ cat ~/.aws/config
[default]
region=us-east-1

So when I run the command above, I get the ImageID for the RHEL 7.4 AMI in us-east-1 (Virginia):

ami-c998b6b2

It’s easy to automate this step. Here’s that same query converted to an Ansible Playbook using the ec2_ami_facts module:

    - name: find ami instance-id for RHEL7
      ec2_ami_facts:
        owners: 309956199498
        filters:
          name: "RHEL-7.4*GA*"
      register: AMIs

This task returns a lot of information about the AMI, presented in structured data (JSON). Since the find-instance-id task used the register keyword to save the output, we can now print the output using the debug module:

    - name: print out AMIs to terminal window
      debug:
        var: AMIs

Here’s what the output looks like in a terminal window:

image1

This output may include multiple ImageIDs, and always includes other information about the AMI. To target just the ImageID for the newest image, create a variable to sort the data and retrieve only the newest image. Then use that variable and select the key “image_id”, so the debug message only prints the ImageID value:

    - name:  print out ami instance id
      vars:
        server01_ami: >
          {{ amis.images | selectattr('name', 'defined') | sort(attribute='creation_date') | last }}
      debug:
        msg: "{{server01_ami.image_id}}"

This task returns exactly what we want:image2

Printing the value to the screen with a debug task confirms that the variable is correctly constructed. Now that you have the right variable, you can pass it to the image parameter of an ec2 module task to provision a new instance:

    - name: Create EC2 instances for server01 node
      ec2:
        group: "blog-demo"
        key_name: "sean-key"
        vpc_subnet_id: "{{ec2_vpc_subnet}}"
        instance_type: t2.medium
        image: "{{ server01_ami.image_id }}"
        instance_tags:
            Name: "Server01"

By pairing the dynamic lookup with your instance-creation task, you find and use the correct AMI ImageID every time. This is more effective and maintainable than keeping multiple AMI ImageIDs in a manual list or a CloudFormation template.

Now you can deploy instances and applications in any region - just provide the region in a variable. That’s what we do in the Ansible Automation workshops. The workshop playbooks are easily consumable by Red Hat Ansible Tower - the survey or extra_vars file lets you provision a workshop in any region:

image3

The ec2_region variable specifies where you want to deploy a workbench, which includes a Red Hat Enterprise Linux control node running Ansible Tower.  So we can use Ansible Tower to deploy more Ansible Tower instances in any region!

 

Next Steps

Are you new to Red Hat Ansible Tower?  If you want to learn more Ansible Tower concepts and gets some hands-on keyboard time please check out our free Ansible Workshops. These workshops are intended for people new to Red Hat Ansible Automation and with limited or no prior experience with Ansible and Ansible Tower. Each student will get their own Ansible Tower control node to learn on and be walked through various exercises by their instructor.

Want to try Red Hat Ansible Tower today on your own lab environment?

Want to hang out with us at AnsibleFest 2019? Join us in Atlanta, GA on September 24-26, 2019. 

Share:

Topics:
Cloud


 

Sean Cavanaugh

Sean is a Principal Product Marketing Manager, Ansible, where he brings over 10 years of experience building and automating computer networks. Sean previously worked for both Cumulus Networks and Cisco Systems where he helped customers deploy, manage and automate their network infrastructure. He resides in Chapel Hill, NC with his wife and children and tweets from @IPvSean.


rss-icon  RSS Feed

Ansible Tower by Red Hat
Learn About Ansible Tower