Terraform GCP Skill
Production patterns for GCP infrastructure provisioning with Terraform.
Provider Setup
terraform {
required_providers {
google = {
source = "hashicorp/google"
version = "~> 5.0"
}
google-beta = {
source = "hashicorp/google-beta"
version = "~> 5.0"
}
}
}
provider "google" {
project = var.project_id
region = var.region
}
VPC Network
resource "google_compute_network" "main" {
name = "${var.project}-vpc"
auto_create_subnetworks = false
routing_mode = "REGIONAL"
}
resource "google_compute_subnetwork" "private" {
name = "${var.project}-private"
ip_cidr_range = "10.0.0.0/24"
region = var.region
network = google_compute_network.main.id
private_ip_google_access = true
secondary_ip_range {
range_name = "pods"
ip_cidr_range = "10.1.0.0/16"
}
secondary_ip_range {
range_name = "services"
ip_cidr_range = "10.2.0.0/16"
}
}
resource "google_compute_router" "main" {
name = "${var.project}-router"
region = var.region
network = google_compute_network.main.id
}
resource "google_compute_router_nat" "main" {
name = "${var.project}-nat"
router = google_compute_router.main.name
region = var.region
nat_ip_allocate_option = "AUTO_ONLY"
source_subnetwork_ip_ranges_to_nat = "ALL_SUBNETWORKS_ALL_IP_RANGES"
}
GKE Cluster
resource "google_container_cluster" "main" {
provider = google-beta
name = "${var.project}-gke"
location = var.region
remove_default_node_pool = true
initial_node_count = 1
network = google_compute_network.main.name
subnetwork = google_compute_subnetwork.private.name
ip_allocation_policy {
cluster_secondary_range_name = "pods"
services_secondary_range_name = "services"
}
private_cluster_config {
enable_private_nodes = true
enable_private_endpoint = false
master_ipv4_cidr_block = "172.16.0.0/28"
}
workload_identity_config {
workload_pool = "${var.project_id}.svc.id.goog"
}
release_channel {
channel = "STABLE"
}
}
resource "google_container_node_pool" "primary" {
name = "primary"
location = var.region
cluster = google_container_cluster.main.name
node_count = 3
autoscaling {
min_node_count = 1
max_node_count = 10
}
node_config {
machine_type = "e2-standard-4"
disk_size_gb = 100
oauth_scopes = [
"https://www.googleapis.com/auth/cloud-platform"
]
workload_metadata_config {
mode = "GKE_METADATA"
}
}
}
Cloud SQL
resource "google_sql_database_instance" "main" {
name = "${var.project}-db"
database_version = "POSTGRES_15"
region = var.region
settings {
tier = "db-custom-4-16384"
availability_type = var.environment == "prod" ? "REGIONAL" : "ZONAL"
backup_configuration {
enabled = true
point_in_time_recovery_enabled = true
start_time = "03:00"
}
ip_configuration {
ipv4_enabled = false
private_network = google_compute_network.main.id
}
}
deletion_protection = var.environment == "prod"
}
IAM
resource "google_service_account" "app" {
account_id = "${var.project}-app"
display_name = "Application Service Account"
}
resource "google_project_iam_member" "app_storage" {
project = var.project_id
role = "roles/storage.objectViewer"
member = "serviceAccount:${google_service_account.app.email}"
}
# Workload Identity binding
resource "google_service_account_iam_member" "workload_identity" {
service_account_id = google_service_account.app.name
role = "roles/iam.workloadIdentityUser"
member = "serviceAccount:${var.project_id}.svc.id.goog[${var.namespace}/${var.k8s_sa_name}]"
}
Troubleshooting
| Error | Cause | Solution |
|-------|-------|----------|
| Permission denied | Missing IAM role | Add required role |
| Quota exceeded | Resource limit | Request quota increase |
| Network not found | Wrong project/name | Check network reference |
Usage
Skill("terraform-gcp")
Related
- Agent: 08-terraform-advanced (SECONDARY_BOND)