In this article we will explore how to create an ec2 instance using Ansible.

Why Ansible

If you have any application running in cloud, there is a pretty good chance that you would have created an ec2 instance, and if you have never heard about Ansible, then you are probably still relying on manual creation of each instance, then installing every required software with appropriate versions and patches and then installing your application on top of it. Sounds like quite some work, right? So how about automating it, sure you can write a shell script to call appropriate commands and keep it, but would it not be awesome to have a consistent way to deal with all such creation and maintenance, something better than every super admin rolling out their own scripts.

This is where Ansible and other IAC (Infrastructure As Code) tools come in, sure Ansible is not the only one in the market, but Ansible is possibly most popular and for sure easiest to learn.

Ansible is written over python and relies on SSH as opposed to having a client installed on other system. So if I spin off an ec2 instance with an ami which has ssh and python installed on it, I am ready to roll. Since ssh and python are mostly preinstalled in almost all linux distro, it makes it easiest to get started.

Prerequisites

  1. You should have an aws account with access key and secret key, if you dont have keys, check AWS doc on how to get access keys
  2. You should have python and pip installed on your system
  3. You should have boto installed on your system. (pip install boto) boto is the aws client for python which would be used by Ansible.
  4. Ofcourse, you would need to install Ansible, you can run pip install ansible

Ansible hello world

- hosts: localhost
  vars:
    # choose the ami based on the region, same os have different ami versions in different regions
      region: ap-south-1
      ami: ami-02b5fbc2cb28b77b8
      instance_type: t2.nano
      
  tasks:
    - include_vars: myvar.yml
      ec2:
        # If you do not have a key, check https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-key-pairs.html#prepare-key-pair
        key_name: mySecretKey 
        instance_type: "{{instance_type}}"
        image: "{{ami}}"
        wait: yes
        region: "{{region}}"
        group: Ansible
        assign_public_ip: yes
        aws_access_key: "{{aws_access_key}}"
        aws_secret_key: "{{aws_secret_key}}"  
        vpc_subnet_id: vpc-12337447
        
        

This is a Ansible script which would create a new ec2 instance when you run

sh ansible-playbook ec2.yml

Variables in Ansible

Lets look at some of the portions of this script, first we have externalised the region, ami and type into variables. This would allow us to change the variables without changing the script. There is another way variables have been declared in this script, which is by include_vars, which allows us to externalise some of the variables in a separate file, in this case we have aws_access_key and aws_secret_key stored in a variable file called myvar.yml.

Generalising the script

If we look closely you can spot two highlighted variables in the script, group and vpc_subnet_id, these two variable are required by aws to create an instance, this script relies on the fact that there is a vpc with id vpc-12337447 in your aws region and a security group with name Ansible. While this works, it defeats the purpose of writing the script in first place, the script will only work for you under a very specific environment, i.e. the vpc in dev, test, uat and prod would change, so you would need to create separate scripts of put it in variable. Doesn’t look a lot better than a shell script right?

There are two ways we can generalise this script, one of the method is to create a new vpc and new security group and get their values and pass it to ec2 script, other would be to use one of the existing vpc or security group. Lets look at both the ways.

We will reuse the VPC and create a new security group for our server. Lets modify the Ansible script.

 - name: Create security group
      ec2_group:
        name: web_security_group
        description: security group for web
        aws_access_key: "{{aws_access_key}}"
        aws_secret_key: "{{aws_secret_key}}"  
        region: "{{region}}"
        state: present
        rules:
          - proto: tcp
            from_port: 22
            to_port: 22
            # This is not secure and allows SSH from anywhere, including aliens and monsters..Replace cidr_ip with your machines ip
            cidr_ip: 0.0.0.0/0

        # Outbound rules, we will only allow consumers to connect to kafka on its known port
        rules_egress:
          - proto: tcp
            from_port: 80
            to_port: 80
            cidr_ip: 0.0.0.0/0
      register: ec2_web_sg  

This script creates a new security group called web_security_group and sets the rules for inbound and outbound traffic and then stores the security group in a ansible variable called ec2_web_sg which we can use in our create ec2 call. One thing to remember is that Ansible supports Idempotency, which is just a fancy way of saying that if you run this script multiple times, it would still create the security group only once. In case the security group is existing then the existing one would be assigned to the ec2_web_sg variable.

Lets look at how to reuse existing VPC.

# Using the existing VPC
    - name: existing vpc
      ec2_vpc_subnet_info: 
        aws_access_key: "{{aws_access_key}}"
        aws_secret_key: "{{aws_secret_key}}"  
        region: "{{region}}"
      register: ec2_vpc  

This script get the information about existing vpc and assigns it to a variable called ec2_vpc. If for whatever reason you want to use existing security group, you can use

- name: existing security group
      ec2_group_info:
        filters:
        group-name: web_security_group
        aws_access_key: "{{aws_access_key}}"
        aws_secret_key: "{{aws_secret_key}}"  
      register: ec2_web_sg  

Now lets change our create ec2 script to use the above variables.

  - name: create ec2 instance
      ec2:
        # If you do not have a key, check https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-key-pairs.html#prepare-key-pair
        key_name: mySecretKey 
        instance_type: "{{instance_type}}"
        image: "{{ami}}"
        wait: yes
        region: "{{region}}"
        group_id :
          - "{{ec2_web_sg.group_id}}"          
        assign_public_ip: yes
        aws_access_key: "{{aws_access_key}}"
        aws_secret_key: "{{aws_secret_key}}"  
        vpc_subnet_id: "{{ec2_vpc.subnets.0.subnet_id}}"

We can optimise this script lot better with using more features from Ansible, this article is intended for readers to get their first taste of Ansible. Hope it helps, please let me know in comments if you like it or hate it.


Author

Nitiz

There are currently no comments.

Bitnami