Deploying Containers on Amazon’s ECS using Fargate and Terraform: Part 2

Bradford Lamson-Scribner
5 min readJul 20, 2018

--

UPDATED (7/23/19): Hey everyone, I just updated the source code and gists throughout this tutorial to use Terraform v0.12.5. Also there were many requests to create the ECS task execution role and ECS auto scaling role with Terraform (prior to now it was done manually in the AWS GUI in Part 1). I’ve added that update to the source code in terraform/roles.tf and those new Terraform resources are now referenced in throughout the gists below.

In this part of the tutorial we will focus on writing out our entire infrastructure from Part 1 using Terraform. Terraform enables you to predictably create, change, and improve infrastructure using code. By the end of this section we will be able to run one command to deploy our entire application giving us:

  • A Virtual Private Cloud with private and public subnets
  • Multiple running container instances
  • A load balancer distributing traffic between the containers
  • Auto scaling of your resources
  • Health checks and logs

Every time I think about that, it blows me away. Just press enter and build an entire system in a few minutes that not too long ago would have taken numerous people a lot of time and money to get up and running.

Let’s get started

One of the nice parts about Terraform is that it’s very self-explanatory. There is some syntax and configuration to learn and then it feels a bit like you’re just outlining how you want your system to work. Here is a link to the Terraform AWS docs. Let’s begin by creating the project and setting up the file structure we want to use.

mkdir terraform-example && cd terraform-example

Next within the root of the project we’ll add a .gitignore file with the following contents.

# Compiled files
*.tfstate
*.tfstate.backup
.terraform.tfstate.lock.info
# Module directory
.terraform/

Within the root of the project add a terraform/ directory. As you’ll see next - Terraform config files use the file extension .tf.

Inside the directory you just made let’s add the following files:

  • provider.tf
  • ecs.tf
  • alb.tf
  • network.tf
  • security.tf
  • auto_scaling.tf
  • logs.tf
  • variables.tf
  • outputs.tf

I tried breaking the code up into files handling each of the different parts of our infrastructure. This was for (hopefully) more clarity, however it will work just fine if you have all the code in just one big main file as well.

The first thing we’ll do is specify the provider. This can be done in different ways but here we’re telling Terraform our provider is AWS and that it can find our credentials in $HOME/.aws/credentials which is the default location for AWS credentials on Mac and Linux.

You’ll notice the string interpolated value for “region”. As you may be able to tell, this is a variable. All of our variables will look like this using dot notation. Let’s set up our variables file so that this makes a little more sense.

Terraform will know to look here for these values anytime it sees var.VARIABLE_NAME. For the sake of clarity the file above is all the variables for the application. Hopefully with their descriptions they all make sense.

We’ll again be using my crystal_blockchain docker image for our application. If you see “cb” throughout the terraform configs - thats what it refers to.

Time to create our network. To get the minimal amount of high availability, we’ll deploy our ECS cluster to run on at least two Availability Zones (AZs). The load balancer also needs at least 2 public subnets in different AZs.

Now that we have our network created, let’s set up some security groups to make sure our app is properly protected.

With all this in place, we’re ready to build out our application load balancer and ECS cluster! For this tutorial we’re going to be listening for HTTP requests on port 80, however I think it goes without saying that if you’re using this in production - listen for HTTPS over port 443. You can use AWS certificate manager (ACM) to provision and manage certificates.

First, our load balancer with a health check:

Then our ECS cluster:

On line 7 above, we use a data source for our container definition. Container definitions can also be written inline in an aws_ecs_task_definition. Here is a link to the docs for how that looks. I prefer to keep things modular and it’s easier for me to read and follow like that. Feel free to go about it either way!

If you do keep the datasource for the container definition we’ll have to add it to the project. Inside the same directory with all of our .tf config files, let’s create a templates/ directory and within that, an ecs/ directory. This is where we’ll put our cb_app.json.tpl file.

You’re getting close!

Time to get some auto scaling set up to monitor our application and automatically adjust capacity. We’ll create two CloudWatch alarms and two auto scaling policies to go with them.

Last but not least let’s add logging.

Wooooo!

You just built a badass infrastructure for an application. The only thing left to do is deploy! Terraform offers “outputs” which are great for getting data back after a deploy is successful. One last config file and it’s a short one I promise :)

This gives us back the load balancer DNS name (A record) after we deploy.

Time to run terraform init terraform/ in your terminal in the root of your project. This gets it all set up and ready to apply.

Finally, run terraform apply terraform/ to get this bad boy deployed! It will refresh state for all your resources and show you what will be created/removed/updated. It then prompts you to reply with “yes” if you want to perform the actions. That’s it! You will see everything getting provisioned. This will take a few minutes.

When it spits out your load balancer url, go ahead and visit it at port :3000 and you should see the JSON returned from the initial block in your deployed crystal_blockchain app.

I don’t know about you but I’m feeling like

Here’s a link to the code in full:

Thanks for reading! :)

--

--

Bradford Lamson-Scribner

Software Developer 💾 Hardware Geek 👽 Bird Whisperer 🐤