Automatic Deployments with Terraform

Brandon Rozek

May 8, 2020

I have recently written about Packer to create system images or snapshots. This post will go over another HashiCorp project named Terraform that we can use to deploy that image to a VPS. Like before, I am going to go over how to setup this up in DigitalOcean. Check out this list for documentation on your favorite cloud provider.

Variables

To protect against committing secrets like API keys, we’re going to create a file that only stores variables. For it to be loaded automatically, it needs to be named terraform.tfvars. Here is an example configuration:

region = "nyc3"
size = "512mb"
domain = "example.com"
subdomain = "temp"

# Secrets
do_token = "DO-TOKEN-HERE"
key_name = "SSH-KEY-NAME-ON-DO"

Now to define the variables in HCL, we need to create a separate variables.tf file defining their types

variable "do_token" {
  type = string
}

variable "domain" {
  type = string
}

variable "key_name" {
  type = string
}

variable "subdomain" {
  type = string
}

variable "region" {
  type = string
}

variable "size" {
  type = string
}

Configuration

Now let’s create a file called do.tf. We need to start off by stating which provider we are using

provider "digitalocean" {
    token = var.do_token
}

If you want to hook up your SSH key, then we need to query the Digital Ocean API for its ID.

data "digitalocean_ssh_key" laptop {
    name = var.key_name
}

We need to also query the API for the packer snapshot we created. Replace this with any standard image like "ubuntu-20-04-x64" if you don’t want to use a snapshot.

data "digitalocean_droplet_snapshot" "packer_snapshot" {
    name = "packer-example"
    most_recent = true
}

Now we can create the droplet

resource "digitalocean_droplet" "web" {
    name = "tf-1"
    image = data.digitalocean_droplet_snapshot.packer_snapshot.id
    region = var.region
    size = var.size
    ssh_keys = [data.digitalocean_ssh_key.laptop.id]
    backups = false
}

Attach a domain to the droplet

resource "digitalocean_record" "www" {
  domain = var.domain
  type   = "A"
  name   = var.subdomain
  value  = digitalocean_droplet.web.ipv4_address
}

Output useful pieces of information like the new system’s IP address and the domain

output "ip" {
    value = digitalocean_droplet.web.ipv4_address
}

output "domain" {
    value = "${digitalocean_record.www.name}.${digitalocean_record.www.domain}"
}

The whole configuration file for your convenience:

provider "digitalocean" {
    token = var.do_token
}

data "digitalocean_ssh_key" laptop {
    name = var.key_name
}

data "digitalocean_droplet_snapshot" "packer_snapshot" {
    name = "packer-example"
    most_recent = true
}

# Create a droplet
resource "digitalocean_droplet" "web" {
    name = "tf-1"
    image = data.digitalocean_droplet_snapshot.packer_snapshot.id
    region = var.region
    size = var.size
    ssh_keys = [data.digitalocean_ssh_key.laptop.id]
    backups = false
}

# Attach a subdomain
resource "digitalocean_record" "www" {
  domain = var.domain
  type   = "A"
  name   = var.subdomain
  value  = digitalocean_droplet.web.ipv4_address
}

output "ip" {
    value = digitalocean_droplet.web.ipv4_address
}

output "domain" {
    value = "${digitalocean_record.www.name}.${digitalocean_record.www.domain}"
}

Deploy

Check if your configuration is valid

terraform plan

Deploy!

terraform apply

Take down when done

terraform destroy