All Linux HowTo's

Build an EC2 using Ansible Step By Step

This article explains step by step how to create (spin up) an EC2 instance within AWS using Ansible and a few extras. Unlike 100% of other articles out there, this one actually demonstrates how to do it. Pay attention to the date of this article because things DO change over time.

We’re using CentOS 7 as the Ansible host.

Run the following commands to install the required dependencies for Ansible and AWS. I’m running this as a normal user with SUDO access, not the root user.

sudo pip install --upgrade pip
sudo pip install boto
sudo yum install ansible

Log into your AWS account to get your “AWS_ACCESS_KEY_ID” and “AWS_SECRET_ACCESS_KEY”. Go to “Identity and Access Management”. Create a new user or select an exiting one. Go to “Security Credentials” and click “Create Access Key”. Here’s an example of what you’ll end up with:

Access Key ID: NUHKOIJFOJF9GFJDO
Secret Access Key: LSDJKFODSJF9SDJF8UH3U3HFKW

Keep those safe – download when asked. Use the above values to create environment variables. Copy and paste the following (with your values replacing mine) into your shell:

export AWS_ACCESS_KEY_ID="NUHKOIJFOJF9GFJDO" 
export AWS_SECRET_ACCESS_KEY="LSDJKFODSJF9SDJF8UH3U3HFKW"

Create the “~/hosts” file with the following contents:

[local]
localhost

[webserver]

Now we build our YML file for Ansible to run through. Here’s a sample that will create a basic EC2 with a public IP address and your public SSH key. Put the following into the file “~/ec2-basic.yml”

---
  - name: Provision an EC2 Instance
    hosts: local
    connection: local
    gather_facts: False
    tags: provisioning
    # Necessary Variables for creating/provisioning the EC2 Instance
    vars:
      instance_type: t2.micro
      security_group: ansible-webserver # Change the security group name here
      image: ami-719fb712 # This is an AMI i created myself
      keypair: agix-key # This is one of my keys that i already have in AWS
      region: ap-southeast-2 # Change the Region
      count: 1

    # Task that will be used to Launch/Create an EC2 Instance
    tasks:

      - name: Create a security group
        local_action: 
          module: ec2_group
          name: "{{ security_group }}"
          description: Security Group for webserver Servers
          region: "{{ region }}"
          rules:
            - proto: tcp
              from_port: 22
              to_port: 22
              cidr_ip: 0.0.0.0/0
            - proto: tcp
              from_port: 80
              to_port: 80
              cidr_ip: 0.0.0.0/0
            - proto: tcp
              from_port: 443
              to_port: 443
              cidr_ip: 0.0.0.0/0
          rules_egress:
            - proto: all
              cidr_ip: 0.0.0.0/0
        register: basic_firewall

      - name: Launch the new EC2 Instance
        local_action: ec2 
                      group={{ security_group }} 
                      instance_type={{ instance_type}} 
                      image={{ image }} 
                      wait=true 
                      region={{ region }} 
                      keypair={{ keypair }}
                      count={{count}}
        register: ec2

      - name: Add the newly created EC2 instance(s) to the local host group (located inside the directory)
        local_action: lineinfile 
                      dest="./hosts" 
                      regexp={{ item.public_ip }} 
                      insertafter="[webserver]" line={{ item.public_ip }}
        with_items: ec2.instances


      - name: Wait for SSH to come up
        local_action: wait_for 
                      host={{ item.public_ip }} 
                      port=22 
                      state=started
        with_items: ec2.instances

      - name: Add tag to Instance(s)
        local_action: ec2_tag resource={{ item.id }} region={{ region }} state=present
        with_items: ec2.instances
        args:
          tags:
            Name: webserver

Being the provisioning (spin it up):

ansible-playbook -i ./hosts ec2-basic.yml

And finally log into your new ec2 instance:

ssh -l centos 54.1.2.3 -i Downloads/agix-key.pem

Resources:

