Comparing CloudFormation, Terraform and Ansible - Simple example

Whenever someone asks me what tools do you use to provision your infrastructure within AWS - the answer is it can be done with a variety of tools - but people usually use one of the following three

The next question that comes up of course - is which one is easier/better to use? The answer of course (as always..) is - “It Depends”. There are really good reasons to use each and everyone of the tools. This could be ease of use, support, extensibility, flexibility, community support (or lack thereof).

I have worked with all three tools, and each of them have their ups and their downs. There are periods that I prefer Ansible, other days that Terraform and sometimes CloudFormation is the only way to get things done.

I wanted to compare all three in a set of scenarios - from the really simple to moderate - to complicated. Firstly - to see how this can be accomplished in each of the tools,evaluating complexity, time to completion and anything else that came up along the way.

Let’s start by diving straight into the first example.

I want to create a VPC. A plain simple VPC, nothing else. No Network, no NAT gateways, routes, subnets, as simple as can be. Essentially this is a simple AWS API call  which would be:

aws ec2 create-vpc --cidr-block 192.168.90.0/24

(The code for all of these scenarios is located here - https://github.com/maishsk/automation-standoff/tree/master/simple)

First lets have a look at CloudFormation

Description:
  This template deploys a VPC.

Parameters:
  EnvironmentName:
    Description: An environment name that will be prefixed to resource names
    Type: String
    Default: "testvpc"

  VpcCIDR:
    Description: Please enter the IP range (CIDR notation) for this VPC
    Type: String
    Default: 192.168.90.0/24

Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VpcCIDR
      EnableDnsSupport: true
      Tags:
        - Key: Name
          Value: "testvpc"

Outputs:
  VPC:
    Description: A reference to the created VPC
    Value: !Ref VPC

Looks pretty simple. I used the native resources in CloudFormation, and set defaults for the name and the CIDR block.

Lets look at Ansible. There is a built-in module for this ec2_vpc_net.

- name: VPC creation playbook
  hosts: localhost
  connection: local
  gather_facts: no

  vars_files:
    - vars/vpc_vars.yml

  tasks:
  - name: Create a VPC
    ec2_vpc_net:
      region: "{{ region }}"
      name: "{{ project_name }}"
      cidr_block: "{{ cidr_block }}"
      state: present
    register: vpc

The only difference here is that the variables are split into a separate file (as per Ansible best practices

Last but not least - Terraform.

resource "aws_vpc" "testvpc" {
    cidr_block = "${var.vpc_cidr}"
    enable_dns_hostnames = true
    tags {
        Name = "${var.project_name}"
    }
}

Here the provider is split out into a separate file and the variables into another file (Terraform best practices)

First Score - # lines of Code (Including all nested files)

Ansible - 19
CloudFormation - 28
Terraform - 29

Second Score - Easy of deployment / teardown.

I will not give a numerical score here - just to mention a basic difference between the three options.

Each of the tools use a  simple command line syntax to deploy

  1. CloudFormation

    aws cloudformation create-stack --stack-name testvpc --template-body [file://vpc_cloudformation_template.yml](file://vpc_cloudformation_template.yml)

  2. Ansible

    ansible-playbook create-vpc.yml

  3. Terraform

    terraform apply -auto-approve

The teardown is a bit different

  1. CloudFormation stores the information as a stack - and all you need to do to remove the stack and all of its resources is to run a simple command of:

    aws cloudformation delete-stack --stack-name <STACKNAME>

  2. Ansible - you will need to create an additional playbook for tearing down the environment - it does not store the state locally. This is a drawback

    ansible-playbook remove-vpc.yml

  3. Terraform - stores the state of the deployment - so a simple run will destroy all the resources

    terraform destroy -auto-approve

The last one I wanted to address was the time it took to deploy/tear down the resources for each tool - and I think that the differences here are quite interesting.

I ran a for.. loop through 3 iterations to bring up the VPC and tear it down and timed the duration for each run.

You can find the full output of the runs below:

Results

CloudFormation

create: 31.987s destroy: 31.879s

Ansible

create: 8.144s destroy: 2.554s

Terraform

create: 17.452s destroy: 12.652s

So to summarize - it seems that Ansible is the fastest one of them all - there are a number of reasons why this is the case (and I will go into more detail into this in a future post)

This is by no means a recommendation to use one tool or the other - or to say that one tool is better than the other - just a simple side by si*de comparison between the three options that I have used in the past.

Next blog post will go into a slightly more complicated scenario.

Thoughts and comments are always welcome, please feel free to leave them below.