diff --git a/modules/cloud-run-v2/README.md b/modules/cloud-run-v2/README.md
index 330fd0258..72c79fdfa 100644
--- a/modules/cloud-run-v2/README.md
+++ b/modules/cloud-run-v2/README.md
@@ -21,6 +21,7 @@ Cloud Run Services and Jobs, with support for IAM roles and Eventarc trigger cre
- [Tag bindings](#tag-bindings)
- [IAP Configuration](#iap-configuration)
- [Adding GPUs](#adding-gpus)
+- [Multi-Region Service](#multi-region-service)
- [Variables](#variables)
- [Outputs](#outputs)
- [Fixtures](#fixtures)
@@ -976,6 +977,30 @@ module "worker" {
}
# tftest inventory=gpu-workerpool.yaml e2e
```
+
+## Multi-Region Service
+
+```hcl
+module "cloud_run" {
+ source = "./fabric/modules/cloud-run-v2"
+ project_id = var.project_id
+ region = "global"
+ name = "example-mr"
+ containers = {
+ hello = {
+ image = "us-docker.pkg.dev/cloudrun/container/hello"
+ }
+ }
+ service_config = {
+ ingress = "INGRESS_TRAFFIC_INTERNAL_LOAD_BALANCER"
+ multi_region_settings = {
+ regions = ["europe-west8", "europe-west1"]
+ }
+ }
+ deletion_protection = false
+}
+# tftest inventory=multiregion.yaml
+```
## Variables
@@ -996,11 +1021,11 @@ module "worker" {
| [revision](variables.tf#L197) | Revision template configurations. | object({…}) | | {} |
| [service_account_config](variables-serviceaccount.tf#L17) | Service account configurations. | object({…}) | | {} |
| [service_config](variables.tf#L264) | Cloud Run service specific configuration options. | object({…}) | | {} |
-| [tag_bindings](variables.tf#L327) | Tag bindings for this service, in key => tag value id format. | map(string) | | {} |
-| [type](variables.tf#L334) | Type of Cloud Run resource to deploy: JOB, SERVICE or WORKERPOOL. | string | | "SERVICE" |
-| [volumes](variables.tf#L344) | Named volumes in containers in name => attributes format. | map(object({…})) | | {} |
+| [tag_bindings](variables.tf#L330) | Tag bindings for this service, in key => tag value id format. | map(string) | | {} |
+| [type](variables.tf#L337) | Type of Cloud Run resource to deploy: JOB, SERVICE or WORKERPOOL. | string | | "SERVICE" |
+| [volumes](variables.tf#L347) | Named volumes in containers in name => attributes format. | map(object({…})) | | {} |
| [vpc_connector_create](variables-vpcconnector.tf#L17) | VPC connector network configuration. Must be provided if new VPC connector is being created. | object({…}) | | null |
-| [workerpool_config](variables.tf#L378) | Cloud Run Worker Pool specific configuration. | object({…}) | | {} |
+| [workerpool_config](variables.tf#L381) | Cloud Run Worker Pool specific configuration. | object({…}) | | {} |
## Outputs
diff --git a/modules/cloud-run-v2/main.tf b/modules/cloud-run-v2/main.tf
index 82c3dae66..4333ca5a2 100644
--- a/modules/cloud-run-v2/main.tf
+++ b/modules/cloud-run-v2/main.tf
@@ -45,6 +45,14 @@ locals {
location = lookup(local.ctx.locations, var.region, var.region)
project_id = lookup(local.ctx.project_ids, var.project_id, var.project_id)
+ multi_region_regions = (
+ try(var.service_config.multi_region_settings.regions, null) == null
+ ? null
+ : [
+ for r in var.service_config.multi_region_settings.regions :
+ lookup(local.ctx.locations, r, r)
+ ]
+ )
revision_name = (
var.revision.name == null ? null : "${var.name}-${var.revision.name}"
diff --git a/modules/cloud-run-v2/service-managed.tf b/modules/cloud-run-v2/service-managed.tf
index a6078c13d..06a7a7c1a 100644
--- a/modules/cloud-run-v2/service-managed.tf
+++ b/modules/cloud-run-v2/service-managed.tf
@@ -28,6 +28,13 @@ resource "google_cloud_run_v2_service" "service" {
deletion_protection = var.deletion_protection
iap_enabled = var.service_config.iap_config != null
+ dynamic "multi_region_settings" {
+ for_each = local.multi_region_regions == null ? [] : [""]
+ content {
+ regions = local.multi_region_regions
+ }
+ }
+
template {
labels = var.revision.labels
encryption_key = var.encryption_key
diff --git a/modules/cloud-run-v2/service-unmanaged.tf b/modules/cloud-run-v2/service-unmanaged.tf
index 033004330..800e013f4 100644
--- a/modules/cloud-run-v2/service-unmanaged.tf
+++ b/modules/cloud-run-v2/service-unmanaged.tf
@@ -28,6 +28,13 @@ resource "google_cloud_run_v2_service" "service_unmanaged" {
deletion_protection = var.deletion_protection
iap_enabled = var.service_config.iap_config != null
+ dynamic "multi_region_settings" {
+ for_each = local.multi_region_regions == null ? [] : [""]
+ content {
+ regions = local.multi_region_regions
+ }
+ }
+
template {
labels = var.revision.labels
encryption_key = var.encryption_key
diff --git a/modules/cloud-run-v2/variables.tf b/modules/cloud-run-v2/variables.tf
index 5d74fc09f..01e25e514 100644
--- a/modules/cloud-run-v2/variables.tf
+++ b/modules/cloud-run-v2/variables.tf
@@ -286,6 +286,9 @@ variable "service_config" {
ingress = optional(string, null)
invoker_iam_disabled = optional(bool, false)
max_concurrency = optional(number)
+ multi_region_settings = optional(object({
+ regions = list(string)
+ }), null)
scaling = optional(object({
max_instance_count = optional(number)
min_instance_count = optional(number)
diff --git a/tests/modules/cloud_run_v2/context.tfvars b/tests/modules/cloud_run_v2/context.tfvars
index bf19aeb91..7a97d4161 100644
--- a/tests/modules/cloud_run_v2/context.tfvars
+++ b/tests/modules/cloud_run_v2/context.tfvars
@@ -67,3 +67,9 @@ tag_bindings = {
baz = "$tag_values:test/one"
foo = "$${projects[\"test-00\"].test}/cc-123"
}
+service_config = {
+ multi_region_settings = {
+ regions = ["$locations:ew8", "europe-west1"]
+ }
+}
+
diff --git a/tests/modules/cloud_run_v2/context.yaml b/tests/modules/cloud_run_v2/context.yaml
index bdfbec77d..1f112329d 100644
--- a/tests/modules/cloud_run_v2/context.yaml
+++ b/tests/modules/cloud_run_v2/context.yaml
@@ -1,10 +1,10 @@
-# Copyright 2025 Google LLC
+# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
@@ -21,6 +21,7 @@ values:
client_version: null
custom_audiences: null
default_uri_disabled: null
+ deletion_policy: DELETE
deletion_protection: true
description: null
effective_labels:
@@ -29,7 +30,10 @@ values:
invoker_iam_disabled: false
labels: null
location: europe-west8
- multi_region_settings: []
+ multi_region_settings:
+ - regions:
+ - europe-west8
+ - europe-west1
name: test-run-context
project: foo-test-0
template:
@@ -38,6 +42,7 @@ values:
encryption_key: null
execution_environment: EXECUTION_ENVIRONMENT_GEN1
gpu_zonal_redundancy_disabled: null
+ health_check_disabled: null
labels: null
node_selector: []
revision: null
@@ -61,6 +66,7 @@ values:
google_service_account.service_account[0]:
account_id: test-run-context
create_ignore_already_exists: null
+ deletion_policy: DELETE
description: null
disabled: false
display_name: test-run-context
@@ -68,7 +74,23 @@ values:
member: serviceAccount:test-run-context@foo-test-0.iam.gserviceaccount.com
project: foo-test-0
timeouts: null
+ google_tags_location_tag_binding.binding["bar"]:
+ deletion_policy: DELETE
+ location: europe-west8
+ tag_value: tagValues/1234567891
+ timeouts: null
+ google_tags_location_tag_binding.binding["baz"]:
+ deletion_policy: DELETE
+ location: europe-west8
+ tag_value: tagValues/1234567890
+ timeouts: null
+ google_tags_location_tag_binding.binding["foo"]:
+ deletion_policy: DELETE
+ location: europe-west8
+ tag_value: foo-test-0/dynamic_test/cc-123
+ timeouts: null
google_vpc_access_connector.connector[0]:
+ deletion_policy: DELETE
ip_cidr_range: 10.10.20.0/28
machine_type: e2-micro
max_instances: 10
@@ -79,21 +101,27 @@ values:
region: europe-west8
subnet: []
timeouts: null
- google_tags_location_tag_binding.binding["bar"]:
- location: europe-west8
- tag_value: tagValues/1234567891
- timeouts: null
- google_tags_location_tag_binding.binding["baz"]:
- location: europe-west8
- tag_value: tagValues/1234567890
- timeouts: null
- google_tags_location_tag_binding.binding["foo"]:
- location: europe-west8
- tag_value: foo-test-0/dynamic_test/cc-123
- timeouts: null
counts:
google_cloud_run_v2_service: 1
google_cloud_run_v2_service_iam_binding: 1
+ google_project_iam_member: 1
+ google_service_account: 1
google_tags_location_tag_binding: 3
google_vpc_access_connector: 1
+ modules: 0
+ resources: 8
+
+outputs:
+ id: __missing__
+ invoke_command: __missing__
+ job: null
+ resource: __missing__
+ resource_name: __missing__
+ service: __missing__
+ service_account: __missing__
+ service_account_email: test-run-context@foo-test-0.iam.gserviceaccount.com
+ service_account_iam_email: serviceAccount:test-run-context@foo-test-0.iam.gserviceaccount.com
+ service_name: __missing__
+ service_uri: __missing__
+ vpc_connector: __missing__
diff --git a/tests/modules/cloud_run_v2/examples/multiregion.yaml b/tests/modules/cloud_run_v2/examples/multiregion.yaml
new file mode 100644
index 000000000..1a109699e
--- /dev/null
+++ b/tests/modules/cloud_run_v2/examples/multiregion.yaml
@@ -0,0 +1,99 @@
+# Copyright 2026 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+values:
+ module.cloud_run.google_cloud_run_v2_service.service[0]:
+ annotations: null
+ binary_authorization: []
+ build_config: []
+ client: null
+ client_version: null
+ custom_audiences: null
+ default_uri_disabled: null
+ deletion_policy: DELETE
+ deletion_protection: false
+ description: null
+ effective_labels:
+ goog-terraform-provisioned: 'true'
+ iap_enabled: false
+ ingress: INGRESS_TRAFFIC_INTERNAL_LOAD_BALANCER
+ invoker_iam_disabled: false
+ labels: null
+ location: global
+ multi_region_settings:
+ - regions:
+ - europe-west8
+ - europe-west1
+ name: example-mr
+ project: project-id
+ template:
+ - annotations: null
+ containers:
+ - args: null
+ base_image_uri: null
+ command: null
+ depends_on: null
+ env: []
+ image: us-docker.pkg.dev/cloudrun/container/hello
+ liveness_probe: []
+ name: hello
+ readiness_probe: []
+ source_code: []
+ volume_mounts: []
+ working_dir: null
+ encryption_key: null
+ execution_environment: EXECUTION_ENVIRONMENT_GEN1
+ gpu_zonal_redundancy_disabled: null
+ health_check_disabled: null
+ labels: null
+ node_selector: []
+ revision: null
+ service_account: example-mr@project-id.iam.gserviceaccount.com
+ service_mesh: []
+ session_affinity: null
+ volumes: []
+ vpc_access: []
+ terraform_labels:
+ goog-terraform-provisioned: 'true'
+ timeouts: null
+ module.cloud_run.google_project_iam_member.default["roles/logging.logWriter"]:
+ condition: []
+ member: serviceAccount:example-mr@project-id.iam.gserviceaccount.com
+ project: project-id
+ role: roles/logging.logWriter
+ module.cloud_run.google_project_iam_member.default["roles/monitoring.metricWriter"]:
+ condition: []
+ member: serviceAccount:example-mr@project-id.iam.gserviceaccount.com
+ project: project-id
+ role: roles/monitoring.metricWriter
+ module.cloud_run.google_service_account.service_account[0]:
+ account_id: example-mr
+ create_ignore_already_exists: null
+ deletion_policy: DELETE
+ description: null
+ disabled: false
+ display_name: example-mr
+ email: example-mr@project-id.iam.gserviceaccount.com
+ member: serviceAccount:example-mr@project-id.iam.gserviceaccount.com
+ project: project-id
+ timeouts: null
+
+counts:
+ google_cloud_run_v2_service: 1
+ google_project_iam_member: 2
+ google_service_account: 1
+ modules: 1
+ resources: 4
+
+outputs: {}
diff --git a/tests/modules/cloud_run_v2/multiregion.tfvars b/tests/modules/cloud_run_v2/multiregion.tfvars
new file mode 100644
index 000000000..f6ae25a66
--- /dev/null
+++ b/tests/modules/cloud_run_v2/multiregion.tfvars
@@ -0,0 +1,15 @@
+name = "test-run-multiregion"
+project_id = "test-project"
+region = "global"
+
+containers = {
+ first = {
+ image = "gcr.io/cloudrun/hello"
+ }
+}
+
+service_config = {
+ multi_region_settings = {
+ regions = ["europe-west8", "europe-west1"]
+ }
+}
diff --git a/tests/modules/cloud_run_v2/multiregion.yaml b/tests/modules/cloud_run_v2/multiregion.yaml
new file mode 100644
index 000000000..11d3a1abe
--- /dev/null
+++ b/tests/modules/cloud_run_v2/multiregion.yaml
@@ -0,0 +1,110 @@
+# Copyright 2026 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+values:
+ google_cloud_run_v2_service.service[0]:
+ annotations: null
+ binary_authorization: []
+ build_config: []
+ client: null
+ client_version: null
+ custom_audiences: null
+ default_uri_disabled: null
+ deletion_policy: DELETE
+ deletion_protection: true
+ description: null
+ effective_labels:
+ goog-terraform-provisioned: 'true'
+ iap_enabled: false
+ invoker_iam_disabled: false
+ labels: null
+ location: global
+ multi_region_settings:
+ - regions:
+ - europe-west8
+ - europe-west1
+ name: test-run-multiregion
+ project: test-project
+ template:
+ - annotations: null
+ containers:
+ - args: null
+ base_image_uri: null
+ command: null
+ depends_on: null
+ env: []
+ image: gcr.io/cloudrun/hello
+ liveness_probe: []
+ name: first
+ readiness_probe: []
+ source_code: []
+ volume_mounts: []
+ working_dir: null
+ encryption_key: null
+ execution_environment: EXECUTION_ENVIRONMENT_GEN1
+ gpu_zonal_redundancy_disabled: null
+ health_check_disabled: null
+ labels: null
+ node_selector: []
+ revision: null
+ service_account: test-run-multiregion@test-project.iam.gserviceaccount.com
+ service_mesh: []
+ session_affinity: null
+ volumes: []
+ vpc_access: []
+ terraform_labels:
+ goog-terraform-provisioned: 'true'
+ timeouts: null
+ google_project_iam_member.default["roles/logging.logWriter"]:
+ condition: []
+ member: serviceAccount:test-run-multiregion@test-project.iam.gserviceaccount.com
+ project: test-project
+ role: roles/logging.logWriter
+ google_project_iam_member.default["roles/monitoring.metricWriter"]:
+ condition: []
+ member: serviceAccount:test-run-multiregion@test-project.iam.gserviceaccount.com
+ project: test-project
+ role: roles/monitoring.metricWriter
+ google_service_account.service_account[0]:
+ account_id: test-run-multiregion
+ create_ignore_already_exists: null
+ deletion_policy: DELETE
+ description: null
+ disabled: false
+ display_name: test-run-multiregion
+ email: test-run-multiregion@test-project.iam.gserviceaccount.com
+ member: serviceAccount:test-run-multiregion@test-project.iam.gserviceaccount.com
+ project: test-project
+ timeouts: null
+
+counts:
+ google_cloud_run_v2_service: 1
+ google_project_iam_member: 2
+ google_service_account: 1
+ modules: 0
+ resources: 4
+
+outputs:
+ id: __missing__
+ invoke_command: __missing__
+ job: null
+ resource: __missing__
+ resource_name: __missing__
+ service: __missing__
+ service_account: __missing__
+ service_account_email: test-run-multiregion@test-project.iam.gserviceaccount.com
+ service_account_iam_email: serviceAccount:test-run-multiregion@test-project.iam.gserviceaccount.com
+ service_name: __missing__
+ service_uri: __missing__
+ vpc_connector: null
diff --git a/tests/modules/cloud_run_v2/tftest.yaml b/tests/modules/cloud_run_v2/tftest.yaml
index cf724f5f0..c413d43f1 100644
--- a/tests/modules/cloud_run_v2/tftest.yaml
+++ b/tests/modules/cloud_run_v2/tftest.yaml
@@ -18,3 +18,5 @@ tests:
context-subnet:
context-subnet-project:
vpcconnector:
+ multiregion:
+