terraform-gcp

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Terraform GCP

Terraform 配置GCP基础设施

Provision and manage Google Cloud Platform infrastructure using Terraform with the
hashicorp/google
provider.
借助
hashicorp/google
provider,使用Terraform配置和管理Google Cloud Platform(GCP)基础设施。

When to Use

适用场景

  • Defining GCP infrastructure as code for repeatable, auditable deployments
  • Managing multi-environment setups (dev, staging, production) from a single codebase
  • Provisioning complex resource graphs (VPC + GKE + Cloud SQL + IAM) in one plan
  • Integrating infrastructure changes into CI/CD pipelines with plan/apply stages
  • 将GCP基础设施定义为代码,实现可重复、可审计的部署
  • 从单一代码库管理多环境配置(开发、预发布、生产)
  • 通过一个计划配置复杂的资源架构(VPC + GKE + Cloud SQL + IAM)
  • 将基础设施变更集成到包含计划/应用阶段的CI/CD流水线中

Prerequisites

前提条件

  • Terraform >= 1.5 installed
  • Google Cloud SDK or a service account key for CI
  • A GCP project with billing enabled
bash
gcloud auth application-default login          # local dev
export GOOGLE_APPLICATION_CREDENTIALS="sa.json" # CI/CD
terraform version
  • 已安装Terraform >= 1.5
  • 用于CI的Google Cloud SDK或服务账号密钥
  • 已启用计费的GCP项目
bash
gcloud auth application-default login          # local dev
export GOOGLE_APPLICATION_CREDENTIALS="sa.json" # CI/CD
terraform version

Provider Configuration

Provider配置

hcl
undefined
hcl
undefined

versions.tf

versions.tf

terraform { required_version = ">= 1.5" required_providers { google = { source = "hashicorp/google"; version = "> 5.0" } google-beta = { source = "hashicorp/google-beta"; version = "> 5.0" } } backend "gcs" { bucket = "my-project-tf-state"; prefix = "terraform/state" } }
provider "google" { project = var.project_id; region = var.region } provider "google-beta" { project = var.project_id; region = var.region }

```hcl
terraform { required_version = ">= 1.5" required_providers { google = { source = "hashicorp/google"; version = "> 5.0" } google-beta = { source = "hashicorp/google-beta"; version = "> 5.0" } } backend "gcs" { bucket = "my-project-tf-state"; prefix = "terraform/state" } }
provider "google" { project = var.project_id; region = var.region } provider "google-beta" { project = var.project_id; region = var.region }

```hcl

variables.tf

variables.tf

variable "project_id" { type = string } variable "region" { type = string; default = "us-central1" } variable "environment" { type = string validation { condition = contains(["dev", "staging", "production"], var.environment) error_message = "Must be dev, staging, or production." } }
undefined
variable "project_id" { type = string } variable "region" { type = string; default = "us-central1" } variable "environment" { type = string validation { condition = contains(["dev", "staging", "production"], var.environment) error_message = "Must be dev, staging, or production." } }
undefined

Project Setup and State Bucket

项目设置与状态存储桶

bash
gcloud storage buckets create gs://my-project-tf-state \
  --location=us-central1 --uniform-bucket-level-access --public-access-prevention
gcloud storage buckets update gs://my-project-tf-state --versioning

terraform init
terraform plan -var="project_id=my-project" -var="environment=production" -out=tfplan
terraform apply tfplan
hcl
resource "google_project_service" "apis" {
  for_each = toset([
    "compute.googleapis.com", "container.googleapis.com",
    "sqladmin.googleapis.com", "servicenetworking.googleapis.com",
    "cloudfunctions.googleapis.com", "run.googleapis.com",
    "secretmanager.googleapis.com", "artifactregistry.googleapis.com",
  ])
  project = var.project_id
  service = each.value
  disable_dependent_services = false
  disable_on_destroy         = false
}
bash
gcloud storage buckets create gs://my-project-tf-state \
  --location=us-central1 --uniform-bucket-level-access --public-access-prevention
gcloud storage buckets update gs://my-project-tf-state --versioning

