GCP Cloud Run with Terraform - Deploy Serverless Containers
Deploy Google Cloud Run services with Terraform. Container deployment, custom domains, traffic splitting, IAM, and VPC connector configuration.
Terraform
Deploy Google Cloud Functions with Terraform. HTTP and event-driven functions, Pub/Sub triggers, Cloud Storage triggers, VPC connectors, and IAM configuration.
resource "google_cloudfunctions2_function" "api" {
name = "my-function"
location = "us-central1"
build_config {
runtime = "nodejs20"
entry_point = "handler"
source {
storage_source {
bucket = google_storage_bucket.source.name
object = google_storage_bucket_object.source.name
}
}
}
service_config {
max_instance_count = 10
available_memory = "256M"
timeout_seconds = 60
}
}# Upload source code
data "archive_file" "source" {
type = "zip"
source_dir = "${path.module}/function-source"
output_path = "${path.module}/function-source.zip"
}
resource "google_storage_bucket" "source" {
name = "${var.project}-function-source"
location = var.region
uniform_bucket_level_access = true
}
resource "google_storage_bucket_object" "source" {
name = "function-source-${data.archive_file.source.output_md5}.zip"
bucket = google_storage_bucket.source.name
source = data.archive_file.source.output_path
}
resource "google_cloudfunctions2_function" "api" {
name = "${var.project}-api"
location = var.region
build_config {
runtime = "nodejs20"
entry_point = "handler"
source {
storage_source {
bucket = google_storage_bucket.source.name
object = google_storage_bucket_object.source.name
}
}
}
service_config {
max_instance_count = 100
min_instance_count = 1 # Keep warm
available_memory = "512M"
timeout_seconds = 300
max_instance_request_concurrency = 80
available_cpu = "1"
service_account_email = google_service_account.function.email
environment_variables = {
ENVIRONMENT = var.environment
PROJECT_ID = var.gcp_project
}
secret_environment_variables {
key = "API_KEY"
project_id = var.gcp_project
secret = google_secret_manager_secret.api_key.secret_id
version = "latest"
}
}
labels = { environment = var.environment }
}
# Public access
resource "google_cloud_run_service_iam_member" "public" {
location = google_cloudfunctions2_function.api.location
service = google_cloudfunctions2_function.api.name
role = "roles/run.invoker"
member = "allUsers"
}
output "function_url" {
value = google_cloudfunctions2_function.api.service_config[0].uri
}resource "google_pubsub_topic" "events" {
name = "${var.project}-events"
}
resource "google_cloudfunctions2_function" "processor" {
name = "${var.project}-processor"
location = var.region
build_config {
runtime = "python312"
entry_point = "process_event"
source {
storage_source {
bucket = google_storage_bucket.source.name
object = google_storage_bucket_object.source.name
}
}
}
service_config {
max_instance_count = 50
available_memory = "256M"
timeout_seconds = 120
service_account_email = google_service_account.function.email
}
event_trigger {
trigger_region = var.region
event_type = "google.cloud.pubsub.topic.v1.messagePublished"
pubsub_topic = google_pubsub_topic.events.id
retry_policy = "RETRY_POLICY_RETRY"
}
}resource "google_cloudfunctions2_function" "image_processor" {
name = "${var.project}-image-processor"
location = var.region
build_config {
runtime = "python312"
entry_point = "process_image"
source {
storage_source {
bucket = google_storage_bucket.source.name
object = google_storage_bucket_object.source.name
}
}
}
service_config {
max_instance_count = 20
available_memory = "1Gi"
timeout_seconds = 300
service_account_email = google_service_account.function.email
}
event_trigger {
trigger_region = var.region
event_type = "google.cloud.storage.object.v1.finalized"
retry_policy = "RETRY_POLICY_RETRY"
service_account_email = google_service_account.function.email
event_filters {
attribute = "bucket"
value = google_storage_bucket.uploads.name
}
}
}resource "google_service_account" "function" {
account_id = "${var.project}-function"
display_name = "Cloud Functions Service Account"
}
resource "google_project_iam_member" "function_secrets" {
project = var.gcp_project
role = "roles/secretmanager.secretAccessor"
member = "serviceAccount:${google_service_account.function.email}"
}| Feature | Gen 1 | Gen 2 |
|---|---|---|
| Concurrency | 1 request/instance | Up to 1000 |
| Timeout | 9 min (HTTP), 10 min (event) | 60 min |
| Instance size | 8 GB / 2 vCPU | 16 GB / 4 vCPU |
| Traffic splitting | No | Yes |
| Min instances | No | Yes |
| Terraform resource | google_cloudfunctions_function | google_cloudfunctions2_function |
Always use Gen 2 functions (google_cloudfunctions2_function) — they support concurrency, longer timeouts, traffic splitting, and are built on Cloud Run. Upload source via Cloud Storage with MD5 in the filename for automatic redeployment on code changes. Use dedicated service accounts with least-privilege IAM.
Deploy Google Cloud Run services with Terraform. Container deployment, custom domains, traffic splitting, IAM, and VPC connector configuration.
Deploy GCP Cloud SQL instances with Terraform. MySQL and PostgreSQL configuration, private networking, backups, replicas, and database user management.
Deploy Google Kubernetes Engine (GKE) clusters with Terraform. Autopilot and Standard modes, node pools, networking, and workload identity.
Deploy Google Cloud Pub/Sub with Terraform. Topics, subscriptions, push and pull delivery, dead-letter topics, message filtering, and BigQuery subscriptions.