Terraform module for a multi-region Google Cloud Run v2 Service behind a serverless Network Endpoint Group (NEG).
Variables support GPUs, GCS mounts, ordered multi-container startup, service ingress, custom audiences, request timeout, max concurrency, labels, CPU allocation, and startup/liveness HTTP probes. Containers use request-scoped CPU by default; set cpu_idle = false for background workers that must continue after an HTTP response. GPU containers always keep CPU allocated.
Set vpc_direct_egress to PRIVATE_RANGES_ONLY or ALL_TRAFFIC. The module retains its compatible default network and subnet defaults. To configure only one interface field, set the other explicitly to null; Cloud Run then infers the omitted network or same-named regional subnet as described in Direct VPC configuration. Enabling egress with both fields set to null is rejected during planning. A fully qualified subnet must embed the same region as each Cloud Run service. For a multi-region service, use network-only inference with a same-named subnet in every region or use separate module instances so each region receives an explicit subnet.
Direct VPC is the outbound VPC leg for Cloud Run services; it does not provide Direct VPC ingress to a service. Requests can still enter through the service's configured Cloud Run ingress, but a service reaching a VM or other private destination uses Direct VPC egress.
This module configures the Cloud Run attachment, but the caller owns its network prerequisites. Use an IPv4 subnet of /26 or larger from RFC 1918, RFC 6598 (100.64.0.0/10), or Class E (240.0.0.0/4), and retain Google Cloud's default network MTU of 1460. The Cloud Run service agent normally receives roles/run.serviceAgent in its service project. For Shared VPC, grant that service-project agent either roles/compute.networkUser on the host project, or roles/compute.networkViewer on the host project plus roles/compute.networkUser on the selected subnet. Authorize destination ingress from the entire subnet CIDR rather than ephemeral instance addresses; Cloud Run network tags and service identities cannot identify the source of an ingress firewall rule.
Cloud Run reserves addresses in /28 blocks during scale-up and uses roughly twice the steady-state instance count. Leave additional capacity for overlapping revisions, and wait 1–2 hours after disconnecting Cloud Run before deleting a subnet. Applications must tolerate occasional connection resets during network maintenance. If all traffic exits through Cloud NAT, account for the documented cold-start delay or evaluate a Serverless VPC Access connector when startup latency is more important than connector cost.
For a service protected by an external Application Load Balancer and Cloud Armor, set ingress = "INGRESS_TRAFFIC_INTERNAL_LOAD_BALANCER", default_uri_disabled = true, and launch_stage = "BETA". Disabling the default run.app URL prevents callers from bypassing the load balancer policy. This Cloud Run feature is currently Preview. It also prevents products that invoke the default URL directly, including Cloud Scheduler, Cloud Tasks, Eventarc, Pub/Sub, Workflows, and uptime checks, from reaching the service; configure another supported endpoint before enabling it.
The legacy startup_probe = "/startup" container attribute remains supported. Use startup_probe_config when timing controls are required:
containers = [{
image = "us-docker.pkg.dev/example/project/app:latest"
name = "app"
port = 8080
startup_probe_config = {
path = "/startup"
port = 8080
initial_delay_seconds = 10
timeout_seconds = 2
period_seconds = 5
failure_threshold = 12
}
}]Probe settings are validated against Cloud Run's startup-probe limits. If both forms are set, startup_probe_config takes precedence. For Direct VPC readiness, the endpoint must verify a connection to an egress dependency before reporting success; either the endpoint can retry internally or it can return failure so Cloud Run retries it within the configured period and threshold window. A generic process-only endpoint does not cover the documented startup connection delay. Probe paths are part of the service's HTTP surface and are reachable by clients allowed through its ingress and authentication policy, so keep responses non-sensitive and make the handler free of state-changing side effects.
For a multi-container service, set depends_on on the dependent container and
give every dependency a startup probe. Cloud Run waits for those probes before
starting the dependent container:
containers = [
{
image = "us-docker.pkg.dev/example/project/vault@sha256:..."
name = "vault"
startup_probe_config = {
path = "/v1/sys/health?uninitcode=200"
port = 8200
timeout_seconds = 2
period_seconds = 5
failure_threshold = 48
}
},
{
image = "us-docker.pkg.dev/example/project/proxy@sha256:..."
name = "proxy"
port = 8080
depends_on = ["vault"]
},
]List dependencies before the containers that depend on them. Dependency names must be unique container names in the same service. Self, duplicate, forward, and unknown dependencies are rejected during planning, which also prevents dependency cycles.
| Name | Version |
|---|---|
| ~> 7.0 |
| Name | Version |
|---|---|
| ~> 7.0 |
No modules.
| Name | Type |
|---|---|
| google_cloud_run_v2_service.cloudrun | resource |
| google_cloud_run_v2_service_iam_member.invoker | resource |
| google_compute_backend_service.backend | resource |
| google_compute_region_network_endpoint_group.neg | resource |
| google_service_account.service_account | data source |
| Name | Description | Type | Default | Required |
|---|---|---|---|---|
| addl_env_vars | Additional environment variables to set in containers | list(object({ |
[] |
no |
| containers | List of container configurations to run in the service. At least one container needs a port. cpu_idle defaults to request-scoped CPU for non-GPU containers; set it false when background work needs CPU outside requests. GPU containers always disable CPU idling. depends_on names containers that must pass their startup probes before this container starts. startup_probe_config takes precedence over the legacy startup_probe path when both are set. | list(object({ |
n/a | yes |
| custom_audiences | Custom audiences accepted by each Cloud Run service. | list(string) |
[] |
no |
| default_uri_disabled | Whether to disable the service's default run.app URL. This preview feature requires launch_stage ALPHA or BETA. | bool |
false |
no |
| deletion_protection | Whether to enable deletion protection on the Cloud Run service. | bool |
false |
no |
| empty_dir_volumes | List of empty directory volumes to create and mount | list(object({ |
[] |
no |
| gcs_volumes | List of Google Cloud Storage buckets to mount as volumes. Must ensure the Cloud Run GSA has proper IAM set on the bucket | list(object({ |
[] |
no |
| gsa | Service account name the Cloud Run service will run as. If empty, creates a new one. | string |
n/a | yes |
| ingress | Cloud Run ingress setting. | string |
"INGRESS_TRAFFIC_ALL" |
no |
| invokers | List of members to grant Cloud Run invoker role | list(string) |
[ |
no |
| labels | Labels to apply to each Cloud Run service. | map(string) |
{} |
no |
| launch_stage | Cloud Run launch stage for the service. | string |
"GA" |
no |
| max_instance_request_concurrency | Optional maximum concurrent requests per Cloud Run instance. | number |
null |
no |
| max_instances | Maximum number of instances to scale to | string |
"100" |
no |
| min_instances | Minimum number of instances to keep running | string |
"0" |
no |
| name | Name of the Cloud Run service | string |
n/a | yes |
| project | The GCP project to use | string |
n/a | yes |
| regions | The GCP region(s) to deploy to | list(string) |
[ |
no |
| secrets | List of Secret Manager secrets to mount as environment variables | list(object({ |
[] |
no |
| skipNeg | Skip creating Network Endpoint Group and Backend Service | bool |
false |
no |
| timeout_seconds | Optional request timeout for each Cloud Run service, in seconds. | number |
null |
no |
| vpc_direct_egress | Traffic VPC egress setting. Set to OFF, ALL_TRAFFIC, or PRIVATE_RANGES_ONLY. |
string |
"OFF" |
no |
| vpc_direct_egress_network | VPC network for Direct VPC egress. Set this or vpc_direct_egress_subnetwork to null to let Cloud Run infer the omitted field. | string |
"default" |
no |
| vpc_direct_egress_subnetwork | VPC subnetwork from which Cloud Run receives IPs. Set this or vpc_direct_egress_network to null to let Cloud Run infer the omitted field. | string |
"default" |
no |
| vpc_direct_egress_tags | Network tags applied to this Cloud Run service | list(string) |
null |
no |
| Name | Description |
|---|---|
| backend | Backend service ID for load balancer (empty if skipNeg is true) |
| name | Map of region to Cloud Run service names |
| url | Primary Cloud Run service URL (first region) |
| urls | Map of region to Cloud Run service URLs |