terraform init
terraform plan -var="project_id=my-project" -var="environment=production" -out=tfplan
terraform apply tfplan
hcl
resource "google_project_service" "apis" {
  for_each = toset([
    "compute.googleapis.com", "container.googleapis.com",
    "sqladmin.googleapis.com", "servicenetworking.googleapis.com",
    "cloudfunctions.googleapis.com", "run.googleapis.com",
    "secretmanager.googleapis.com", "artifactregistry.googleapis.com",
  ])
  project = var.project_id
  service = each.value
  disable_dependent_services = false
  disable_on_destroy         = false
}

Networking Module

网络模块

hcl
undefined
hcl
undefined

modules/networking/main.tf

modules/networking/main.tf

resource "google_compute_network" "vpc" { name = "${var.environment}-vpc" auto_create_subnetworks = false routing_mode = "REGIONAL" }
resource "google_compute_subnetwork" "main" { name = "${var.environment}-main-subnet" ip_cidr_range = var.subnet_cidr region = var.region network = google_compute_network.vpc.id private_ip_google_access = true log_config { aggregation_interval = "INTERVAL_5_SEC"; flow_sampling = 0.5 } }
resource "google_compute_subnetwork" "gke" { name = "${var.environment}-gke-subnet" ip_cidr_range = var.gke_subnet_cidr region = var.region network = google_compute_network.vpc.id private_ip_google_access = true secondary_ip_range { range_name = "pods"; ip_cidr_range = var.pods_cidr } secondary_ip_range { range_name = "services"; ip_cidr_range = var.services_cidr } }
resource "google_compute_firewall" "allow_iap" { name = "${var.environment}-allow-iap" network = google_compute_network.vpc.name allow { protocol = "tcp"; ports = ["22", "3389"] } source_ranges = ["35.235.240.0/20"] }
resource "google_compute_router" "router" { name = "${var.environment}-router" region = var.region network = google_compute_network.vpc.id }
resource "google_compute_router_nat" "nat" { name = "${var.environment}-nat" router = google_compute_router.router.name region = var.region nat_ip_allocate_option = "AUTO_ONLY" source_subnetwork_ip_ranges_to_nat = "ALL_SUBNETWORKS_ALL_IP_RANGES" log_config { enable = true; filter = "ERRORS_ONLY" } }
output "vpc_id" { value = google_compute_network.vpc.id } output "gke_subnet_id" { value = google_compute_subnetwork.gke.id }
undefined
resource "google_compute_network" "vpc" { name = "${var.environment}-vpc" auto_create_subnetworks = false routing_mode = "REGIONAL" }
resource "google_compute_subnetwork" "main" { name = "${var.environment}-main-subnet" ip_cidr_range = var.subnet_cidr region = var.region network = google_compute_network.vpc.id private_ip_google_access = true log_config { aggregation_interval = "INTERVAL_5_SEC"; flow_sampling = 0.5 } }
resource "google_compute_subnetwork" "gke" { name = "${var.environment}-gke-subnet" ip_cidr_range = var.gke_subnet_cidr region = var.region network = google_compute_network.vpc.id private_ip_google_access = true secondary_ip_range { range_name = "pods"; ip_cidr_range = var.pods_cidr } secondary_ip_range { range_name = "services"; ip_cidr_range = var.services_cidr } }
resource "google_compute_firewall" "allow_iap" { name = "${var.environment}-allow-iap" network = google_compute_network.vpc.name allow { protocol = "tcp"; ports = ["22", "3389"] } source_ranges = ["35.235.240.0/20"] }
resource "google_compute_router" "router" { name = "${var.environment}-router" region = var.region network = google_compute_network.vpc.id }
resource "google_compute_router_nat" "nat" { name = "${var.environment}-nat" router = google_compute_router.router.name region = var.region nat_ip_allocate_option = "AUTO_ONLY" source_subnetwork_ip_ranges_to_nat = "ALL_SUBNETWORKS_ALL_IP_RANGES" log_config { enable = true; filter = "ERRORS_ONLY" } }
output "vpc_id" { value = google_compute_network.vpc.id } output "gke_subnet_id" { value = google_compute_subnetwork.gke.id }
undefined

