Intro

In this blog we are going to take a look at Terraform. Terraform is tool that enables you to manage your cloud infrastructure in an auditable and programmatic way. In this initial post we are going to go through the most basic application, creating and spinning up an EC2 instance. Future posts will build on this for other applications

Setup

You will need to install Terraform in your terminal. I am not going to cover installation in this post, but you can check out terraform.io and install if from there.

What is Terraform

Many people think Terraform is just a bunch of config files, but rather than thinking of it as config files it is more helpful to think of it as a programming language. You can define lists, maps (similar to python dictionaries), strings, and perform actions using values in those variables.

Variables

For example, Here's how I could define a map, where I may store different ami's for different region.

variable "AMIS" {
    type = map(string)
    default = {
        us-east-1 = "ami-0ac80df6eff0e70b5",
        us-east-2 = "ami-31432143214213435"
    }
}

Then in terrarorm console get that value using:

var.AMIS.us-east-1

So this is how we can get and store different configuration options. But Terraform is not just variables. You also have ways of running your code to deploy things. For example terraform plan shows you what it would do if you deployed. terraform apply deploys your options and terraform destroy destroys all your infrastructure defined.

But what is it applying? So far all we have done is define a variable. Let's define an EC2 instance.

Actions

resource "aws_instance" "web" {
ami = "${lookup(var.AMIS, var.AWS_REGION)}"
instance_type = "t2.micro"
}

From the above we can see we have most of what we need to launch an EC2 instance. We define an AMI by looking up the AWS_Region variable from the AMIS variable we defined above.

Full EC2 setup

You may have noticed, there's a few things missing from the above. For example, how does it connect to AWS? How do you give it the credentials without putting them in github? We will create 4 files that gets a good organized setup for the full thing.

  • instance.tf: This will be the actual command that defined the EC2 instance we want to create
  • vars.tf: We can define all the variables we will need here
  • provider.tf: This will have the command needed to connect to our AWS account
  • terraform.tfvars: This will store our aws credentials

vars.tf

First we will define all the variables we need. You may notice I do not put any values in the the credentials. This is on purpose - best practice is to keep access keys out of github. We will define these in a different file.

You can see we also set a default AWS_REGION as well as AMIs to use. I am only setting 1, but you can make as complicated of a map variable as you want with multiple regions, different types of instances (maybe a Deep learning ami, and a random forest ami, and a generally compute ami).

variable "AWS_ACCESS_KEY" {}
variable "AWS_SECRET_KEY" {}
variable "AWS_REGION" {
    default = "us-east-1"
}

variable "AMIS" {
    type = map(string)
    default = {
        us-east-1 = "ami-0ac80df6eff0e70b5"
    }
}

terraform.tfvars

This is a pretty simple file where we define the values for our credentials. The important thing is to add this file to the gitignore so that it does not get put in the github reposity (for security reason). It just holds your credentials, for example it may be.

AWS_ACCESS_KEY = "ABCDE12345FGHI6789"
AWS_SECRET_KEY = "abc123def456+789ghi983klm

provider.tf

Next. we will connect to aws using the keys we defined in the terraform.tfvars and vars.tf files. The provider.tf file looks like this:

provider "aws" {
access_key = "${var.AWS_ACCESS_KEY}"
secret_key = "${var.AWS_SECRET_KEY}"
region = "${var.AWS_REGION}"
}

instance.tf

Now finally we are ready to launch our instance. We have our region, our credentials, and are connected to aws. Naturally we could have 100 different instances defined in this same way for different regions and instance types and it will automatically create them all, but for now we will just create 1 and stay within the free-tier.

resource "aws_instance" "web" {
ami = "${lookup(var.AMIS, var.AWS_REGION)}"
instance_type = "t2.micro"
}

You will notice I am using the lookup funciton. This is looking up the var.AWS_REGION from the var.AMIS variable. We set the default region to us-east-1 in the vars.tf file. And it uses that to lookup that key in the AMIS variable, which is a map of strings.

Apply the Changes

Now all you need to do is run terraform apply in your terminal and your t2.micro ec2 instance will automatically be created! If it is a new folder for terraform, you will need to run terraform init in the folder before it will work.