Here’s a detailed and structured example using Terraform to create Infrastructure as Code (IaC) scripts for deploying your Kotlin application to Google Cloud Platform (GCP). Terraform is chosen over Google Deployment Manager because it is cloud-agnostic, widely adopted, easy to version-control, and powerful for managing infrastructure at scale.


πŸ“‚ Project Structure

terraform-gcp-deployment/
β”œβ”€β”€ main.tf
β”œβ”€β”€ variables.tf
β”œβ”€β”€ outputs.tf
β”œβ”€β”€ terraform.tfvars
β”œβ”€β”€ iam.tf
└── providers.tf

πŸ“Œ Step-by-Step IaC Setup


βœ… Step 1: providers.tf β€” Configure Terraform and Providers

This file defines the Terraform configuration and sets up Google Cloud Provider.

terraform {
  required_version = ">= 1.5"
  required_providers {
    google = {
      source  = "hashicorp/google"
      version = "~> 5.0"
    }
  }
}
 
provider "google" {
  project     = var.project_id
  region      = var.region
}

βœ… Step 2: iam.tf β€” IAM Configuration

# Cloud Run Invoker - Allows authenticated users to access Cloud Run service
resource "google_cloud_run_service_iam_member" "authenticated_invoker" {
  service  = google_cloud_run_service.app_service.name
  location = var.region
  role     = "roles/run.invoker"
  member   = "allAuthenticatedUsers"
}
 
# Service Account for Cloud Run to securely access Cloud SQL and Cloud Storage
resource "google_service_account" "cloud_run_service_account" {
  account_id   = "cloud-run-sa"
  display_name = "Service Account for Cloud Run Application"
}

βœ… Step 2: variables.tf β€” Define Terraform Variables

variable "project_id" {
  description = "Google Cloud Project ID"
  type        = string
}
 
variable "region" {
  description = "Default region for resources"
  type        = string
  default     = "us-central1"
}
 
variable "cloud_run_service_name" {
  description = "Name for Cloud Run service"
  type        = string
}
 
variable "docker_image_url" {
  description = "Container image URL to deploy"
  type        = string
}
 
variable "cloudsql_instance_name" {
  description = "Name for the Cloud SQL instance"
  type        = string
}
 
variable "cloudsql_database_name" {
  description = "Name for the Cloud SQL database"
  type        = string
}
 
variable "cloudsql_user" {
  description = "Database user name"
  type        = string
}
 
variable "cloudsql_password" {
  description = "Cloud SQL database password"
  type        = string
}
 
variable "bucket_name" {
  description = "Name for Cloud Storage bucket"
  type        = string
}

βœ… Step 3: terraform.tfvars β€” Populate your variables

project_id              = "your-gcp-project-id"
region                  = "us-central1"
cloudsql_instance_name  = "my-cloudsql-instance"
cloudsql_database_name  = "app_database"
cloudsql_user           = "app_user"
cloudsql_password       = "secure_password"
cloudsql_tier           = "db-custom-1-3840"
cloudsql_instance_tier  = "db-f1-micro"
cloudsql_version        = "POSTGRES_15"
cloudsql_disk_size      = 20
cloudsql_disk_type      = "PD_SSD"
cloudsql_user           = "dbuser"
docker_image            = "gcr.io/my-gcp-project-id/my-app-image:latest"
cloud_run_service_name  = "my-app-service"
bucket_name             = "my-app-storage-bucket"

βœ… Step 4: main.tf β€” Resource Definitions (Cloud SQL, Cloud Run, Storage, IAM)

Cloud SQL (PostgreSQL Instance):

resource "google_sql_database_instance" "postgres_instance" {
  name             = var.cloudsql_instance_name
  database_version = "POSTGRES_15"
  region          = var.region
 
  settings {
    tier = "db-custom-1-3840"  # Customize for cost optimization
    availability_type = "REGIONAL"  # HA setup
 
    disk_size  = 20
    disk_type  = "PD_SSD"
 
    backup_configuration {
      enabled = true
      point_in_time_recovery_enabled = true
    }
 
    ip_configuration {
      ipv4_enabled = false  # Secure using Private IP
      authorized_networks = []
    }
  }
}
 