GKE Cluster Module

GKE集群模块

hcl
undefined
hcl
undefined

modules/gke/main.tf

modules/gke/main.tf

resource "google_container_cluster" "primary" { name = "${var.environment}-cluster" location = var.region
release_channel { channel = var.release_channel } workload_identity_config { workload_pool = "${var.project_id}.svc.id.goog" } network = var.vpc_name subnetwork = var.gke_subnet_name
ip_allocation_policy { cluster_secondary_range_name = "pods" services_secondary_range_name = "services" } private_cluster_config { enable_private_nodes = true master_ipv4_cidr_block = "172.16.0.0/28" } network_policy { enabled = true } logging_config { enable_components = ["SYSTEM_COMPONENTS", "WORKLOADS"] } monitoring_config { enable_components = ["SYSTEM_COMPONENTS", "WORKLOADS"] managed_prometheus { enabled = true } }
remove_default_node_pool = true initial_node_count = 1 }
resource "google_container_node_pool" "primary" { name = "primary-pool" cluster = google_container_cluster.primary.name location = var.region
initial_node_count = var.initial_node_count autoscaling { min_node_count = var.min_nodes; max_node_count = var.max_nodes } management { auto_repair = true; auto_upgrade = true }
node_config { machine_type = var.machine_type disk_size_gb = 100 oauth_scopes = ["https://www.googleapis.com/auth/cloud-platform"] shielded_instance_config { enable_secure_boot = true; enable_integrity_monitoring = true } metadata = { disable-legacy-endpoints = "true" } } }
output "cluster_name" { value = google_container_cluster.primary.name } output "cluster_endpoint" { value = google_container_cluster.primary.endpoint; sensitive = true }
undefined
resource "google_container_cluster" "primary" { name = "${var.environment}-cluster" location = var.region
release_channel { channel = var.release_channel } workload_identity_config { workload_pool = "${var.project_id}.svc.id.goog" } network = var.vpc_name subnetwork = var.gke_subnet_name
ip_allocation_policy { cluster_secondary_range_name = "pods" services_secondary_range_name = "services" } private_cluster_config { enable_private_nodes = true master_ipv4_cidr_block = "172.16.0.0/28" } network_policy { enabled = true } logging_config { enable_components = ["SYSTEM_COMPONENTS", "WORKLOADS"] } monitoring_config { enable_components = ["SYSTEM_COMPONENTS", "WORKLOADS"] managed_prometheus { enabled = true } }
remove_default_node_pool = true initial_node_count = 1 }
resource "google_container_node_pool" "primary" { name = "primary-pool" cluster = google_container_cluster.primary.name location = var.region
initial_node_count = var.initial_node_count autoscaling { min_node_count = var.min_nodes; max_node_count = var.max_nodes } management { auto_repair = true; auto_upgrade = true }
node_config { machine_type = var.machine_type disk_size_gb = 100 oauth_scopes = ["https://www.googleapis.com/auth/cloud-platform"] shielded_instance_config { enable_secure_boot = true; enable_integrity_monitoring = true } metadata = { disable-legacy-endpoints = "true" } } }
output "cluster_name" { value = google_container_cluster.primary.name } output "cluster_endpoint" { value = google_container_cluster.primary.endpoint; sensitive = true }
undefined

Cloud SQL Module

Cloud SQL模块

hcl
undefined
hcl
undefined

modules/cloud-sql/main.tf

modules/cloud-sql/main.tf

