diff --git a/README.md b/README.md
index 44aeac172..d29981edf 100644
--- a/README.md
+++ b/README.md
@@ -63,6 +63,7 @@ module "cloud_run" {
| force\_override | Option to force override existing mapping | `bool` | `false` | no |
| generate\_revision\_name | Option to enable revision name generation | `bool` | `true` | no |
| image | GCR hosted image URL to deploy | `string` | n/a | yes |
+| ingress | Restricts network access to your Cloud Run service | `string` | `"INGRESS_TRAFFIC_ALL"` | no |
| limits | Resource limits to the container | `map(string)` | `null` | no |
| liveness\_probe | Periodic probe of container liveness. Container will be restarted if the probe fails.
More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes |
object({
failure_threshold = optional(number, null)
initial_delay_seconds = optional(number, null)
timeout_seconds = optional(number, null)
period_seconds = optional(number, null)
http_get = optional(object({
path = optional(string)
http_headers = optional(list(object({
name = string
value = string
})), null)
}), null)
grpc = optional(object({
port = optional(number)
service = optional(string)
}), null)
}) | `null` | no |
| location | Cloud Run service deployment location | `string` | n/a | yes |
@@ -82,6 +83,8 @@ module "cloud_run" {
| verified\_domain\_name | List of Custom Domain Name | `list(string)` | `[]` | no |
| volume\_mounts | [Beta] Volume Mounts to be attached to the container (when using secret) | list(object({
mount_path = string
name = string
})) | `[]` | no |
| volumes | [Beta] Volumes needed for environment variables (when using secret) | list(object({
name = string
secret = set(object({
secret_name = string
items = map(string)
}))
})) | `[]` | no |
+| vpc\_connector | The full resource name of the VPC Access connector to use. Leave null to use Direct VPC Egress. | `string` | `null` | no |
+| vpc\_egress | The outbound traffic setting for VPC. Use 'PRIVATE\_RANGES\_ONLY' with a connector. Use 'ALL\_TRAFFIC' for Direct VPC Egress. Set to null to disable all VPC egress. | `string` | `"ALL_TRAFFIC"` | no |
## Outputs
diff --git a/examples/v2_multi_regions/README.md b/examples/v2_multi_regions/README.md
index bc14ca762..e0e089adb 100644
--- a/examples/v2_multi_regions/README.md
+++ b/examples/v2_multi_regions/README.md
@@ -1,13 +1,18 @@
# Cloud Run Service using v2 API and multi-regions Example
-This example showcases the basic deployment of containerized applications on Cloud Run and IAM policy for the service in multi-regions.
+This example showcases the basic deployment of containerized applications on Cloud Run and IAM policy for the service in multi-regions. It allows for the optional provisioning of a Global Load Balancer for traffic distribution and SSL termination depending on the configuration.
The resources/services/activations/deletions that this example will create/trigger are:
* Deploys a Cloud Run V2 service across multiple regions.
* Creates a Service Account to be used by Cloud Run Service.
-* Creates a Serverless VPC Access Connectors per region.
-* Cloud Run -> VPC integration through regional connectors.
+* Creates Serverless VPC Access Connectors per region (or configures Direct VPC Egress).
+* **If `enable_load_balancer` is set to `true`:**
+ * Reserves a Global Static IP Address (if not provided).
+ * Creates Serverless Network Endpoint Groups (NEGs) per region to bridge the Load Balancer and Cloud Run.
+ * Provisions a Global External Application Load Balancer (HTTP/S) with URL Maps and Backend Services.
+ * Sets up Google-managed SSL Certificates for secure HTTPS access.
+ * Configures outlier detection to handle failover between regions automatically.
## Assumptions and Prerequisites
@@ -15,26 +20,99 @@ This example assumes that below mentioned prerequisites are in place before cons
* All required APIs are enabled in the GCP Project
+## Usage
+
+- Rename the `tfvars` file by running `mv terraform.tfvars.example terraform.tfvars` and update `terraform.tfvars` with values from your environment.
+
+ ```bash
+ mv terraform.tfvars.example terraform.tfvars
+ ```
+
+- Run `terraform init` to get the plugins.
+
+ ```bash
+ terraform init
+ ```
+
+- Run `terraform plan` and review the plan.
+
+ ```bash
+ terraform plan
+ ```
+
+- Run `terraform apply` to apply the infrastructure build.
+
+ ```bash
+ terraform apply
+ ```
+
+
+### Clean up
+
+- Run `terraform destroy` to clean up your environment.
+The input `delete_contents_on_destroy` must have been set to `true` in the original `apply` for the `terraform destroy` command to work.
+
+ ```bash
+ terraform destroy
+ ```
+
+> **DISCLAIMER**: Please pay attention to the following important details regarding the Cloud Run **Service Health** feature used in this project:
+
+* **Pre-GA Feature:** This feature is subject to the "Pre-GA Offerings Terms" in the General Service Terms section of the Service Specific Terms. Pre-GA features are available "as is" and might have limited support.
+* **Load Balancer Behavior:** Revisions without configured probes are treated as **unknown**. Please note that the Load Balancer considers instances with "unknown" status as **healthy** and will route traffic to them.
+* **Manual Configuration Required:** Currently, the `google_cloud_run_v2_service` Terraform resource does not natively support `readiness_probe` configuration. Due to this limitation, you must manually execute the following `gcloud` command to correctly enable this check after deployment:
+
+```bash
+gcloud beta run deploy SERVICE \
+ --image=IMAGE_URL \
+ --readiness-probe httpGet.path=PATH,httpGet.port=CONTAINER_PORT,successThreshold=SUCCESS_THRESHOLD,failureThreshold=FAILURE_THRESHOLD,timeoutSeconds=TIMEOUT,periodSeconds=PERIOD
+```
+For more information, please visit: [Cloud Run Service Health Documentation](https://docs.cloud.google.com/run/docs/configuring/healthchecks#readiness-probes)
+
## Inputs
| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| cloud\_run\_deletion\_protection | Prevents Terraform from destroying/recreating Cloud Run jobs/services. | `bool` | `true` | no |
+| cloud\_run\_vpc\_egress\_mode | Defines how Cloud Run connects to the VPC for outbound traffic. Modes can be default, direct-vpc-egress or vpc-access-connector. | `string` | `"default"` | no |
+| enable\_load\_balancer | If true, creates the Global Load Balancer resources. Defaults to false. | `bool` | `false` | no |
+| image | Name of the image used by cloud run. | `string` | `"us-docker.pkg.dev/cloudrun/container/hello:latest"` | no |
+| lb\_domain | Optional: Use an existing domain. Leave empty to use .sslip.io. | `string` | `null` | no |
+| lb\_ip\_address | Optional: Use an existing Global IP for Load Balancer. Leave empty to create a new one. | `string` | `null` | no |
+| location | Settings for creating a Multi-Region Service. Make sure to use region = 'global' if deploying a multi-region cloud run. | `string` | `"global"` | no |
+| primary\_region | Primary region for reference. | `string` | `"us-west1"` | no |
| project\_id | Project where the Cloud Run v2 will be deployed. | `string` | n/a | yes |
-| regions | Regions where serverless vpc access connectors will be created. | `list(string)` | [
"us-west1",
"europe-west1"
]
| no |
-| vpc\_connectors | Configuration for Serverless VPC Access connectors by regions. | map(object({
name = string
region = string
subnet_name = string
})) | n/a | yes |
+| regions | Regions where serverless VPC Access connectors will be created. | `list(string)` | [
"us-west1",
"europe-west1"
]
| no |
+| service\_name | Cloud Run service name. | `string` | n/a | yes |
+| vpc\_connectors | Configuration for Serverless VPC Access connectors by region. | map(object({
name = string
region = string
subnet_name = string
})) | `{}` | no |
+| vpc\_egress\_traffic | Defines which outbound traffic from Cloud Run is routed through the VPC (private IP ranges only or all traffic) when VPC egress is enabled. | `string` | `"private-ranges-only"` | no |
+| vpc\_network | Configuration of VPC Network by region (only for direct-vpc-egress). | `string` | `null` | no |
+| vpc\_subnets | Configuration of VPC subnets by region (only for direct-vpc-egress). | `map(string)` | `{}` | no |
## Outputs
| Name | Description |
|------|-------------|
+| backend\_service\_global | Global backend service backing the Cloud Run multi-region service. |
+| cloud\_run\_regions | Regions where the Cloud Run service is deployed. |
| cloud\_run\_service\_account | Service account used by Cloud Run instances. |
-| service\_id | Service IDs per region |
-| service\_name | Service names per region |
-| service\_uri | Service URIs per region |
-| vpc\_connectors\_ids | Serverless VPC Access Connectors IDs by region. |
-| vpc\_connectors\_names | VPC Access Connectors. |
+| cloud\_run\_service\_id | Cloud Run service ID. |
+| cloud\_run\_vpc\_egress\_mode | Cloud Run VPC egress mode in use. |
+| cloud\_run\_vpc\_egress\_setting | Cloud Run VPC egress setting. |
+| global\_entrypoint | Global HTTPS entrypoint for the Cloud Run multi-region service. |
+| global\_forwarding\_rule\_id | ID of the global HTTPS forwarding rule. |
+| https\_proxy\_id | ID of the HTTPS target proxy. |
+| lb\_domain | Domain for the Load Balancer (IP.sslip.io if no custom domain is provided). |
+| lb\_https\_url | HTTPS URL for the global Load Balancer. |
+| lb\_ip | Global IP address of the Load Balancer. |
+| serverless\_neg\_self\_links | Serverless NEG self links by region. |
+| serverless\_negs | Serverless NEGs by region. |
+| ssl\_certificate\_domains | Domains covered by the managed SSL certificate. |
+| ssl\_certificate\_id | Managed SSL certificate ID. |
+| url\_map\_id | ID of the URL map. |
+| vpc\_connectors\_ids | VPC Access Connectors IDs by region. |
+| vpc\_connectors\_names | VPC Access Connectors names by region. |
@@ -54,6 +132,8 @@ These sections describe requirements for using this example.
A service account can be used with required roles to execute this example:
* Cloud Run Admin: `roles/run.admin`
+* Compute Load Balancer Admin: `roles/compute.loadBalancerAdmin` (required for LB resources)
+* Compute Network Admin: `roles/compute.networkAdmin` (required for NEGs and IP reservation)
Know more about [Cloud Run Deployment Permissions](https://cloud.google.com/run/docs/reference/iam/roles#additional-configuration).
@@ -64,6 +144,8 @@ The [Project Factory module](https://registry.terraform.io/modules/terraform-goo
A project with the following APIs enabled must be used to host the main resource of this example:
+* Google Artifact Registry `artifactregistry.googleapis.com`
+* Google Cloud Build: `cloudbuild.googleapis.com`
* Google Cloud Run: `run.googleapis.com`
* Google Compute Engine: `compute.googleapis.com`
-* Google Servless VPC Acces: `vpcaccess.googleapis.com`
+* Google Network Services: `networkservices.googleapis.com`
diff --git a/examples/v2_multi_regions/custom_image/Dockerfile b/examples/v2_multi_regions/custom_image/Dockerfile
new file mode 100644
index 000000000..0445f538c
--- /dev/null
+++ b/examples/v2_multi_regions/custom_image/Dockerfile
@@ -0,0 +1,17 @@
+FROM golang:1.23-alpine as builder
+
+WORKDIR /app
+
+COPY main.go .
+
+RUN CGO_ENABLED=0 go build -o server main.go
+
+FROM alpine:3
+
+WORKDIR /app
+
+COPY --from=builder /app/server .
+
+ENV PORT 8080
+
+CMD ["./server"]
diff --git a/examples/v2_multi_regions/custom_image/main.go b/examples/v2_multi_regions/custom_image/main.go
new file mode 100644
index 000000000..e47a14116
--- /dev/null
+++ b/examples/v2_multi_regions/custom_image/main.go
@@ -0,0 +1,42 @@
+package main
+
+import (
+ "fmt"
+ "log"
+ "net/http"
+ "os"
+)
+
+func main() {
+ http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
+ if r.URL.Path == "/healthcheck" {
+ healthHandler(w, r)
+ return
+ }
+
+ w.Header().Set("Content-Type", "text/html")
+ fmt.Fprintf(w, `
+
+
Hello Cloud Run!
+
Path: %s
+
+ `, r.URL.Path)
+ })
+
+ http.HandleFunc("/healthcheck", healthHandler)
+
+ port := os.Getenv("PORT")
+ if port == "" {
+ port = "8080"
+ }
+
+ log.Printf("Listening on port %s", port)
+ if err := http.ListenAndServe(":"+port, nil); err != nil {
+ log.Fatal(err)
+ }
+}
+
+func healthHandler(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ fmt.Fprint(w, "OK")
+}
diff --git a/examples/v2_multi_regions/main.tf b/examples/v2_multi_regions/main.tf
index 217f526a8..749a6eeb3 100644
--- a/examples/v2_multi_regions/main.tf
+++ b/examples/v2_multi_regions/main.tf
@@ -15,25 +15,23 @@
*/
locals {
- vpc_connectors_ids = {
- for region, conn in google_vpc_access_connector.vpc_connectors :
- region => conn.id
- }
-
- vpc_config_valid = (
- (var.vpc_mode == "vpc-access-connector" && length(var.vpc_connectors) > 0) ||
- (var.vpc_mode == "direct-vpc-egress" && var.vpc_network != null && length(var.vpc_subnets) > 0)
+ vpc_flags = (
+ var.cloud_run_vpc_egress_mode == "vpc-access-connector" ?
+ "--vpc-connector=${var.vpc_connectors[var.primary_region].name} --vpc-egress=${var.vpc_egress_traffic}" :
+ var.cloud_run_vpc_egress_mode == "direct-vpc-egress" ?
+ "--network=${var.vpc_network} --subnet=${var.vpc_subnets[var.primary_region]} --vpc-egress=${var.vpc_egress_traffic}" :
+ ""
)
}
resource "google_service_account" "sa" {
project = var.project_id
account_id = "ci-cloud-run-v2-sa"
- display_name = "Service account for ci-cloud-run-v2-sa"
+ display_name = "Service account for Cloud Run multi-region"
}
resource "google_vpc_access_connector" "vpc_connectors" {
- for_each = var.vpc_mode == "vpc-access-connector" ? var.vpc_connectors : {}
+ for_each = var.cloud_run_vpc_egress_mode == "vpc-access-connector" ? var.vpc_connectors : {}
name = each.value.name
project = var.project_id
@@ -47,51 +45,78 @@ resource "google_vpc_access_connector" "vpc_connectors" {
max_instances = 4
}
+resource "null_resource" "validate_primary_region" {
+ count = contains(var.regions, var.primary_region) ? 0 : 1
+
+ provisioner "local-exec" {
+ command = "echo \"ERROR: primary_region (${var.primary_region}) must be one of: ${join(", ", var.regions)}\" && exit 1"
+ }
+}
+
resource "null_resource" "validate_vpc" {
- count = local.vpc_config_valid ? 0 : 1
+ count = (
+ var.cloud_run_vpc_egress_mode != "default" && (
+ (var.cloud_run_vpc_egress_mode == "vpc-access-connector" && length(var.vpc_connectors) == 0) ||
+ (var.cloud_run_vpc_egress_mode == "direct-vpc-egress" &&
+ (var.vpc_network == null || length(var.vpc_subnets) == 0)
+ )
+ )
+ ) ? 1 : 0
provisioner "local-exec" {
- command = "echo 'ERROR: VPC configuration invalid. Check your vpc_mode, vpc_connectors, vpc_network and vpc_subnets'' && exit 1"
+ command = "echo 'ERROR: Invalid VPC configuration for selected cloud_run_vpc_egress_mode' && exit 1"
}
}
module "cloud_run_v2_multiregion" {
source = "../../modules/v2"
- for_each = toset(var.regions)
-
- service_name = "cloudrun-multiregion-${each.key}"
- project_id = var.project_id
- location = each.key
-
- create_service_account = false
- service_account = google_service_account.sa.email
-
+ service_name = var.service_name
+ location = var.location
+ project_id = var.project_id
+ create_service_account = false
+ service_account = google_service_account.sa.email
cloud_run_deletion_protection = var.cloud_run_deletion_protection
- vpc_access = (
- var.vpc_mode == "vpc-access-connector"
- ?
- {
- connector = local.vpc_connectors_ids[each.key]
- egress = "PRIVATE_RANGES_ONLY"
- network_interfaces = null
- }
- :
- {
- connector = null
- egress = var.vpc_egress
- network_interfaces = {
- network = var.vpc_network
- subnetwork = var.vpc_subnets[each.key]
- }
- }
- )
+ multi_region_settings = {
+ regions = var.regions
+ }
+
+ load_balancer_config = var.enable_load_balancer ? {
+ regions = var.regions
+ global_ip_address = var.lb_ip_address
+ domain = var.lb_domain
+ name_prefix = var.service_name
+ } : null
containers = [
{
- container_image = "us-docker.pkg.dev/cloudrun/container/hello"
+ container_image = var.image
container_name = "hello-world"
+
+ startup_probe = {
+ initial_delay_seconds = 10
+ timeout_seconds = 3
+ period_seconds = 3
+ failure_threshold = 5
+
+ http_get = {
+ path = "/"
+ port = 8080
+ }
+ }
+
+ liveness_probe = {
+ initial_delay_seconds = 10
+ timeout_seconds = 3
+ period_seconds = 3
+ failure_threshold = 5
+
+ http_get = {
+ path = "/"
+ port = 8080
+ }
+ }
}
]
}
diff --git a/examples/v2_multi_regions/outputs.tf b/examples/v2_multi_regions/outputs.tf
index d0a0512f4..ff543edff 100644
--- a/examples/v2_multi_regions/outputs.tf
+++ b/examples/v2_multi_regions/outputs.tf
@@ -19,28 +19,54 @@ output "cloud_run_service_account" {
value = google_service_account.sa.email
}
-output "service_name" {
- description = "Service names per region."
- value = {
- for region, mod in module.cloud_run_v2_multiregion :
- region => mod.service_name
- }
+output "cloud_run_service_id" {
+ description = "Cloud Run service ID."
+ value = module.cloud_run_v2_multiregion.service_id
}
-output "service_uri" {
- description = "Service URIs per region."
- value = {
- for region, mod in module.cloud_run_v2_multiregion :
- region => mod.service_uri
- }
+output "global_forwarding_rule_id" {
+ description = "ID of the global HTTPS forwarding rule."
+ value = module.cloud_run_v2_multiregion.global_forwarding_rule_id
}
-output "service_id" {
- description = "Service IDs per region."
- value = {
- for region, mod in module.cloud_run_v2_multiregion :
- region => mod.service_id
- }
+output "https_proxy_id" {
+ description = "ID of the HTTPS target proxy."
+ value = module.cloud_run_v2_multiregion.https_proxy_id
+}
+
+output "url_map_id" {
+ description = "ID of the URL map."
+ value = module.cloud_run_v2_multiregion.url_map_id
+}
+
+output "serverless_neg_self_links" {
+ description = "Serverless NEG self links by region."
+ value = module.cloud_run_v2_multiregion.serverless_negs
+}
+
+output "ssl_certificate_domains" {
+ description = "Domains covered by the managed SSL certificate."
+ value = module.cloud_run_v2_multiregion.ssl_certificate_domains
+}
+
+output "cloud_run_vpc_egress_mode" {
+ description = "Cloud Run VPC egress mode in use."
+ value = var.cloud_run_vpc_egress_mode
+}
+
+output "cloud_run_vpc_egress_setting" {
+ description = "Cloud Run VPC egress setting."
+ value = var.vpc_egress_traffic
+}
+
+output "cloud_run_regions" {
+ description = "Regions where the Cloud Run service is deployed."
+ value = var.regions
+}
+
+output "serverless_negs" {
+ description = "Serverless NEGs by region."
+ value = module.cloud_run_v2_multiregion.serverless_negs
}
output "vpc_connectors_ids" {
@@ -49,14 +75,42 @@ output "vpc_connectors_ids" {
for region, connector in google_vpc_access_connector.vpc_connectors :
region => connector.id
}
- sensitive = false
}
output "vpc_connectors_names" {
- description = "VPC Access Connectors name by region."
+ description = "VPC Access Connectors names by region."
value = {
for region, connector in google_vpc_access_connector.vpc_connectors :
region => connector.name
}
- sensitive = false
+}
+
+output "backend_service_global" {
+ description = "Global backend service backing the Cloud Run multi-region service."
+ value = module.cloud_run_v2_multiregion.backend_service_global_id
+}
+
+output "lb_ip" {
+ description = "Global IP address of the Load Balancer."
+ value = module.cloud_run_v2_multiregion.lb_ip
+}
+
+output "lb_domain" {
+ description = "Domain for the Load Balancer (IP.sslip.io if no custom domain is provided)."
+ value = module.cloud_run_v2_multiregion.lb_domain
+}
+
+output "lb_https_url" {
+ description = "HTTPS URL for the global Load Balancer."
+ value = module.cloud_run_v2_multiregion.lb_https_url
+}
+
+output "ssl_certificate_id" {
+ description = "Managed SSL certificate ID."
+ value = module.cloud_run_v2_multiregion.ssl_certificate_id
+}
+
+output "global_entrypoint" {
+ description = "Global HTTPS entrypoint for the Cloud Run multi-region service."
+ value = module.cloud_run_v2_multiregion.lb_https_url
}
diff --git a/examples/v2_multi_regions/terraform.tfvars.example b/examples/v2_multi_regions/terraform.tfvars.example
new file mode 100644
index 000000000..dac1ffbbe
--- /dev/null
+++ b/examples/v2_multi_regions/terraform.tfvars.example
@@ -0,0 +1,46 @@
+project_id = "YOUR-PROJECT-ID"
+regions = ["us-west1", "europe-west1"]
+primary_region = "us-west1"
+service_name = "cloudrun-multiregion"
+
+# Choose between direct-vpc-egress or vpc-access-connector
+cloud_run_vpc_egress_mode = "direct-vpc-egress"
+vpc_egress_traffic = "all-traffic"
+
+# Only for Direct VPC Egress
+#vpc_network = "projects/YOUR-PROJECT/global/networks/YOUR-VPCE"
+
+# vpc_subnets = {
+# "us-west1" = "projects/YOUR-PROJECT/regions/us-west1/subnetworks/sb-restricted-us-west1"
+# "europe-west1" = "projects/YOUR-PROJECT/regions/europe-west1/subnetworks/sb-restricted-europe-west1"
+# }
+
+# Set to true to create the load balancer infrastructure
+# enable_load_balancer = true
+lb_domain = null # Opcional - Your LB domain
+lb_ip_address = null # Opcional - Your LB Global IP
+
+# Un-comment if you want to use the default vpc network
+# cloud_run_vpc_egress_mode = "default"
+# vpc_egress = null
+# vpc_network = null
+# vpc_subnets = {}
+# vpc_connectors = {}
+# lb_ip_address = null
+# lb_domain = null
+
+# Un-comment if you want to use the vpc-access-connector
+# vpc_connectors = {
+# "us-west1" = {
+# name = "con-cloud-run-us"
+# region = "us-west1"
+# subnet_name = "cloudrun-us-west1"
+# }
+# "europe-west1" = {
+# name = "con-cloud-run-eu"
+# region = "europe-west1"
+# subnet_name = "cloudrun-europe-west1"
+# }
+# }
+
+# cloud_run_deletion_protection = false
diff --git a/examples/v2_multi_regions/variables.tf b/examples/v2_multi_regions/variables.tf
index 120cf5906..884ff4963 100644
--- a/examples/v2_multi_regions/variables.tf
+++ b/examples/v2_multi_regions/variables.tf
@@ -21,35 +21,55 @@ variable "project_id" {
variable "regions" {
type = list(string)
- description = "Regions where serverless vpc access connectors will be created."
+ description = "Regions where serverless VPC Access connectors will be created."
default = ["us-west1", "europe-west1"]
}
+variable "location" {
+ type = string
+ description = " Settings for creating a Multi-Region Service. Make sure to use region = 'global' if deploying a multi-region cloud run."
+ default = "global"
+}
+
+variable "service_name" {
+ type = string
+ description = "Cloud Run service name."
+}
+
+variable "image" {
+ type = string
+ description = "Name of the image used by cloud run."
+ default = "us-docker.pkg.dev/cloudrun/container/hello:latest"
+}
+
variable "cloud_run_deletion_protection" {
type = bool
description = "Prevents Terraform from destroying/recreating Cloud Run jobs/services."
default = true
}
-variable "vpc_mode" {
+variable "cloud_run_vpc_egress_mode" {
type = string
- description = "VPC Mode: direct-vpc-egress (default) or vpc-access-connector."
- default = "direct-vpc-egress"
+ description = "Defines how Cloud Run connects to the VPC for outbound traffic. Modes can be default, direct-vpc-egress or vpc-access-connector."
+ default = "default"
validation {
- condition = contains(["direct-vpc-egress", "vpc-access-connector"], var.vpc_mode)
- error_message = "vpc_mode must be 'direct-vpc-egress' or 'vpc-access-connector'."
+ condition = contains(
+ ["default", "direct-vpc-egress", "vpc-access-connector"],
+ var.cloud_run_vpc_egress_mode
+ )
+ error_message = "cloud_run_vpc_egress_mode must be 'default', 'direct-vpc-egress' or 'vpc-access-connector'."
}
}
variable "vpc_connectors" {
- description = "Configuration for Serverless VPC Access connectors by regions."
type = map(object({
name = string
region = string
subnet_name = string
}))
- default = {}
+ description = "Configuration for Serverless VPC Access connectors by region."
+ default = {}
}
variable "vpc_network" {
@@ -64,11 +84,36 @@ variable "vpc_subnets" {
default = {}
}
-variable "vpc_egress" {
+variable "vpc_egress_traffic" {
type = string
- default = "PRIVATE_RANGES_ONLY"
+ description = "Defines which outbound traffic from Cloud Run is routed through the VPC (private IP ranges only or all traffic) when VPC egress is enabled."
+ default = "private-ranges-only"
validation {
- condition = var.vpc_egress == null || can(regex("^(PRIVATE_RANGES_ONLY|ALL_TRAFFIC)$", var.vpc_egress))
- error_message = "vpc_egress must be PRIVATE_RANGES_ONLY, ALL_TRAFFIC or null."
+ condition = var.vpc_egress_traffic == null || can(regex("^(private-ranges-only|all-traffic)$", var.vpc_egress_traffic))
+ error_message = "vpc_egress_traffic must be private-ranges-only, all-traffic or null."
}
}
+
+variable "primary_region" {
+ type = string
+ description = "Primary region for reference."
+ default = "us-west1"
+}
+
+variable "lb_ip_address" {
+ type = string
+ description = "Optional: Use an existing Global IP for Load Balancer. Leave empty to create a new one."
+ default = null
+}
+
+variable "lb_domain" {
+ type = string
+ description = "Optional: Use an existing domain. Leave empty to use .sslip.io."
+ default = null
+}
+
+variable "enable_load_balancer" {
+ type = bool
+ description = "If true, creates the Global Load Balancer resources. Defaults to false."
+ default = false
+}
diff --git a/metadata.yaml b/metadata.yaml
index 46f92dd60..c7a6fbf72 100644
--- a/metadata.yaml
+++ b/metadata.yaml
@@ -64,6 +64,8 @@ spec:
location: examples/simple_job_exec
- name: v2
location: examples/v2
+ - name: v2_multi_regions
+ location: examples/v2_multi_regions
- name: v2_with_gmp
location: examples/v2_with_gmp
- name: v2_with_gpu
@@ -119,6 +121,17 @@ spec:
description: A set of key/value label pairs to assign to the container metadata
varType: map(string)
defaultValue: {}
+ - name: ingress
+ description: Restricts network access to your Cloud Run service
+ varType: string
+ defaultValue: INGRESS_TRAFFIC_ALL
+ - name: vpc_connector
+ description: The full resource name of the VPC Access connector to use. Leave null to use Direct VPC Egress.
+ varType: string
+ - name: vpc_egress
+ description: The outbound traffic setting for VPC. Use 'PRIVATE_RANGES_ONLY' with a connector. Use 'ALL_TRAFFIC' for Direct VPC Egress. Set to null to disable all VPC egress.
+ varType: string
+ defaultValue: ALL_TRAFFIC
- name: template_annotations
description: Annotations to the container metadata including VPC Connector and SQL. See [more details](https://cloud.google.com/run/docs/reference/rpc/google.cloud.run.v1#revisiontemplate)
varType: map(string)
@@ -323,13 +336,13 @@ spec:
roles:
- level: Project
roles:
- - roles/cloudkms.admin
- - roles/resourcemanager.projectIamAdmin
- - roles/run.admin
- roles/iam.serviceAccountAdmin
- roles/artifactregistry.admin
- roles/iam.serviceAccountUser
- roles/serviceusage.serviceUsageViewer
+ - roles/cloudkms.admin
+ - roles/resourcemanager.projectIamAdmin
+ - roles/run.admin
services:
- accesscontextmanager.googleapis.com
- cloudbilling.googleapis.com
diff --git a/modules/job-exec/metadata.yaml b/modules/job-exec/metadata.yaml
index 8247c5733..6d90fcf47 100644
--- a/modules/job-exec/metadata.yaml
+++ b/modules/job-exec/metadata.yaml
@@ -48,6 +48,8 @@ spec:
location: examples/simple_job_exec
- name: v2
location: examples/v2
+ - name: v2_multi_regions
+ location: examples/v2_multi_regions
- name: v2_with_gmp
location: examples/v2_with_gmp
- name: v2_with_gpu
@@ -219,13 +221,13 @@ spec:
roles:
- level: Project
roles:
- - roles/run.admin
- - roles/iam.serviceAccountAdmin
- roles/artifactregistry.admin
- roles/iam.serviceAccountUser
- roles/serviceusage.serviceUsageViewer
- roles/cloudkms.admin
- roles/resourcemanager.projectIamAdmin
+ - roles/run.admin
+ - roles/iam.serviceAccountAdmin
services:
- accesscontextmanager.googleapis.com
- cloudbilling.googleapis.com
diff --git a/modules/secure-cloud-run-core/metadata.yaml b/modules/secure-cloud-run-core/metadata.yaml
index c2a6df4a7..00aa85803 100644
--- a/modules/secure-cloud-run-core/metadata.yaml
+++ b/modules/secure-cloud-run-core/metadata.yaml
@@ -48,6 +48,8 @@ spec:
location: examples/simple_job_exec
- name: v2
location: examples/v2
+ - name: v2_multi_regions
+ location: examples/v2_multi_regions
- name: v2_with_gmp
location: examples/v2_with_gmp
- name: v2_with_gpu
@@ -306,13 +308,13 @@ spec:
roles:
- level: Project
roles:
- - roles/cloudkms.admin
- - roles/resourcemanager.projectIamAdmin
- roles/run.admin
- roles/iam.serviceAccountAdmin
- roles/artifactregistry.admin
- roles/iam.serviceAccountUser
- roles/serviceusage.serviceUsageViewer
+ - roles/cloudkms.admin
+ - roles/resourcemanager.projectIamAdmin
services:
- accesscontextmanager.googleapis.com
- cloudbilling.googleapis.com
diff --git a/modules/secure-cloud-run-security/metadata.yaml b/modules/secure-cloud-run-security/metadata.yaml
index 0b9de8caf..3fe91395b 100644
--- a/modules/secure-cloud-run-security/metadata.yaml
+++ b/modules/secure-cloud-run-security/metadata.yaml
@@ -48,6 +48,8 @@ spec:
location: examples/simple_job_exec
- name: v2
location: examples/v2
+ - name: v2_multi_regions
+ location: examples/v2_multi_regions
- name: v2_with_gmp
location: examples/v2_with_gmp
- name: v2_with_gpu
@@ -133,13 +135,13 @@ spec:
roles:
- level: Project
roles:
- - roles/cloudkms.admin
- - roles/resourcemanager.projectIamAdmin
- roles/run.admin
- roles/iam.serviceAccountAdmin
- roles/artifactregistry.admin
- roles/iam.serviceAccountUser
- roles/serviceusage.serviceUsageViewer
+ - roles/cloudkms.admin
+ - roles/resourcemanager.projectIamAdmin
services:
- accesscontextmanager.googleapis.com
- cloudbilling.googleapis.com
diff --git a/modules/secure-cloud-run/metadata.yaml b/modules/secure-cloud-run/metadata.yaml
index 284d4d749..55e1f5b94 100644
--- a/modules/secure-cloud-run/metadata.yaml
+++ b/modules/secure-cloud-run/metadata.yaml
@@ -48,6 +48,8 @@ spec:
location: examples/simple_job_exec
- name: v2
location: examples/v2
+ - name: v2_multi_regions
+ location: examples/v2_multi_regions
- name: v2_with_gmp
location: examples/v2_with_gmp
- name: v2_with_gpu
@@ -250,13 +252,13 @@ spec:
roles:
- level: Project
roles:
+ - roles/iam.serviceAccountUser
- roles/serviceusage.serviceUsageViewer
- roles/cloudkms.admin
- roles/resourcemanager.projectIamAdmin
- roles/run.admin
- roles/iam.serviceAccountAdmin
- roles/artifactregistry.admin
- - roles/iam.serviceAccountUser
services:
- accesscontextmanager.googleapis.com
- cloudbilling.googleapis.com
diff --git a/modules/secure-serverless-harness/metadata.yaml b/modules/secure-serverless-harness/metadata.yaml
index 466cd1126..ce9fc6009 100644
--- a/modules/secure-serverless-harness/metadata.yaml
+++ b/modules/secure-serverless-harness/metadata.yaml
@@ -48,6 +48,8 @@ spec:
location: examples/simple_job_exec
- name: v2
location: examples/v2
+ - name: v2_multi_regions
+ location: examples/v2_multi_regions
- name: v2_with_gmp
location: examples/v2_with_gmp
- name: v2_with_gpu
diff --git a/modules/secure-serverless-net/metadata.yaml b/modules/secure-serverless-net/metadata.yaml
index f7c089b4f..ffc463ea7 100644
--- a/modules/secure-serverless-net/metadata.yaml
+++ b/modules/secure-serverless-net/metadata.yaml
@@ -48,6 +48,8 @@ spec:
location: examples/simple_job_exec
- name: v2
location: examples/v2
+ - name: v2_multi_regions
+ location: examples/v2_multi_regions
- name: v2_with_gmp
location: examples/v2_with_gmp
- name: v2_with_gpu
diff --git a/modules/v2/README.md b/modules/v2/README.md
index 017b81765..605514c4b 100644
--- a/modules/v2/README.md
+++ b/modules/v2/README.md
@@ -57,6 +57,7 @@ Functional examples are included in the
| create\_service\_account | Create a new service account for cloud run service | `bool` | `true` | no |
| custom\_audiences | One or more custom audiences that you want this service to support. Specify each custom audience as the full URL in a string. [Refer](https://cloud.google.com/run/docs/configuring/custom-audiences) | `list(string)` | `null` | no |
| description | Cloud Run service description. This field currently has a 512-character limit. | `string` | `null` | no |
+| enable\_load\_balancer | If true, creates the Global Load Balancer resources. Defaults to false. | `bool` | `false` | no |
| enable\_prometheus\_sidecar | Enable Prometheus sidecar in Cloud Run instance. | `bool` | `false` | no |
| encryption\_key | A reference to a customer managed encryption key (CMEK) to use to encrypt this container image. This is optional. | `string` | `null` | no |
| execution\_environment | The sandbox environment to host this Revision. | `string` | `"EXECUTION_ENVIRONMENT_GEN2"` | no |
@@ -64,9 +65,13 @@ Functional examples are included in the
| iap\_members | Valid only when launch stage is set to 'BETA'. IAP is enabled automatically when users or service accounts (SAs) are provided. Use allUsers for public access, allAuthenticatedUsers for any Google-authenticated user, or specify individual users/SAs. [More info](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/iap_web_cloud_run_service_iam#member/members-2) | `list(string)` | `[]` | no |
| ingress | Restricts network access to your Cloud Run service | `string` | `"INGRESS_TRAFFIC_ALL"` | no |
| launch\_stage | The launch stage as defined by Google Cloud Platform Launch Stages. Cloud Run supports ALPHA, BETA, and GA. If no value is specified, GA is assumed. | `string` | `"GA"` | no |
+| lb\_domain | Optional: Use an existing domain. Leave empty to use .sslip.io. (Only used if enable\_load\_balancer is true) | `string` | `null` | no |
+| lb\_ip\_address | Optional: Use an existing Global IP for Load Balancer. Leave empty to create a new one. (Only used if enable\_load\_balancer is true) | `string` | `null` | no |
+| load\_balancer\_config | Configuration for the Load Balancer. If null, no LB resources are created. | object({
regions = list(string)
global_ip_address = optional(string, null)
domain = optional(string, null)
name_prefix = optional(string, "cloudrun")
}) | `null` | no |
| location | Cloud Run service deployment location | `string` | n/a | yes |
| max\_instance\_request\_concurrency | Sets the maximum number of requests that each serving instance can receive. This is optional. | `string` | `null` | no |
| members | Users/SAs to be given invoker access to the service. Grant invoker access by specifying the users or service accounts (SAs). Use allUsers for public access, allAuthenticatedUsers for access by logged-in Google users, or provide a list of specific users/SAs. [See the complete list of available options here](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/cloud_run_v2_service_iam#member/members-1) | `list(string)` | `[]` | no |
+| multi\_region\_settings | Settings for creating a Multi-Region Service. | object({
regions = list(string)
}) | `null` | no |
| node\_selector | Node Selector describes the hardware requirements of the GPU resource. [More info](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/cloud_run_v2_service#nested_template_node_selector). | object({
accelerator = string
}) | `null` | no |
| project\_id | The project ID to deploy to | `string` | n/a | yes |
| revision | The unique name for the revision. If this field is omitted, it will be automatically generated based on the Service name | `string` | `null` | no |
@@ -90,18 +95,28 @@ Functional examples are included in the
| Name | Description |
|------|-------------|
| apphub\_service\_uri | Service URI in CAIS style to be used by Apphub. |
+| backend\_service\_global\_id | n/a |
| creator | Email address of the authenticated creator. |
| effective\_annotations | All of annotations (key/value pairs) present on the resource in GCP, including the annotations configured through Terraform, other clients and services. |
+| global\_forwarding\_rule\_id | n/a |
+| https\_proxy\_id | n/a |
| last\_modifier | Email address of the last authenticated modifier. |
| latest\_created\_revision | Name of the last created revision. See comments in reconciling for additional information on reconciliation process in Cloud Run. |
| latest\_ready\_revision | Name of the latest revision that is serving traffic. See comments in reconciling for additional information on reconciliation process in Cloud Run. |
+| lb\_domain | n/a |
+| lb\_https\_url | n/a |
+| lb\_ip | n/a |
| location | Location in which the Cloud Run service was created |
| observed\_generation | The generation of this Service currently serving traffic. |
| project\_id | Google Cloud project in which the service was created |
+| serverless\_negs | n/a |
| service\_account\_id | Service account id and email |
| service\_id | Unique Identifier for the created service with format projects/{{project}}/locations/{{location}}/services/{{name}} |
| service\_name | Name of the created service |
| service\_uri | The main URI in which this Service is serving traffic. |
+| ssl\_certificate\_domains | n/a |
+| ssl\_certificate\_id | n/a |
| traffic\_statuses | Detailed status information for corresponding traffic targets. |
+| url\_map\_id | n/a |
diff --git a/modules/v2/main.tf b/modules/v2/main.tf
index e94534e66..89b6b1e3d 100644
--- a/modules/v2/main.tf
+++ b/modules/v2/main.tf
@@ -76,6 +76,146 @@ locals {
startup_probe = []
liveness_probe = []
}]
+
+ create_lb = var.load_balancer_config != null
+
+ lb_prefix = try(var.load_balancer_config.name_prefix, "cloudrun")
+
+ create_ip = local.create_lb && try(var.load_balancer_config.global_ip_address, null) == null
+ lb_ip_address = local.create_lb ? (
+ local.create_ip ? google_compute_global_address.lb_ip[0].address : var.load_balancer_config.global_ip_address
+ ) : null
+
+ lb_domain = local.create_lb ? (
+ try(var.load_balancer_config.domain, null) != null
+ ? var.load_balancer_config.domain
+ : "${local.lb_ip_address}.sslip.io"
+ ) : null
+
+ neg_regions = local.create_lb ? toset(var.load_balancer_config.regions) : toset([])
+}
+
+resource "google_compute_global_address" "lb_ip" {
+ count = local.create_ip ? 1 : 0
+ name = "${local.lb_prefix}-global-ip"
+ project = var.project_id
+}
+
+resource "google_compute_region_network_endpoint_group" "cloudrun_neg" {
+ for_each = local.neg_regions
+
+ project = var.project_id
+ region = each.key
+ name = "${local.lb_prefix}-neg-${each.key}"
+ network_endpoint_type = "SERVERLESS"
+
+ cloud_run {
+ service = google_cloud_run_v2_service.main.name
+ }
+}
+
+resource "google_compute_backend_service" "cloudrun_backend_global" {
+ count = local.create_lb ? 1 : 0
+ project = var.project_id
+ name = "${local.lb_prefix}-backend-global"
+
+ protocol = "HTTP"
+ load_balancing_scheme = "EXTERNAL_MANAGED"
+ enable_cdn = false
+
+ outlier_detection {
+ consecutive_errors = 3
+ consecutive_gateway_failure = 5
+ enforcing_consecutive_errors = 100
+ enforcing_consecutive_gateway_failure = 100
+
+ base_ejection_time { seconds = 30 }
+ interval { seconds = 10 }
+ }
+
+ dynamic "backend" {
+ for_each = google_compute_region_network_endpoint_group.cloudrun_neg
+ content {
+ group = backend.value.id
+ }
+ }
+}
+
+resource "google_compute_url_map" "cloudrun_urlmap" {
+ count = local.create_lb ? 1 : 0
+ name = "${local.lb_prefix}-urlmap"
+ project = var.project_id
+
+ default_service = google_compute_backend_service.cloudrun_backend_global[0].id
+
+ host_rule {
+ hosts = ["*"]
+ path_matcher = "allpaths"
+ }
+
+ path_matcher {
+ name = "allpaths"
+ default_service = google_compute_backend_service.cloudrun_backend_global[0].id
+
+ path_rule {
+ paths = ["/*"]
+
+ route_action {
+ weighted_backend_services {
+ backend_service = google_compute_backend_service.cloudrun_backend_global[0].id
+ weight = 100
+ }
+
+ retry_policy {
+ num_retries = 10
+ per_try_timeout { seconds = 30 }
+ retry_conditions = [
+ "5xx",
+ "gateway-error",
+ "connect-failure",
+ "retriable-4xx",
+ "unavailable",
+ "dead-deadline-exceeded",
+ ]
+ }
+ }
+ }
+ }
+}
+
+resource "google_compute_managed_ssl_certificate" "cloudrun_cert" {
+ count = local.create_lb ? 1 : 0
+ name = "${local.lb_prefix}-cert"
+ project = var.project_id
+
+ managed {
+ domains = [local.lb_domain]
+ }
+}
+
+resource "google_compute_target_https_proxy" "cloudrun_https_proxy" {
+ count = local.create_lb ? 1 : 0
+ name = "${local.lb_prefix}-https-proxy"
+ project = var.project_id
+ ssl_certificates = [google_compute_managed_ssl_certificate.cloudrun_cert[0].id]
+ url_map = google_compute_url_map.cloudrun_urlmap[0].id
+}
+
+resource "google_compute_global_forwarding_rule" "cloudrun_https_rule" {
+ count = local.create_lb ? 1 : 0
+ name = "${local.lb_prefix}-https-rule"
+ project = var.project_id
+
+ ip_address = local.lb_ip_address
+ ip_protocol = "TCP"
+ port_range = "443"
+ target = google_compute_target_https_proxy.cloudrun_https_proxy[0].id
+ load_balancing_scheme = "EXTERNAL_MANAGED"
+
+ depends_on = [
+ google_compute_target_https_proxy.cloudrun_https_proxy,
+ google_compute_managed_ssl_certificate.cloudrun_cert
+ ]
}
resource "google_service_account" "sa" {
@@ -104,6 +244,13 @@ resource "google_cloud_run_v2_service" "main" {
iap_enabled = length(var.iap_members) > 0
deletion_protection = var.cloud_run_deletion_protection
+ dynamic "multi_region_settings" {
+ for_each = var.multi_region_settings == null ? [] : [var.multi_region_settings]
+ content {
+ regions = multi_region_settings.value.regions
+ }
+ }
+
template {
revision = var.revision
labels = var.template_labels
diff --git a/modules/v2/metadata.yaml b/modules/v2/metadata.yaml
index 56515638e..fe492834e 100644
--- a/modules/v2/metadata.yaml
+++ b/modules/v2/metadata.yaml
@@ -48,6 +48,8 @@ spec:
location: examples/simple_job_exec
- name: v2
location: examples/v2
+ - name: v2_multi_regions
+ location: examples/v2_multi_regions
- name: v2_with_gmp
location: examples/v2_with_gmp
- name: v2_with_gpu
@@ -60,6 +62,12 @@ spec:
description: The project ID to deploy to
varType: string
required: true
+ - name: multi_region_settings
+ description: " Settings for creating a Multi-Region Service."
+ varType: |-
+ object({
+ regions = list(string)
+ })
- name: location
description: Cloud Run service deployment location
varType: string
@@ -501,6 +509,25 @@ spec:
description: The sandbox environment to host this Revision.
varType: string
defaultValue: EXECUTION_ENVIRONMENT_GEN2
+ - name: load_balancer_config
+ description: Configuration for the Load Balancer. If null, no LB resources are created.
+ varType: |-
+ object({
+ regions = list(string)
+ global_ip_address = optional(string, null)
+ domain = optional(string, null)
+ name_prefix = optional(string, "cloudrun")
+ })
+ - name: enable_load_balancer
+ description: If true, creates the Global Load Balancer resources. Defaults to false.
+ varType: bool
+ defaultValue: false
+ - name: lb_ip_address
+ description: "Optional: Use an existing Global IP for Load Balancer. Leave empty to create a new one. (Only used if enable_load_balancer is true)"
+ varType: string
+ - name: lb_domain
+ description: "Optional: Use an existing domain. Leave empty to use .sslip.io. (Only used if enable_load_balancer is true)"
+ varType: string
outputs:
- name: apphub_service_uri
description: Service URI in CAIS style to be used by Apphub.
@@ -509,6 +536,7 @@ spec:
- location: string
service_id: string
service_uri: string
+ - name: backend_service_global_id
- name: creator
description: Email address of the authenticated creator.
type: string
@@ -517,6 +545,8 @@ spec:
type:
- map
- string
+ - name: global_forwarding_rule_id
+ - name: https_proxy_id
- name: last_modifier
description: Email address of the last authenticated modifier.
type: string
@@ -526,6 +556,9 @@ spec:
- name: latest_ready_revision
description: Name of the latest revision that is serving traffic. See comments in reconciling for additional information on reconciliation process in Cloud Run.
type: string
+ - name: lb_domain
+ - name: lb_https_url
+ - name: lb_ip
- name: location
description: Location in which the Cloud Run service was created
type: string
@@ -535,6 +568,7 @@ spec:
- name: project_id
description: Google Cloud project in which the service was created
type: string
+ - name: serverless_negs
- name: service_account_id
description: Service account id and email
type:
@@ -551,6 +585,8 @@ spec:
- name: service_uri
description: The main URI in which this Service is serving traffic.
type: string
+ - name: ssl_certificate_domains
+ - name: ssl_certificate_id
- name: traffic_statuses
description: Detailed status information for corresponding traffic targets.
type:
@@ -561,17 +597,18 @@ spec:
tag: string
type: string
uri: string
+ - name: url_map_id
requirements:
roles:
- level: Project
roles:
- - roles/run.admin
- - roles/iam.serviceAccountAdmin
- roles/iam.serviceAccountUser
- roles/serviceusage.serviceUsageViewer
- roles/resourcemanager.projectIamAdmin
- roles/compute.viewer
- roles/iap.admin
+ - roles/run.admin
+ - roles/iam.serviceAccountAdmin
services:
- cloudresourcemanager.googleapis.com
- compute.googleapis.com
@@ -583,6 +620,6 @@ spec:
- storage-api.googleapis.com
providerVersions:
- source: hashicorp/google
- version: ">= 6, < 7"
+ version: ">= 6, < 8"
- source: hashicorp/google-beta
- version: ">= 6, < 7"
+ version: ">= 6, < 8"
diff --git a/modules/v2/outputs.tf b/modules/v2/outputs.tf
index 4e76d00f9..1c948563f 100644
--- a/modules/v2/outputs.tf
+++ b/modules/v2/outputs.tf
@@ -87,3 +87,45 @@ output "apphub_service_uri" {
}
description = "Service URI in CAIS style to be used by Apphub."
}
+
+output "https_proxy_id" {
+ value = try(google_compute_target_https_proxy.cloudrun_https_proxy[0].id, null)
+}
+
+output "url_map_id" {
+ value = try(google_compute_url_map.cloudrun_urlmap[0].id, null)
+}
+
+output "ssl_certificate_domains" {
+ value = try(google_compute_managed_ssl_certificate.cloudrun_cert[0].managed[0].domains, [])
+}
+
+output "ssl_certificate_id" {
+ value = try(google_compute_managed_ssl_certificate.cloudrun_cert[0].id, null)
+}
+
+output "serverless_negs" {
+ value = {
+ for k, v in google_compute_region_network_endpoint_group.cloudrun_neg : k => v.self_link
+ }
+}
+
+output "backend_service_global_id" {
+ value = try(google_compute_backend_service.cloudrun_backend_global[0].id, null)
+}
+
+output "lb_ip" {
+ value = local.lb_ip_address
+}
+
+output "lb_domain" {
+ value = local.lb_domain
+}
+
+output "lb_https_url" {
+ value = local.lb_domain != null ? "https://${local.lb_domain}" : null
+}
+
+output "global_forwarding_rule_id" {
+ value = try(google_compute_global_forwarding_rule.cloudrun_https_rule[0].id, null)
+}
\ No newline at end of file
diff --git a/modules/v2/variables.tf b/modules/v2/variables.tf
index c62537e7f..684345e9c 100644
--- a/modules/v2/variables.tf
+++ b/modules/v2/variables.tf
@@ -20,6 +20,14 @@ variable "project_id" {
type = string
}
+variable "multi_region_settings" {
+ description = " Settings for creating a Multi-Region Service."
+ type = object({
+ regions = list(string)
+ })
+ default = null
+}
+
variable "location" {
description = "Cloud Run service deployment location"
type = string
@@ -357,3 +365,31 @@ variable "execution_environment" {
}
}
+variable "load_balancer_config" {
+ description = "Configuration for the Load Balancer. If null, no LB resources are created."
+ type = object({
+ regions = list(string)
+ global_ip_address = optional(string, null)
+ domain = optional(string, null)
+ name_prefix = optional(string, "cloudrun")
+ })
+ default = null
+}
+
+variable "enable_load_balancer" {
+ type = bool
+ description = "If true, creates the Global Load Balancer resources. Defaults to false."
+ default = false
+}
+
+variable "lb_ip_address" {
+ type = string
+ description = "Optional: Use an existing Global IP for Load Balancer. Leave empty to create a new one. (Only used if enable_load_balancer is true)"
+ default = null
+}
+
+variable "lb_domain" {
+ type = string
+ description = "Optional: Use an existing domain. Leave empty to use .sslip.io. (Only used if enable_load_balancer is true)"
+ default = null
+}