28

I'm trying to create an small webapp infrastructure with ansible on Amazon AWS and I want to do all the process: launch instance, configure services, etc. but I can't find a proper tool or module to deal with that from ansible. Mainly EC2 Launch.

Thanks a lot.

Thomas Dickey
  • 51,086
  • 7
  • 70
  • 105
JorelC
  • 788
  • 1
  • 9
  • 17

3 Answers3

40

This is the short answer of your question, if you want detail and fully automated role, please let me know. Thanks

Prerequisite:

  • Ansible

  • Python boto library

  • Set up the AWS access and secret keys in the environment settings
    (best is inside the ~./boto)

To Create the EC2 Instance(s):

In order to create the EC2 Instance, please modified these parameters that you can find inside the "ec2_launch.yml" file under "vars":

  • region # where is want to launch the instance(s), USA, Australia, Ireland etc
  • count # Number of instance(s), you want to create

    Once, you have mentioned these parameter, please run the following command:

ansible-playbook -i hosts ec2_launch.yml

Contents of hosts file:

[local]
localhost

[webserver]

Contents of ec2_launch.yml file:

---
  - 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: t1.micro
      security_group: webserver # Change the security group name here
      image: ami-98aa1cf0 # Change the AMI, from which you want to launch the server
      region: us-east-1 # Change the Region
      keypair: ansible # Change the keypair name
      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
              type: ssh
              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
          rules_egress:
            - proto: all
              type: all
              cidr_ip: 0.0.0.0/0


      - 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
Arbab Nazar
  • 22,378
  • 10
  • 76
  • 82
  • 2
    should be with_items: "{{ ec2.instances }}" etc. at least for the current version – Christian Smorra Dec 07 '16 at 17:39
  • 2
    When should I use `local_action` and when should I not? I've seen code snippets like the above (eg `local_action: ec2 ...`) and I've seen code snippets that just do `ec2: ...` directly, but I can't find any information about when one might prefer one over the other. The ansible docs intro on AWS does not use it, for example: https://docs.ansible.com/ansible/guide_aws.html –  Dec 22 '16 at 11:52
  • In the task "Wait for SSH to come up", I am experiencing a timeout error. I have the same task as above, where the action is to wait for the item.public_ip. When I check the instance, public_ip is populated. Any suggestions for what the issue could be? – fuzzi Aug 24 '17 at 07:30
13

As others have said, the cloud module contains just about all the AWS provisioning support you'd need. That said, Ansible's paradigm makes most sense once there's an existing SSH:able machine to target and connect to. The instantiation phase, by comparison, essentially asks you to target your local machine and calls AWS API endpoints from there.

Like you, I wanted a single-shot command with a graceful transition from EC2 instantiation into its configuration. There's suggestions on how to accomplish something like this in the documentation, but it relies on the the add_host module to tweak Ansible's idea of current host inventory, and even then I couldn't find a solution that didn't feel like i was working against rather than with the system.

In the end I opted for two distinct playbooks: a provision.yml that uses the ec2, ec2_group, ec2_vol, ec2_eip and route53 modules to ensure I have the "hardware" in place, and then configure.yml, more like a traditional Ansible site.yml, which is able to treat host inventory (static in my case, but dynamic will work well) as a given and do all that good declarative state transitioning.

Both playbooks are idempotent, but it's configure.yml that's meant to be rerun over and over in the long run.

Pär Winzell
  • 191
  • 1
  • 5
  • Couldn't agree more. The main problem I'm running into is that it does not seem possible to keep Ansible `ec2 ` task parameters for separate EC2 instances in separate `group_vars` or `host_vars` files - because there is no host to talk to yet as the `ec2 ` task is running against `localhost`. How did you solve that in your `provision.yml` playbook ? – ssc Jan 07 '18 at 15:46
3

The EC2 module was designed precisely for creating and destroying instances.

If you want the "best" way, it's hard to beat CloudFormation, which can be launched from Ansible.

tedder42
  • 23,519
  • 13
  • 86
  • 102