# ============================================================================= # GCP Workload Cluster # ============================================================================= # A lean GKE cluster for running application workloads. No managed data # services — those live on the platform cluster. ArgoCD (on the platform # cluster) deploys apps to this cluster via the app-of-apps pattern. # # Platform components deployed by deploy-workload.sh: # nginx-ingress, cert-manager, external-dns, external-secrets, alloy # # Usage: # tofu init && tofu plan && tofu apply # ./sync-tofu-outputs.sh --env gcp-workload # ./deploy-workload.sh --env gcp-workload # ============================================================================= variable "prefix" { description = "Prefix for resource names (e.g., clst-workload)" type = string default = "clst-workload" } variable "node_machine_type" { description = "GKE node machine type" type = string default = "e2-standard-2" } variable "node_count" { description = "Number of nodes per zone" type = number default = 1 } variable "kubernetes_version" { description = "GKE Kubernetes version (null = STABLE release channel)" type = string default = null } variable "deletion_protection" { description = "Prevent cluster deletion" type = bool default = false } variable "labels" { description = "Labels applied to all resources" type = map(string) default = { environment = "workload" managed-by = "tofu" } } # ─── Required APIs ──────────────────────────────────────────────────── resource "google_project_service" "compute" { project = var.project_id service = "compute.googleapis.com" disable_on_destroy = false } resource "google_project_service" "container" { project = var.project_id service = "container.googleapis.com" disable_on_destroy = false } resource "google_project_service" "iam" { project = var.project_id service = "iam.googleapis.com" disable_on_destroy = false } resource "google_project_service" "dns" { project = var.project_id service = "dns.googleapis.com" disable_on_destroy = false } # ─── Networking ─────────────────────────────────────────────────────── resource "google_compute_network" "main" { project = var.project_id name = "${var.prefix}-vpc" auto_create_subnetworks = false depends_on = [google_project_service.compute] } resource "google_compute_subnetwork" "main" { project = var.project_id name = "${var.prefix}-subnet" ip_cidr_range = "10.110.0.0/22" region = var.region network = google_compute_network.main.id secondary_ip_range { range_name = "pods" ip_cidr_range = "10.210.0.0/14" } secondary_ip_range { range_name = "services" ip_cidr_range = "10.214.0.0/20" } } # ─── GKE Cluster ────────────────────────────────────────────────────── resource "google_container_cluster" "main" { project = var.project_id name = "${var.prefix}-gke" location = var.region network = google_compute_network.main.id subnetwork = google_compute_subnetwork.main.id ip_allocation_policy { cluster_secondary_range_name = "pods" services_secondary_range_name = "services" } workload_identity_config { workload_pool = "${var.project_id}.svc.id.goog" } remove_default_node_pool = true initial_node_count = 1 deletion_protection = var.deletion_protection dynamic "release_channel" { for_each = var.kubernetes_version == null ? [1] : [] content { channel = "STABLE" } } resource_labels = var.labels depends_on = [google_project_service.container] } resource "google_container_node_pool" "main" { project = var.project_id name = "${var.prefix}-nodes" location = var.region cluster = google_container_cluster.main.name node_count = var.node_count node_config { machine_type = var.node_machine_type workload_metadata_config { mode = "GKE_METADATA" } oauth_scopes = [ "https://www.googleapis.com/auth/cloud-platform", ] labels = merge(var.labels, { role = "worker" }) } management { auto_repair = true auto_upgrade = true } } # ─── External-DNS Workload Identity ────────────────────────────────── # Allows external-dns to manage Cloud DNS records for app ingresses. resource "google_service_account" "external_dns" { project = var.project_id account_id = "${var.prefix}-external-dns" display_name = "External-DNS Service Account (Workload Identity)" depends_on = [google_project_service.iam] } resource "google_project_iam_member" "external_dns_dns_admin" { project = var.project_id role = "roles/dns.admin" member = "serviceAccount:${google_service_account.external_dns.email}" } resource "google_service_account_iam_member" "external_dns_workload_identity" { service_account_id = google_service_account.external_dns.name role = "roles/iam.workloadIdentityUser" member = "serviceAccount:${var.project_id}.svc.id.goog[external-dns/external-dns]" }