Feb 18, 2018

We are huge fans of HashiCorp's Terraform here at Elastic Byte. Terraform allows us to define infrastructure across nearly all cloud providers in a simple markup format. Being able to apply deltas to physical infrastructure, e.g. provision a new machine, or create a firewall rule and have Terraform determine dependencies and what needs to be created/deleted is fantastic.

Our second love affair is with Google Cloud Platform and Compute Engine. Compute Engine offers per minute second billing, typically superior VM performance compared to other clouds, and their persistent disks are significantly faster than Amazon Web Services EBS volumes.

Let's marry Terraform with Google Compute Engine, and provide a simple example of creating a few firewall rules and a standard blog VM instance. The only prerequisite is that you create a Google Cloud account and setup a default network which Google automagically does for you anyway.

Terraform loads in files with a .tf extension, so simply create a directory and start creating Terraform configs.

First, let's setup authorization to our Google Cloud project.

# gcp.tf

#####################################################################
# Google Cloud Platform
#####################################################################
provider "google" {
    credentials = "${file("gcp-credentials.json")}"
    project = "elastic-byte"
    region = "us-central1-a"
}

Next, let's create two firewall rules. The first locks down SSH to only allow inbound SSH connections from the Elastic Byte office ip address. The second firewall rule is a typical rule to allow http (port 80) traffic for the blog.

# firewall.tf

#####################################################################
# Firewall Rules
#####################################################################
resource "google_compute_firewall" "allow_ssh_office" {
    name = "allow-ssh-office"
    network = "default"

    allow {
        protocol = "tcp"
        ports = ["22"]
    }

    source_ranges = ["38.88.232.58/32"]
}

resource "google_compute_firewall" "allow_http" {
    name = "allow-http"
    network = "default"

    allow {
        protocol = "tcp"
        ports = ["80"]
    }

    source_ranges = ["0.0.0.0/0"]
    target_tags = ["http"]
}

Finally, let's create a SSD disk and VM for our blog. The SSD disk is created from a snapshot in Compute Engine.

# blog.tf

#####################################################################
# Variables
#####################################################################
variable "blog_zone" {
    type = "string"
    default = "us-central1-a"
    description = "The zone to provision into"
}

#####################################################################
# Disks
#####################################################################
resource "google_compute_disk" "blog" {
    name  = "blog"
    type  = "pd-ssd"
    zone  = "${var.blog_zone}"
    snapshot = "blog-2017-02-09-1"
    size = 10
}

#####################################################################
# VM Instances
#####################################################################
resource "google_compute_instance" "blog" {
    name = "blog"
    machine_type = "f1-micro"
    zone = "${var.blog_zone}"

    tags = ["http"]

    boot_disk {
        source = "${google_compute_disk.blog.name}"
        auto_delete = true
    }

    network_interface {
        network = "default"
        access_config {
            # ephemeral external ip address
        }
    }

    scheduling {
        preemptible = false
        on_host_maintenance = "MIGRATE"
        automatic_restart = true
    }

    provisioner "remote-exec" {
        inline = [
            'echo "hello from $HOST" > ~/terraform_complete'
        ]
        connection {
            type = "ssh"
            user = "ubuntu",
            private_key = "${file("~/.ssh/google_compute_engine")}"
        }
    }
}

Terraform is pretty self-explanatory and self-documenting which is a tribute to its design. One cool trick is that Terraform does handle some minimal configuration management in that you can specify commands to be executed over SSH when the instance boots. In this simple example though, we are just echoing hello from $HOST into a file on the VM.

To actually invoke this setup on Google Compute just run:

terraform apply

Terraform has lots more functionality and commands and we recommend reading their documentation. You'll discover that Amazon Web Services is their most widely supported cloud provider, but nearly all other cloud infrastructure providers have integrations.