Terraform is a powerful Infrastructure as Code (IaC) tool that lets you describe, provision, and manage cloud resources declaratively. In an era that celebrates “low-code” and “no-code,” using Terraform may seem contradictory, but it dramatically simplifies infrastructure lifecycle management.
One killer feature: every resource Terraform creates can be destroyed with a single terraform destroy. When I experiment in personal cloud projects, that command saves me money by removing everything—no more missed resources lurking on the bill.
This post walks through my go-to setup for provisioning and tearing down GKE clusters with Terraform.
Authenticate with gcloud
Terraform needs credentials to talk to GCP. I rely on gcloud auth:
gcloud auth login --brief
Sign in through the browser window that pops up.
List authenticated accounts:
gcloud auth list
Remove an account if necessary (I use this to avoid mixing company and personal projects):
gcloud auth revoke test@gmail.com
Finally, set the application default credentials so Terraform can pick them up:
gcloud auth application-default login
After this Terraform can access GCP on your behalf.
Install Terraform
On macOS:
brew tap hashicorp/tap
brew install hashicorp/tap/terraform
Other platforms are covered in the official download page.
Verify the installation:
$ terraform --version
Terraform v1.4.6
on darwin_arm64
Prepare the Module Layout
Creating a GKE cluster manually requires configuring VPCs, subnets, service accounts, and more. Rather than reimplement everything, I use the excellent modules from terraform-google-modules, specifically the google-kubernetes-engine repository.
Clone the repo and organize it like this:
$ tree
.
├── gke
│ ├── gke.tf
│ └── variables.tf
└── module
└── google-kubernetes-engine
├── README.md
├── cluster.tf
├── dns.tf
├── firewall.tf
├── main.tf
├── masq.tf
├── networks.tf
├── outputs.tf
├── sa.tf
├── scripts
│ └── delete-default-resource.sh
├── variables.tf
├── variables_defaults.tf
└── versions.tf
All module code lives under module/google-kubernetes-engine; the gke directory holds the configuration for my cluster.
gke.tf wires the module:
module "cluster" {
source = "../module/google-kubernetes-engine"
ip_range_pods = ""
ip_range_services = ""
name = "<cluster-name>"
network = ""
project_id = "<project-id>"
subnetwork = ""
region = "asia-northeast3"
zones = ["asia-northeast3-a"]
regional = false
node_pools = [
{
name = "pool-1"
machine_type = "e2-standard-2"
autoscaling = false
node_count = 2
disk_size_gb = 10
disk_type = "pd-balanced"
auto_upgrade = true
},
]
}
variables.tf configures the provider and backend:
provider "google" {
project = "<project-id>"
region = "asia-northeast3"
}
terraform {
backend "gcs" {
bucket = "terraform-state-bucket"
prefix = "terraform-gke"
}
required_providers {
google = {
source = "hashicorp/google"
version = ">= 4.51.0, < 4.65.0"
}
}
}
Feel free to adapt these files to your environment. If you don’t need remote state, swap the backend for local.
Provision the Cluster
Run Terraform from the gke directory:
cd terraforms/gke # example path
Initialize providers and modules:
terraform init
Show the planned changes:
terraform plan
Apply the configuration:
terraform apply
Review the plan and type yes. Terraform provisions the VPC, subnet, service accounts, cluster, and node pools. When it finishes you’ll see:
Apply complete! Resources: 9 added, 0 changed, 0 destroyed.
Modify the configuration as needed—Terraform keeps everything in sync.
Tear Everything Down
When you’re done (and want to save on cloud costs), destroy the resources:
terraform destroy
That single command deletes every object Terraform created.