https://pypi.python.org/pypi/boto#downloads
http://www.tivix.com/blog/using-ansible-create-aws-instances/
http://stackoverflow.com/questions/30227140/best-way-to-launch-aws-ec2-instances-with-ansible

Similar Posts:

8 comments

  1. Hi,
    I have facing issue while following you.
    fatal: [localhost -> localhost]: FAILED! => {“changed”: false, “msg”: “boto required for this module”}

    pip freeze |grep boto
    boto==2.48.0
    boto3==1.5.14
    botocore==1.8.28
    (ansble) ansible@sharma:~/aws$ pip show boto3
    Name: boto3
    Version: 1.5.14
    Summary: The AWS SDK for Python
    Home-page: https://github.com/boto/boto3
    Author: Amazon Web Services
    Author-email: UNKNOWN
    License: Apache License 2.0
    Location: /home/ansible/ansble/lib/python2.7/site-packages
    Requires: jmespath, s3transfer, botocore
    (ansble) ansible@sharma:~/aws$ pip show boto
    Name: boto
    Version: 2.48.0
    Summary: Amazon Web Services Library
    Home-page: https://github.com/boto/boto/
    Author: Mitch Garnaat
    Author-email: mitch@garnaat.com
    License: MIT
    Location: /home/ansible/ansble/lib/python2.7/site-packages
    Requires:

    I don’t know what is the issue.

  2. Instance creation is done but after that it throws below error . Can you have a look and let me know the resolution.

    task path: /etc/ansible/ec2-basic.yaml:54
    fatal: [localhost]: FAILED! => {“msg”: “The task includes an option with an undefined variable. The error was: ‘ansible.utils.unsafe_proxy.AnsibleUnsafeText object’ has no attribute ‘public_ip’\n\nThe error appears to have been in ‘/etc/ansible/ec2-basic.yaml’: line 54, column 9, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n – name: Add the newly created EC2 instance(s) to the local host group (located inside the directory)\n ^ here\n\nexception type: \nexception: ‘ansible.utils.unsafe_proxy.AnsibleUnsafeText object’ has no attribute ‘public_ip'”}

  3. Got the issue …. Now it’s working fine.

    with_items: ec2.instances
    It should be:

    with_items: ‘{{ ec2.instances }}’

  4. Hi

    I am getting following message and EC2 is not getting launched.

    root@ip-172-31-39-198:/home/ubuntu# vim ~/hosts
    root@ip-172-31-39-198:/home/ubuntu# ansible-playbook -i ./hosts ec2-basic.yml
    [WARNING]: provided hosts list is empty, only localhost is available

    PLAY [Provision an EC2 Instance] ***********************************************
    skipping: no hosts matched

    PLAY RECAP *********************************************************************

    root@ip-172-31-39-198:/home/ubuntu#

    I changed region, key details before running yml script

    [local]
    54.173.108.250

    [webserver]

    ~ ~ ~ ~ ~ ~ ~ ~ “~/hosts” 5L, 37C

    Can you please help

    1. Hi,

      It was my mistake . I had not changed your default parameters.

      It worked now. Thanks for the exact example and steps in detail

      Best regards

      1. Please kindly elaborate on the solution here as I get the same issue (named my file aws.yml).
        [root@localhost home]# ansible-playbook -i ./hosts aws.yml
        [WARNING]: Unable to parse /home/hosts as an inventory source

        [WARNING]: No inventory was parsed, only implicit localhost is available

        [WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match ‘all’

        [WARNING]: Could not match supplied host pattern, ignoring: local

        PLAY [Provision an EC2 Instance] *******************************************************************************************************
        skipping: no hosts matched

        PLAY RECAP *******************************************************************************************************

  5. Hi Marudi,

    Make sure the “hosts” file exists in that location. It looks like you’re in “/home” (although that’s not clear) but you probably should be in “/home/myuser”.

    To check, try something like this:
    ansible-playbook -i ~/hosts aws.yml

    Notice the “~” indicating your home directory. It’s a guess but i think it’s what you want.

    Thanks.
    Andrew Galdes

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.