Skip to main content

On This Page

Scaling Google Cloud Infrastructure with Reusable Terraform Modules

3 min read
Share

These articles are AI-generated summaries. Please check the original sources for full details.

Terraform Modules for Reusable GCP Infrastructure (With a Real VPC Module Example)

Terraform modules encapsulate infrastructure logic into discrete units comprising variables, outputs, and resources. By moving beyond copy-pasted code, engineers can manage VPCs, subnets, and firewalls through clean, input-driven interfaces.

Why This Matters

In high-scale engineering environments, manual infrastructure replication leads to configuration drift and increased operational overhead. Using generic modules that avoid hardcoded regions or CIDRs allows for composable architecture, while caution with authoritative IAM resources prevents accidental access revocation during automated deployments.

Key Insights

  • A standard Terraform module requires a structure of variables.tf for inputs, outputs.tf for resource exposure, and main.tf for resource definition.
  • Dynamic subnet creation is achieved using the for_each meta-argument to iterate over a list of subnet objects including CIDR and region data.
  • Input validation within the variables.tf file, such as restricting routing_mode to REGIONAL or GLOBAL, catches configuration errors before deployment.
  • Module versioning via Git tags (e.g., ?ref=v1.0.0) allows teams to pin specific versions, ensuring production stability while testing new changes in dev.
  • Composable architecture is preferred over monolithic ‘platform modules’ by splitting logic into specialized components like modules/vpc and modules/cloud_sql.

Working Examples

Core logic for a reusable GCP VPC module using for_each for subnet management.

resource "google_compute_network" "this" { project = var.project_id name = var.vpc_name auto_create_subnetworks = false routing_mode = var.routing_mode } resource "google_compute_subnetwork" "this" { for_each = { for s in var.subnets : s.name => s } project = var.project_id name = each.value.name ip_cidr_range = each.value.cidr region = each.value.region network = google_compute_network.this.id private_ip_google_access = each.value.private_google_access }

Calling the VPC module from an environment-specific directory.

module "vpc" { source = "../../modules/vpc" project_id = var.project_id vpc_name = "dev-vpc" subnets = [{ name = "dev-us-central1-public", region = "us-central1", cidr = "10.10.0.0/24", private_google_access = true }] }

Practical Applications

  • Use case: Standardizing networking across dev and prod by calling a central VPC module with different CIDR blocks. Pitfall: Hardcoding environment names or project IDs inside the module folder makes it non-reusable.
  • Use case: Automated firewall management where rules are passed as a list of objects to the network module. Pitfall: Implementing authoritative IAM resources which can remove existing project permissions unexpectedly.
  • Use case: Version-controlled infrastructure updates where the prod environment is pinned to a specific Git ref while dev uses the latest master. Pitfall: Neglecting to use version pins, leading to breaking changes in production when a shared module is updated.

References:

Continue reading

Next article

Optimizing API Architecture: Processing 1 Billion Requests for $40

Related Content