resource "google_sql_database" "app_db" {
  name     = var.cloudsql_database_name
  instance = google_sql_database_instance.app_db_instance.name
}
 
resource "google_sql_user" "db_user" {
  name     = "dbuser"
  instance = google_sql_database_instance.app_db_instance.name
  password = "secure-db-password"
}

βœ… Step 4: main.tf β€” Cloud Storage & Cloud Run Configuration

resource "google_storage_bucket" "app_bucket" {
  name          = var.bucket_name
  location      = var.region
  storage_class = "STANDARD"
 
  lifecycle_rule {
    action {
      type = "Delete"
    }
    condition {
      age = 365  # Cleanup old objects after a year
    }
  }
}
 
# Cloud Run Service
resource "google_cloud_run_service" "app_service" {
  name     = var.cloud_run_service_name
  location = var.region
 
  template {
    spec {
      containers {
        image = var.docker_image
        resources {
          limits = {
            cpu    = "1"
            memory = "512Mi"
          }
    }
    env {
      name  = "DATABASE_URL"
      value = "jdbc:postgresql://${google_sql_database_instance.app_db_instance.private_ip_address}/${google_sql_database.app_db.name}"
    }
  }
 
  traffic {
    percent         = 100
    latest_revision = true
  }
}
 
# Cloud Run IAM Policy
resource "google_cloud_run_service_iam_member" "allow_invoker" {
  location = google_cloud_run_service.app_service.location
  project  = var.project_id
  service  = google_cloud_run_service.app_service.name
  role     = "roles/run.invoker"
  member   = "allUsers"  # Adjust to specific identities if restricted access
}

βœ… Step 4: outputs.tf β€” Helpful Output Variables

output "cloud_run_url" {
  description = "URL of the Cloud Run service"
  value       = google_cloud_run_service.app_service.status[0].url
}
 
output "cloud_sql_instance_connection_name" {
  description = "Connection string for Cloud SQL instance"
  value       = google_sql_database_instance.app_db_instance.connection_name
}
 
output "bucket_url" {
  description = "Bucket URL"
  value       = google_storage_bucket.app_bucket.url
}

πŸš€ Executing Terraform

Run the following commands to initialize, review, and apply your infrastructure:

terraform init
terraform plan
terraform apply

πŸ›‘οΈ Security Considerations

  • Use private IP addresses to isolate Cloud SQL access.
  • IAM roles: apply least privilege to Cloud Run and storage buckets.
  • Always manage secrets securely (e.g., Secret Manager or environment variables encrypted with Cloud KMS).

πŸš€ Why Terraform?

  • Idempotent and reproducible infrastructure
  • Easier to maintain and version control compared to Google Deployment Manager.
  • Better ecosystem and community support.

πŸš€ Performance Considerations

  • Keep Cloud Run container images lightweight (e.g., use Alpine-based images).
  • Cloud SQL: Regularly tune and monitor for query performance and indexing.
  • Utilize Google’s Cloud CDN for caching static assets from Cloud Storage, if needed.

πŸ’° Cost Optimization

  • Cloud Run: Adjust CPU/memory based on actual needs.
  • Cloud SQL: Opt for appropriate instance types and utilize SSD only if high IOPS are necessary.
  • Regularly audit unused resources.

βœ… Next Steps:

  • Set up CI/CD pipelines (e.g., Cloud Build or GitHub Actions) for automatic deployments.
  • Establish monitoring and alerting through Cloud Operations.

πŸš€ Summary:

By following these Terraform configurations, you’re establishing:

  • A scalable, secure, and cost-effective infrastructure.
  • Clearly defined roles and permissions using IAM.
  • Efficient resource usage leveraging managed GCP components.

If you’d like to extend or adjust any specific part of this configuration, let me know!