Add Multi-Region support to cloud-run-v2 module (#4022)

* Add Multi-Region support to cloud-run-v2 module

* Support context expansion for multi_region_settings regions

* Fix multi_region_regions formatting line length
This commit is contained in:
Simone Ruffilli
2026-06-11 17:07:30 +02:00
committed by GitHub
parent d57c79ac92
commit a0987e189d
11 changed files with 329 additions and 19 deletions

View File

@@ -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
```
<!-- BEGIN TFDOC -->
## Variables
@@ -996,11 +1021,11 @@ module "worker" {
| [revision](variables.tf#L197) | Revision template configurations. | <code>object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> |
| [service_account_config](variables-serviceaccount.tf#L17) | Service account configurations. | <code>object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> |
| [service_config](variables.tf#L264) | Cloud Run service specific configuration options. | <code>object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> |
| [tag_bindings](variables.tf#L327) | Tag bindings for this service, in key => tag value id format. | <code>map&#40;string&#41;</code> | | <code>&#123;&#125;</code> |
| [type](variables.tf#L334) | Type of Cloud Run resource to deploy: JOB, SERVICE or WORKERPOOL. | <code>string</code> | | <code>&#34;SERVICE&#34;</code> |
| [volumes](variables.tf#L344) | Named volumes in containers in name => attributes format. | <code>map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [tag_bindings](variables.tf#L330) | Tag bindings for this service, in key => tag value id format. | <code>map&#40;string&#41;</code> | | <code>&#123;&#125;</code> |
| [type](variables.tf#L337) | Type of Cloud Run resource to deploy: JOB, SERVICE or WORKERPOOL. | <code>string</code> | | <code>&#34;SERVICE&#34;</code> |
| [volumes](variables.tf#L347) | Named volumes in containers in name => attributes format. | <code>map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [vpc_connector_create](variables-vpcconnector.tf#L17) | VPC connector network configuration. Must be provided if new VPC connector is being created. | <code>object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> |
| [workerpool_config](variables.tf#L378) | Cloud Run Worker Pool specific configuration. | <code>object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> |
| [workerpool_config](variables.tf#L381) | Cloud Run Worker Pool specific configuration. | <code>object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> |
## Outputs

View File

@@ -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}"

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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"]
}
}

View File

@@ -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__

View File

@@ -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: {}

View File

@@ -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"]
}
}

View File

@@ -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

View File

@@ -18,3 +18,5 @@ tests:
context-subnet:
context-subnet-project:
vpcconnector:
multiregion: