Fast and Consistent Deployments with Terraform
Tags: terraform, saas, devops
Published: 2024-05-30 22:33:44

Most types of internet-first businesses have become incredibly competitive. You're not just competing with people in your town, but everyone around the world. Because of this, the speed at which you can launch new products and features can be the difference between success and failure. This is why it is important to have a good infrastructure in place that allows you to not only launch fast, but update fast too.

In this article, I'll be giving a brief overview of Terraform and show you how I used it to launch my new monitoring tool, [Ping Bot](https://pingbot.dev).

## What is Terraform?

Terraform is an open-source **infrastructure as code** software tool created by HashiCorp. It lets you define and provision data center infrastructure using a declarative configuration language. Terraform manages external resources like public cloud infrastructure, private cloud infrastructure, network appliances, software as a service, platform as a service, DNS, and a whole lot more with a code.

Let's see a simple example:
    
```hcl
provider "aws" {
  region = "us-west-2"
}

resource "aws_instance" "example" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"
}
```

This code will create an EC2 instance in the `us-west-2` region with the `t2.micro` instance type. You could do the same thing for most other cloud providers, like Azure, Google Cloud, and Digital Ocean.

For a single instance, Terraform doesn't give you much of an advantage. But when you add in all of the other resources and configurations, it becomes a powerful tool. Not just for the time-saving, but consistency and repeatability as well. If your service only uses a small number of resources, you might not see the benefits of Terraform.

There are 3 main reasons I decided to use Terraform:

1. **Speed**: I wanted to be able to launch my products as fast as possible. Terraform allowed me to quickly create all of the resources I needed in AWS. From servers to databases to S3 buckets, I could do it all with a single command.
2. **Consistency**: I wanted to make sure that my infrastructure was consistent across all of my environments. When you have dozens of resources, manually creating and configuring them can lead to mistakes. Terraform ensures that everything is created the same way every time.
3. **Repeatability**: I wanted to be able to easily recreate my infrastructure in case of a disaster. If something were to happen to my AWS account or I needed to transfer accounts, I could easily recreate everything.

## Terraform Setup

Before we get ahead of ourselves, let's talk about setup. There are a ton of resources on [installing](https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli) and using Terraform, so in this article I'll mostly be talking about how I used it. This kind of setup is probably best for single-person projects or small teams. For larger teams, you might want to look into more advanced configurations and tooling.

If you're like me, you have a few different AWS accounts for different projects. Because of this, I've set up my different profiles in the `~/.aws/credentials` file. This allows me to easily switch between accounts.

```ini
[default]
aws_access_key_id = YOUR_ACCESS_KEY
aws_secret_access_key = YOUR_SECRET_KEY

[pingbot]
aws_access_key_id = YOUR_ACCESS_KEY
aws_secret_access_key = YOUR_SECRET_KEY
```

I can then use this in my Terraform config to switch between AWS accounts, depending on which environtment I want to deploy to:

```hcl
provider "aws" {
  region = "us-west-2"
  profile = "pingbot"
}
```

I also took advantage of Terraform's workspace feature. This allows you to have multiple environments, like `dev`, `staging`, and `production`, all in the same codebase. This is great because you can easily test changes in a safe environment before deploying to production.

Once I've created my workspaces with `terraform workspace new [NAME]`, I can switch between them with `terraform workspace select [NAME]`. Then in my configuration code, I use the workspace throughout to create different resources based on the environment. This can be done using `locals`.

```hcl
locals {
  ns = {
    dev   = "-dev"
    stage = "-stage"
    prod  = ""
  }

  instance_type = {
    dev   = "t2.micro"
    stage = "t2.medium"
    prod  = "t2.large"
  }
}

resource "aws_instance" "example" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = local.instance_type[terraform.workspace]
}

resource "aws_s3_bucket" "pingbot" {
  bucket = "pingbot${local.ns[terraform.workspace]}"
}

resource "aws_route53_record" "pingbot" {
  zone_id = aws_route53_zone.pingbot.zone_id
  name    = terraform.workspace == "prod" ? "pingbot.dev" : "${terraform.workspace}.pingbot.dev"
  type    = "A"
  ttl     = "300"
  records = [aws_instance.pingbot.public_ip]
}
```

Here I'm changing the instance size, S3 bucket name, and Route53 record based on the workspace.

## Modules

One of the most powerful features of Terraform is modules. Modules are reusable Terraform configurations that can be called multiple times. This is great for creating reusable components that can be used multiple times in a project or shared across different projects.

For exampale, with Ping Bot I wanted to be able to [monitor infrastructure](https://pingbot.dev) for our customers from multiple locations around the world. Manually creating these resources in different AWS regions would've been tedious and error-prone. Instead, I created a module that would create the SQS queues and Lambdas in each location and installs the necessary software to run the pings.

```hcl
module "ping_infra" {
  source = "./modules/ping_infra"

  locations = ["us-west-2", "us-east-1", "eu-west-1", "ap-southeast-1"]
}
```

Instead of taking an hour or two to set up ping infra in the Asia Pacific region, for example, I can do it in a few minutes with a single line change and `terraform apply` command.

A lot of teams are also pretty opinionated about how they want their infrastructure set up. By creating modules, you can create a standard way of doing things that everyone can use. This can help with onboarding new team members and make it easier to move between projects.

## Cons of Terraform

While Terraform is a great tool, it's not without its downsides. Here are a few things to consider before using it:

1. **Complexity**: Terraform can be complex, especially when you start using modules and more advanced features. This can make it hard for new team members to get up to speed if your setup isn't well thought-out or you don't have someone who specifically owns the process.

2. **State Management**: Terraform uses a state file to keep track of the resources it creates. This file can get out of sync with your actual infrastructure if you're not careful. This can lead to some pretty bad situations if you're not careful. You'll often find yourself needing to migrate state as files change, which can be a huge pain.

3. **Learning Curve**: Terraform has a bit of a learning curve. While the basics are pretty easy to pick up, the more advanced features and edge cases can be confusing, especially for more junior developers. This can make it hard to get started if you're not already familiar with infrastructure as code tools.

4. **Cost**: Terraform can be expensive, especially if you're using it to manage a lot of resources. This isn't exactly Terraform's fault, but when your resources just become code, it's easy to lose track of what you're actually spending. This can lead to some pretty big bills if you're not careful. Self-funded startups, in particular, should be careful!

## Conclusion

Terraform is a powerful tool that can help you launch faster and more consistently. By defining your infrastructure as code, you can easily create and manage resources across multiple environments. This can help you move faster and reduce the risk of mistakes. While it's definitely not perfect, it's a great tool to have in your toolbox if you're looking to launch fast and stay competitive.

Thoughts? Feedback? I'd love to hear from you - there are plenty of places to [reach me](https://linktr.ee/scottwrobinson).