Recently I had to evaluate cloud computing offers for a new project. I started with Google Cloud Platform.

Google Cloud: Free Tier

For my evaluation goals the always-free tier was enough.

This free tier has many perks (at IaaS and PaaS), but for this exercise we will use:

Goals

We are going to bootstrap a 1-VM cluster on Google Cloud Compute Engine using Terraform. The VM will have a 30GB hard disk.

Terraform

Terraform is tool to automate the provision of cloud infrastructures. Basically it translate a descriptor (Configurations in Terraform jargon) in calls to the chosen cloud provider API. The fancy name for this management process is “Infrastructure as Code”.

Infrastructure as Code

Why should you describe your infrastructure with code? For three reasons:

  1. It will be auditable: you know what’s in there
  2. It can be versioned: you can control the changes
  3. It can automatically processed: there are tools that can process your infrastructure descriptors and automatically apply changes

Terraform Configurations

The whole project is available on GitHub: ferrarimarco/google-cloud-playground

Being this a really simple infrastructure, we used just three configurations

  1. Resources: gce.tf
  2. Outputs: outputs.tf
  3. Variables: variables.tf

Resources

In this configuration we define the following resources:

  1. A backend
  2. Default provider credentials
  3. A reginal Google Compute Engine IP Address
  4. A Virtual Machine

Backend

A backend is needed to share the Terraform state, if you want to collaborate with others on the management activities of the infrastructure. You could avoid setting up a backend (Terraform will use a local backend by default), but then you need to deal with the inevitable merging conflicts due to Terraform executions by different users. I configured it because with a remote backend I’m able to modify my infrastructure from any workstation.

To keep this in the same infrastructure, I manually created a Google Cloud Storage bucket and configured it in the resources configuration as:

terraform {
  backend "gcs" {
    credentials = "account.json"
    prefix  = "terraform/state"
  }
}

where account.json is a credential file created as described in the README.

Default Provider Configuration

These are the default settings that we configured for the Google Cloud provider. Can be overridden by other resources.

provider "google" {
  credentials = "${file("account.json")}"
  project     = "${var.project_id}"
  region = "us-east1"
  zone = "us-east1-b"
}

Note the use of variables (${}). We’ll explain this later.

Google Compute Engine: IP Address and VM

Now let’s get to the meat: the Virtual Machine and its public IP address. The syntax is straightforward.

resource "google_compute_address" "regional-m1-ip" {
  name = "regional-m1-ip"
}

resource "google_compute_instance" "gce-free-tier" {
  name = "gce1"
  machine_type = "f1-micro"
  tags = ["free-tier"]

  boot_disk {
    auto_delete = true
    initialize_params {
      image = "ubuntu-os-cloud/ubuntu-1804-bionic-v20180426b"
      size = 30
      type = "pd-standard"
    }
  }

  metadata {
    ssh-keys = "${var.ssh_user}:${file("${var.public_key_path}")}"
  }

  network_interface {
    access_config {
      nat_ip = "${google_compute_address.regional-m1-ip.address}"
    }
    subnetwork = "default"
  }

  service_account {
    scopes = [
      "https://www.googleapis.com/auth/devstorage.read_only",
      "https://www.googleapis.com/auth/logging.write",
      "https://www.googleapis.com/auth/monitoring.write",
      "https://www.googleapis.com/auth/servicecontrol",
      "https://www.googleapis.com/auth/service.management.readonly",
      "https://www.googleapis.com/auth/trace.append"
    ]
  }
}

A couple of notes:

  • Terraform does not yet support OS-Login. We are stuck with Metadata-based logins (hence the setup of metadata) in the configuration
  • Region and image id should be parametrized with variables as well

Outputs

With Terraform we can define the outputs of each terraform apply run. In this case it’s useful to get, for each VM, its id public IP address so we can connect to continue with the configuration.

output "instances" {
  value = "${join(",", google_compute_instance.gce-free-tier.*.instance_id, google_compute_instance.gce-free-tier.*.network_interface.0.address, google_compute_instance.gce-free-tier.*.network_interface.0.access_config.0.assigned_nat_ip)}"
}

Variables

To avoid hard coding values in the configuration, I used a separate file to define runtime variables that can be overridden if necessary:

variable "public_key_path" {
  description = "Path to file containing public key"
  default     = "~/.ssh/id_rsa_gcloud.pub"
}

variable "private_key_path" {
  description = "Path to file containing private key"
  default     = "~/.ssh/id_rsa_gcloud"
}

variable "project_id" {
  description = "Google Cloud Project ID"
}

variable "ssh_user" {
  description = "SSH User"
}

Conclusions

I showed you how to automatically setup a completely free (but somewhat limited) 1-VM cluster in Google Cloud and Terraform.

Keep up with the updates in the GitHub repository: I’m going to expand the cluster with more Google Cloud free tier perks.