resource "google_sql_database_instance" "main" { name = "${var.environment}-db" database_version = var.database_version region = var.region
settings { tier = var.tier availability_type = var.environment == "production" ? "REGIONAL" : "ZONAL" disk_type = "PD_SSD" disk_size = var.disk_size disk_autoresize = true
backup_configuration {
  enabled                        = true
  start_time                     = "02:00"
  point_in_time_recovery_enabled = true
  backup_retention_settings { retained_backups = var.environment == "production" ? 30 : 7 }
}
ip_configuration {
  ipv4_enabled    = false
  private_network = var.vpc_id
  require_ssl     = true
}
database_flags { name = "max_connections"; value = var.max_connections }
}
deletion_protection = var.environment == "production" depends_on = [var.private_vpc_connection] }
resource "google_sql_database" "app" { name = var.database_name; instance = google_sql_database_instance.main.name } resource "google_sql_user" "app" { name = var.db_user; instance = google_sql_database_instance.main.name; password = random_password.db.result } resource "random_password" "db" { length = 32; special = true }
output "connection_name" { value = google_sql_database_instance.main.connection_name } output "private_ip" { value = google_sql_database_instance.main.private_ip_address }
undefined
resource "google_sql_database_instance" "main" { name = "${var.environment}-db" database_version = var.database_version region = var.region
settings { tier = var.tier availability_type = var.environment == "production" ? "REGIONAL" : "ZONAL" disk_type = "PD_SSD" disk_size = var.disk_size disk_autoresize = true
backup_configuration {
  enabled                        = true
  start_time                     = "02:00"
  point_in_time_recovery_enabled = true
  backup_retention_settings { retained_backups = var.environment == "production" ? 30 : 7 }
}
ip_configuration {
  ipv4_enabled    = false
  private_network = var.vpc_id
  require_ssl     = true
}
database_flags { name = "max_connections"; value = var.max_connections }
}
deletion_protection = var.environment == "production" depends_on = [var.private_vpc_connection] }
resource "google_sql_database" "app" { name = var.database_name; instance = google_sql_database_instance.main.name } resource "google_sql_user" "app" { name = var.db_user; instance = google_sql_database_instance.main.name; password = random_password.db.result } resource "random_password" "db" { length = 32; special = true }
output "connection_name" { value = google_sql_database_instance.main.connection_name } output "private_ip" { value = google_sql_database_instance.main.private_ip_address }
undefined

IAM and Service Accounts

IAM与服务账号

hcl
resource "google_service_account" "gke_nodes" {
  account_id   = "${var.environment}-gke-nodes"
  display_name = "GKE Node Pool SA"
}

resource "google_project_iam_member" "gke_nodes" {
  for_each = toset([
    "roles/logging.logWriter", "roles/monitoring.metricWriter",
    "roles/artifactregistry.reader",
  ])
  project = var.project_id
  role    = each.value
  member  = "serviceAccount:${google_service_account.gke_nodes.email}"
}

resource "google_service_account" "app" {
  account_id   = "${var.environment}-app"
  display_name = "Application SA"
}

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[myapp/app-ksa]"
}
hcl
resource "google_service_account" "gke_nodes" {
  account_id   = "${var.environment}-gke-nodes"
  display_name = "GKE Node Pool SA"
}

resource "google_project_iam_member" "gke_nodes" {
  for_each = toset([
    "roles/logging.logWriter", "roles/monitoring.metricWriter",
    "roles/artifactregistry.reader",
  ])
  project = var.project_id
  role    = each.value
  member  = "serviceAccount:${google_service_account.gke_nodes.email}"
}

resource "google_service_account" "app" {
  account_id   = "${var.environment}-app"
  display_name = "Application SA"
}

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[myapp/app-ksa]"
}

Root Module Composition

根模块组合

hcl
module "networking" {
  source      = "./modules/networking"
  project_id  = var.project_id
  environment = var.environment
  region      = var.region
}

module "gke" {
  source          = "./modules/gke"
  project_id      = var.project_id
  environment     = var.environment
  region          = var.region
  vpc_name        = module.networking.vpc_id
  gke_subnet_name = module.networking.gke_subnet_id
  node_sa_email   = google_service_account.gke_nodes.email
  depends_on      = [module.networking]
}

module "database" {
  source               = "./modules/cloud-sql"
  project_id           = var.project_id
  environment          = var.environment
  region               = var.region
  vpc_id               = module.networking.vpc_id
  database_version     = "POSTGRES_16"
  tier                 = "db-custom-4-16384"
  private_vpc_connection = module.networking.private_vpc_connection
  depends_on           = [module.networking]
}
hcl
module "networking" {
  source      = "./modules/networking"
  project_id  = var.project_id
  environment = var.environment
  region      = var.region
}

