Managing Cloud Spanner with Terraform

Learn how to set up and manage Google Cloud Spanner using Terraform

In this guide, we’ll explore how to manage Google Cloud Spanner using Terraform.

Video Tutorial

Learn more about managing Google Cloud Spanner with Terraform in this comprehensive video tutorial:

View Source Code

Prerequisites

  • Google Cloud SDK installed and configured
  • Terraform installed (version 1.0.0 or later)
  • A GCP project with billing enabled

Provider Configuration

terraform {
  required_providers {
    google = {
      source  = "hashicorp/google"
      version = "~> 4.0"
    }
  }
}

provider "google" {
  project = var.project_id
  region  = var.region
}

Variables

variable "project_id" {
  description = "The ID of the GCP project"
  type        = string
}

variable "region" {
  description = "The region to deploy resources to"
  type        = string
  default     = "us-central1"
}

variable "instance_name" {
  description = "Name of the Spanner instance"
  type        = string
}

variable "database_name" {
  description = "Name of the Spanner database"
  type        = string
}

Instance Configuration

resource "google_spanner_instance" "main" {
  name         = var.instance_name
  config       = "regional-${var.region}"
  display_name = "Main Spanner Instance"
  num_nodes    = 1

  labels = {
    environment = "production"
  }
}

resource "google_spanner_database" "database" {
  instance = google_spanner_instance.main.name
  name     = var.database_name
  ddl = [
    "CREATE TABLE users (user_id STRING(36) NOT NULL, name STRING(MAX), email STRING(MAX)) PRIMARY KEY (user_id)",
    "CREATE TABLE orders (order_id STRING(36) NOT NULL, user_id STRING(36) NOT NULL, amount FLOAT64, status STRING(MAX)) PRIMARY KEY (order_id)",
    "CREATE INDEX UserOrdersByAmount ON orders(user_id, amount DESC)",
  ]

  deletion_protection = true
}

IAM Configuration

resource "google_spanner_database_iam_binding" "database" {
  instance = google_spanner_instance.main.name
  database = google_spanner_database.database.name
  role     = "roles/spanner.databaseUser"

  members = [
    "serviceAccount:${google_service_account.spanner_user.email}",
  ]
}

resource "google_service_account" "spanner_user" {
  account_id   = "spanner-user"
  display_name = "Spanner User Service Account"
}

resource "google_project_iam_member" "spanner_viewer" {
  project = var.project_id
  role    = "roles/spanner.viewer"
  member  = "serviceAccount:${google_service_account.spanner_user.email}"
}

Backup Configuration

resource "google_spanner_backup" "backup" {
  instance = google_spanner_instance.main.name
  database = google_spanner_database.database.name
  backup   = "${var.database_name}-backup"
  expiration_seconds = 7 * 24 * 60 * 60  # 7 days

  lifecycle {
    prevent_destroy = true
  }
}

Instance Configuration with High Availability

resource "google_spanner_instance" "ha_instance" {
  name         = "${var.instance_name}-ha"
  config       = "regional-${var.region}"
  display_name = "HA Spanner Instance"
  num_nodes    = 3  # Minimum for high availability

  labels = {
    environment = "production"
    ha          = "true"
  }
}

resource "google_spanner_database" "ha_database" {
  instance = google_spanner_instance.ha_instance.name
  name     = "${var.database_name}-ha"
  
  version_retention_period = "7d"  # Keep 7 days of version history
  
  ddl = [
    "CREATE TABLE users (user_id STRING(36) NOT NULL, name STRING(MAX), email STRING(MAX)) PRIMARY KEY (user_id)",
    "CREATE TABLE orders (order_id STRING(36) NOT NULL, user_id STRING(36) NOT NULL, amount FLOAT64, status STRING(MAX)) PRIMARY KEY (order_id)",
    "CREATE INDEX UserOrdersByAmount ON orders(user_id, amount DESC)",
  ]

  deletion_protection = true

  encryption_config {
    kms_key_name = google_kms_crypto_key.spanner_key.id
  }
}

Monitoring Configuration

resource "google_monitoring_alert_policy" "spanner_cpu" {
  display_name = "Spanner CPU Usage Alert"
  combiner     = "OR"

  conditions {
    display_name = "High CPU Usage"
    condition_threshold {
      filter          = "metric.type=\"spanner.googleapis.com/instance/cpu/utilization\" AND resource.type=\"spanner_instance\""
      duration        = "300s"
      comparison     = "COMPARISON_GT"
      threshold_value = 0.8

      trigger {
        count = 1
      }

      aggregations {
        alignment_period   = "60s"
        per_series_aligner = "ALIGN_MEAN"
      }
    }
  }

  notification_channels = [google_monitoring_notification_channel.email.name]
}

Outputs

output "instance_id" {
  value       = google_spanner_instance.main.id
  description = "The ID of the Spanner instance"
}

output "database_id" {
  value       = google_spanner_database.database.id
  description = "The ID of the Spanner database"
}

output "instance_state" {
  value       = google_spanner_instance.main.state
  description = "The current state of the Spanner instance"
}

Best Practices

  1. Instance Management:

    • Right-size nodes
    • Enable high availability
    • Configure backups
    • Monitor performance
  2. Security:

    • Use IAM roles
    • Enable encryption
    • Regular audits
    • Secure connections
  3. Performance:

    • Optimize schemas
    • Monitor metrics
    • Use indexes
    • Regular maintenance
  4. Cost Optimization:

    • Monitor usage
    • Right-size instances
    • Clean up unused
    • Regular review

Common Operations

Creating Resources

terraform init
terraform plan
terraform apply

Database Operations

# Create backup
gcloud spanner backups create backup-name \
    --instance=instance-name \
    --database=database-name

# List backups
gcloud spanner backups list --instance=instance-name

Best Practices and Tips

  1. Schema Management:

    • Plan carefully
    • Use proper types
    • Create indexes
    • Regular review
  2. Backup Strategy:

    • Regular backups
    • Test restores
    • Monitor space
    • Retention policy
  3. Operations:

    • Monitor performance
    • Track metrics
    • Set up alerts
    • Regular maintenance

Conclusion

You’ve learned how to set up and manage Google Cloud Spanner using Terraform. This setup provides:

  • Scalable database
  • High availability
  • Data consistency
  • Best practices implementation