Skip to main content

Hands-on: Build, Change, Destroy

Exam guide§2.4

With the workflow and HCL blocks understood, this is the hands-on loop: point Terraform at the Google provider, then build, change, and destroy a real google_compute_instance - watching how terraform plan classifies every action before you apply it.

Define the Google provider

A Google Cloud configuration starts with two blocks: a terraform block that declares which provider to pull from the registry, and a provider "google" block that sets the default project, region, and zone for the resources you create.

terraform {
required_providers {
google = {
source = "hashicorp/google"
}
}
}
 
provider "google" {
project = "Project ID"
region = "Region"
zone = "Zone"
}

Initialize

terraform init reads the config, downloads the matching provider plugin, and writes a .terraform.lock.hcl lock file recording the exact provider version it selected.

GotchaCommit the lock file

terraform init creates .terraform.lock.hcl to pin the provider version. Check it into version control so every init on every machine selects the same provider by default, rather than silently pulling a newer version that could change plan output.

(Working in Cloud Shell? See the install recipe - Terraform is no longer pre-installed there.)

Build the infrastructure

A resource block takes two labels: the resource type (google_compute_instance, set by the provider) and a local name (terraform, your handle for referencing it elsewhere in the config). It is not the name of the VM in Google Cloud - that is the name argument.

resource "google_compute_instance" "terraform" {
name = "terraform"
machine_type = "e2-micro"
boot_disk {
initialize_params {
image = "debian-cloud/debian-11"
}
}
network_interface {
network = "default"
access_config {
}
}
}
GotchaA compute instance needs a `network_interface`

Omit the network_interface block and terraform plan fails before it ever calls the API: Error: Insufficient network_interface blocks ... At least 1 "network_interface" blocks are required. A VM cannot exist without a network, so this block is mandatory. The empty nested access_config {} is what gives the instance an external IP.

terraform plan previews the change and marks every action with a symbol - + create, ~ update in-place, - destroy (the full change-symbol legend lives with the commands); terraform apply (then typing yes) executes it.

The build ends with Plan: 1 to add, 0 to change, 0 to destroy and, after apply, the VM appears under Compute Engine > VM instances.

Change the infrastructure

Editing the .tf file and re-running apply reconciles the live resource to the new desired state. How Terraform applies a change depends on the argument.

Adding network tags is an in-place update (~) - the running VM keeps running:

resource "google_compute_instance" "terraform" {
name = "terraform"
machine_type = "e2-micro"
tags = ["web", "dev"]
# ...
}

Changing machine_type from e2-micro to e2-medium, however, fails on a running VM:

GotchaSome updates require stopping the VM

A running instance cannot have its machine type changed. terraform apply errors until you acknowledge the stop by adding allow_stopping_for_update = true, which lets Terraform stop the VM, update it, and restart it:

resource "google_compute_instance" "terraform" {
name = "terraform"
machine_type = "e2-medium"
allow_stopping_for_update = true
# ...
}

Setting desired_status = "TERMINATED" also stops it, but Terraform will not restart it afterward.

FactsArguments whose change forces a stop

Changing any of these on a started instance requires allow_stopping_for_update = true:

  • machine_type
  • min_cpu_platform
  • service_account
  • enable_display
  • shielded_instance_config
  • scheduling.node_affinities
  • network_interface.[#].(network / subnetwork / subnetwork_project)
  • advanced_machine_features

Destroy the infrastructure

terraform destroy (confirmed with yes) removes every resource in the state. Each line is prefixed with -, and the VM disappears from the console.

Recap

CommandsThe build-change-destroy loop
terraform init # download the google provider, write .terraform.lock.hcl
terraform plan # preview: + create, ~ update in-place, - destroy
terraform apply # execute the plan (type "yes")
terraform destroy # tear it all down (type "yes")
DECISIONWill an argument change update in-place or need a stop?
Tags, labels, metadata, and most soft settingsin-place update (~), VM keeps running
machine_type, service_account, shielded/display config, networkrequires allow_stopping_for_update = true
name, boot-disk image, and other immutable fieldsdestroy and recreate (- then +)
Pick this when: check whether the field can change on a running VM