module "gke" {
  source          = "./modules/gke"
  project_id      = var.project_id
  environment     = var.environment
  region          = var.region
  vpc_name        = module.networking.vpc_id
  gke_subnet_name = module.networking.gke_subnet_id
  node_sa_email   = google_service_account.gke_nodes.email
  depends_on      = [module.networking]
}

module "database" {
  source               = "./modules/cloud-sql"
  project_id           = var.project_id
  environment          = var.environment
  region               = var.region
  vpc_id               = module.networking.vpc_id
  database_version     = "POSTGRES_16"
  tier                 = "db-custom-4-16384"
  private_vpc_connection = module.networking.private_vpc_connection
  depends_on           = [module.networking]
}

Environment Configuration

环境配置

hcl
undefined
hcl
undefined

environments/production.tfvars

environments/production.tfvars

project_id = "my-company-prod" environment = "production" region = "us-central1"

```bash
terraform plan -var-file=environments/production.tfvars -out=tfplan
terraform apply tfplan
project_id = "my-company-prod" environment = "production" region = "us-central1"

```bash
terraform plan -var-file=environments/production.tfvars -out=tfplan
terraform apply tfplan

CI/CD Integration

CI/CD集成

bash
terraform init -input=false
terraform validate && terraform fmt -check
terraform plan -var-file=environments/${ENV}.tfvars -out=tfplan -input=false
terraform apply -input=false tfplan
bash
terraform init -input=false
terraform validate && terraform fmt -check
terraform plan -var-file=environments/${ENV}.tfvars -out=tfplan -input=false
terraform apply -input=false tfplan

Import existing resources

Import existing resources

terraform import google_compute_network.vpc projects/${PROJECT_ID}/global/networks/prod-vpc
terraform import google_compute_network.vpc projects/${PROJECT_ID}/global/networks/prod-vpc

State management

State management

terraform state list terraform state mv google_compute_instance.old google_compute_instance.new
undefined
terraform state list terraform state mv google_compute_instance.old google_compute_instance.new
undefined

Troubleshooting

故障排查

SymptomCauseFix
Error 403: Access Not Configured
API not enabledAdd API to
google_project_service
resources
Error acquiring the state lock
Concurrent run or stale lockRun
terraform force-unlock LOCK_ID
after verification
Resource already exists
Created outside TerraformImport with
terraform import
Quota exceeded
Project quota too lowRequest increase in Cloud Console > Quotas
Plan shows destroy/recreateChanged force-new attributeUse
moved
blocks or
terraform state mv
Backend initialization required
Changed backend configRun
terraform init -migrate-state
Cycle in resource graphCircular referencesRefactor with data sources; split applies
症状原因解决方法
Error 403: Access Not Configured
API未启用将API添加到
google_project_service
资源中
Error acquiring the state lock
并发运行或锁已过期验证后执行
terraform force-unlock LOCK_ID
Resource already exists
资源在Terraform外部创建使用
terraform import
导入资源
Quota exceeded
项目配额不足在Cloud Console > 配额页面申请提升配额
计划显示销毁/重建修改了强制重建属性使用
moved
块或
terraform state mv
命令
Backend initialization required
后端配置已更改执行
terraform init -migrate-state
资源图存在循环依赖存在循环引用使用数据源重构;拆分应用步骤

Related Skills

相关技能

  • gcp-networking - VPC and firewall resources managed by Terraform
  • gcp-gke - GKE cluster provisioning with Terraform modules
  • gcp-cloud-sql - Cloud SQL instance management via Terraform
  • gcp-compute - Compute Engine resources defined in Terraform
  • gcp-cloud-functions - Serverless function deployment with Terraform
  • gcp-networking - 通过Terraform管理VPC和防火墙资源
  • gcp-gke - 使用Terraform模块配置GKE集群
  • gcp-cloud-sql - 通过Terraform管理Cloud SQL实例
  • gcp-compute - 在Terraform中定义Compute Engine资源
  • gcp-cloud-functions - 使用Terraform部署无服务器函数