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!
Why always me?