
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
- 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
- You should have python and pip installed on your system
- You should have boto installed on your system. (pip install boto) boto is the aws client for python which would be used by Ansible.
- 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.