TerraformPilot

Terraform

GCP Cloud SQL with Terraform - MySQL and PostgreSQL

Deploy GCP Cloud SQL instances with Terraform. MySQL and PostgreSQL configuration, private networking, backups, replicas, and database user management.

LLuca Berton1 min read

Quick Answer

#
resource "google_sql_database_instance" "main" {
  name             = "my-db"
  database_version = "POSTGRES_15"
  region           = "us-central1"
  settings {
    tier = "db-f1-micro"
  }
  deletion_protection = false
}

Production PostgreSQL

#
resource "google_sql_database_instance" "postgres" {
  name                = "${var.project}-postgres"
  database_version    = "POSTGRES_15"
  region              = var.region
  deletion_protection = true
 
  settings {
    tier              = "db-custom-2-7680"  # 2 vCPU, 7.5 GB RAM
    availability_type = "REGIONAL"          # High availability
    disk_size         = 50
    disk_type         = "PD_SSD"
    disk_autoresize   = true
 
    ip_configuration {
      ipv4_enabled    = false              # No public IP
      private_network = google_compute_network.main.id
    }
 
    backup_configuration {
      enabled                        = true
      point_in_time_recovery_enabled = true
      start_time                     = "03:00"
      transaction_log_retention_days = 7
 
      backup_retention_settings {
        retained_backups = 30
      }
    }
 
    maintenance_window {
      day  = 7  # Sunday
      hour = 4
    }
 
    database_flags {
      name  = "log_min_duration_statement"
      value = "1000"  # Log queries > 1 second
    }
 
    insights_config {
      query_insights_enabled  = true
      record_application_tags = true
      record_client_address   = true
    }
  }
 
  depends_on = [google_service_networking_connection.private]
}
 
# Private Service Access
resource "google_compute_global_address" "private_ip" {
  name          = "${var.project}-db-ip"
  purpose       = "VPC_PEERING"
  address_type  = "INTERNAL"
  prefix_length = 16
  network       = google_compute_network.main.id
}
 
resource "google_service_networking_connection" "private" {
  network                 = google_compute_network.main.id
  service                 = "servicenetworking.googleapis.com"
  reserved_peering_ranges = [google_compute_global_address.private_ip.name]
}

Database and Users

#
resource "google_sql_database" "app" {
  name     = "myapp"
  instance = google_sql_database_instance.postgres.name
}
 
resource "random_password" "db" {
  length  = 32
  special = false
}
 
resource "google_sql_user" "app" {
  name     = "app"
  instance = google_sql_database_instance.postgres.name
  password = random_password.db.result
}
 
# Store password in Secret Manager
resource "google_secret_manager_secret" "db_password" {
  secret_id = "${var.project}-db-password"
  replication { auto {} }
}
 
resource "google_secret_manager_secret_version" "db_password" {
  secret      = google_secret_manager_secret.db_password.id
  secret_data = random_password.db.result
}

Read Replica

#
resource "google_sql_database_instance" "replica" {
  name                 = "${var.project}-postgres-replica"
  master_instance_name = google_sql_database_instance.postgres.name
  database_version     = "POSTGRES_15"
  region               = var.region
 
  replica_configuration {
    failover_target = false
  }
 
  settings {
    tier            = "db-custom-2-7680"
    disk_autoresize = true
 
    ip_configuration {
      ipv4_enabled    = false
      private_network = google_compute_network.main.id
    }
  }
}

Machine Type Tiers

#
TiervCPURAMUse Case
db-f1-microShared0.6 GBDev/test
db-g1-smallShared1.7 GBSmall apps
db-custom-2-768027.5 GBProduction
db-custom-4-15360415 GBHigh traffic
#

Conclusion

#

Use private networking (no public IP), regional availability for HA, automated backups with point-in-time recovery, and Secret Manager for passwords. Use db-custom-* tiers for production and read replicas for scaling read-heavy workloads.

#Terraform#GCP#Cloud SQL#Database#Infrastructure as Code

Share this article