How to use Terraform without server ?

guillaume blaquiere
Google Cloud - Community
6 min readAug 20, 2019

Terraform is trendy. Many ops use it: Multi cloud support, up-to-date, large community and templates,… Its advantages are multiple. However, I’m a big fan of serverless and I preferred Deployment manager. My ops did not, because it’s sticky to GCP. And they are right.

In fact, I never liked Terraform because of this endless loop :

For clean deployment of a server, use Terraform to deploy this server. Terraform has to be installed on a server; Use Terraform to deploy this server...

Thereby, I never used Terraform… until this unrelated post of Steren

What? Use Cloud Build for not building containers? It’s so smart!

Thanks to this tweet, an amazing idea comes to me: Use Terraform in serverless mode through Cloud Build!

First (bad) idea

Where to start? I need to execute Terraform and, as much as I (not) know Terraform, I need to keep tfstate files.

First step: does a docker image exist ?

Yes, Terraform installation is packaged in a container and available on Docker Hub. Thereby, it will be easy to use it with Cloud Build.

Second step: How to manage tfstate files?

Steren tweet shows how to push a file from Cloud Build environment to Google Cloud Storage at the end of the process. And for getting them from Storage at the beginning, use Cloud Builder images. That’s done!

I’m going to test and deep dive into Terraform mechanisms and documentation and… Bad first approach!

Terraform is mature

In fact, Terraform is far more mature than I expected. I discovered that a backend definition exists. It allows to retrieve and to store the deployment states remotely.

A GCS implementation exists and it’s very easy to use. Simply define the backend bucket and path in your main.tf file.

terraform {
backend "gcs" {
bucket = "my-state-bucket"
prefix = "terraform/state"
}
}

My second step is settled by 4 lines of configuration! It’s perfect!

Now, let’s focus on Terraform commands. There are only 2 steps to define in the cloudbuild.yaml file:

  • Run init command to set up the Cloud Build ephemeral environment
- name: 'hashicorp/terraform'  
args: ['init']
  • Run apply command to execute the deployment/update in auto-approve mode
- name: 'hashicorp/terraform'
args: ['apply','-var=PROJECT_ID=$PROJECT_ID','-auto-approve']

The apply command requires to know the PROJECT_ID. The trick is to valorize a Terraform variable with the Cloud Build environment variables PROJECT_ID. Terraform’s main.tf file handles the PROJECT_ID variable like this :

variable "PROJECT_ID" {
type = string
}
provider "google" {
//credentials = NOT NEEDED, use Cloud Build service account permissions
project = var.PROJECT_ID
region = "us-central1"
}

Leverage Cloud Build

The combination of Cloud Build and Terraform produces more than I expected initially: run Terraform on a server that I don’t have to manage.

Authentication

It’s another pain point not mentioned before, and that annoyed my ops: security. Indeed, on a managed server, dedicated to deployment of several different projects, you have to manage different service-accounts, with different permissions on these different projects.

For that, you have to store different JSON security key files. You have to rotate these JSON key files, to ensure their confidentiality/access right on the VM,… Lots of manual work, time consuming, and not always state of art security best practices.

Cloud Build solves this point. You simply use the permissions of a Cloud Build service account for the project. The security is now ensured by the platform.

Automation

With a server dedicated to deployment, you have to connect to it, to pull the code updates, and to launch the correct commands to apply changes. Without manual mistakes.

Cloud Build comes with automation and triggers. Thereby, a simple commit on the infrastructure definition files and the update is done automatically some minutes after.

History

With local execution on a server, you have only 1 file of history (terraform.tfstate.backup). Moreover, what is the resilience of this file on 1 server ? How is it protected against deletion/update by mistake ?

Here again, another advantage of this solution thanks to Terraform backend feature. The tfstate files are stored in Google Cloud Storage with high resilience and durability. And for keeping the history of changes, Terraform documentation recommends to activate versioning on the bucket dedicated of state storage

You can have much more than 1 backup file, and thus a better control of change and history. This is not related to Cloud Build, and you can use this capability independently

Portability and skills

Today, many teams already use Terraform because of its qualities. Teams have their process, their skills, they are trained on the product.

Here, the product combination doesn’t change team organization. It’s very simple to switch from one solution (server to manage) to another one (serverless with Cloud Build). The Terraform script are very similar; the Terraform skills in the teams are still required and the processes internally defined can be kept.

Versions management

Version management can be also a challenge. In case of backward incompatibilities, several versions can be required in the same time on the same server, increasing the management cost and issues probabilities (side effects, or human mistakes)

With Cloud Build, you can specify the Terraform build version that you want to use. The executions are isolated (no side effect between versions) and the version update is as simple as changing a version number in the cloudbuild.yaml file.

Pricing

Again and again, cost is an important decision factor. Cloud Build offers, per project, 120 minutes of build free per day and up to 10 concurrent builds.

In addition, you don’t have any platform management cost : server updates/patches, Terraform version managements, JSON key files to rotate, …

And more…

I’m sure I missing some key advantages. If you have one, share it!

I can add the Cloud Build cache that only downloads the hashicorp/terraform image for the first step and reuses it for the second step, without another download.

Another feature is the capability to add other steps, for deploying specific components on the infrastructure thanks to Cloud Builders. This feature is especially great in case of a missing Terraform feature that is available as a gcloud CLI command. This is a great workaround until Terraform implements these features (especially for Alpha/Beta services).

Also, still with Cloud Builders, there is the ability to decrypt secrets before using them as Terraform variables.

Finally, the notification feature that allows to push or pull the build state and to perform post-process on this event.

Cloud Build + Terraform: The ultimate combination

Definitively, the combination of the infrastructure automation and management of Terraform and the flexibility and build automation of Cloud Build generates a powerful product combination that I want to recommend to every team.

This is simple, affordable, quick; and above all, serverless!

I’m new to the Terraform world and if you have specific/complex use-cases that do not fit with this setup, I would like to know more and discuss these. Same thing if I’m incorrect or if there are better practices.

My example project is available here. The README.md helps you test it, and destroy your deployment.

--

--

guillaume blaquiere
Google Cloud - Community

GDE cloud platform, Group Data Architect @Carrefour, speaker, writer and polyglot developer, Google Cloud platform 3x certified, serverless addict and Go fan.