Serve traffic from multiple regions

You can return faster responses to your users around the world by deploying services in multiple regions and routing your users to the nearest region. Deploying across multiple regions delivers low latency and higher availability in case of regional outages.

Because Cloud Run services are deployed into individual regions, you'll need to deploy your service to multiple regions and then configure global load balancing for the service.

Deploy the service to multiple regions

You can deploy the same service to multiple regions using one of the following methods:

Deploy a multi-region service

This section shows you how to deploy and configure a multi-region service from a single gcloud CLI command.

  • To create and deploy a multi-region service, run the gcloud beta run deploy command using the --regions flag:

    gcloud beta run deploy SERVICE_NAME \
      --image=IMAGE_URL \
      --regions=REGIONS

    Replace the following:

    • SERVICE_NAME: The name of the multi-region service that you want to deploy.
    • IMAGE_URL: A reference to the container image, for example, us-docker.pkg.dev/cloudrun/container/hello:latest.
    • REGIONS: The list of multiple regions that you want to deploy to. For example, us-central1,asia-east1.

Update a multi-region service

You can update a multi-region Cloud Run service by running the gcloud beta run multi-region services command, using the same settings that you use to update a Cloud Run service. To add or remove regions from a multi-region service, run the gcloud beta run multi-region-services update command.

  • To add the multi-region service to an additional region or regions, use the --add-regions flag:

    gcloud beta run multi-region-services update SERVICE_NAME \
      --add-regions=REGIONS
  • To remove the multi-region service from a region or regions, use the --remove-regions flag:

    gcloud beta run multi-region-services update SERVICE_NAME \
      --remove-regions=REGIONS

    Replace the following:

  • SERVICE_NAME: The name of the multi-region service that you want to update.

  • REGIONS: The region or regions that you want to add your service to or remove your service from. For example, us-central1,asia-east1.

Delete a multi-region service

  • To delete a multi-region service, run the gcloud beta run multi-region-services delete command:

    gcloud beta run multi-region-services delete SERVICE_NAME

    Replace SERVICE_NAME with the name of the multi-region service that you want to delete.

Configure global load balancing

This section shows you how to configure an external Application Load Balancer with a domain secured with a managed TLS certificate pointing to a global anycast IP address, which routes users to the nearest Google data center that deploys your service.

The architecture described in this section does not automatically route requests to a different region when a regional Cloud Run service becomes unresponsive or starts returning errors. To increase the availability of your multi-regional service, you can configure outlier detection to identify unhealthy Cloud Run services based on their HTTP error rate and diverge some requests to another region.

Create a load balancer

Creating an external load balancer involves creating various networking resources and connecting them together:

gcloud CLI

  1. Reserve a static IP address so you don't have to update your DNS records when you recreate your load balancer.
    gcloud compute addresses create --global SERVICE_IP
    In the command above, replace SERVICE_IP with a name for the IP address resource (e.g. myservice-ip).

    This IP address is a global anycast IPv4 address that routes to the Google datacenter or point of presence closest to your visitors.

  2. Create a backend service.
    gcloud compute backend-services create --global BACKEND_NAME

    In the command above, replace BACKEND_NAME with a name you want to give to the backend service (e.g. myservice-backend).

  3. Create a URL map.
    gcloud compute url-maps create URLMAP_NAME --default-service=BACKEND_NAME

    Replace URLMAP_NAME with a name you want to give to the URL map (e.g. myservice-urlmap).

  4. Create a managed TLS certificate for your domain to serve HTTPS traffic. (Replace example.com with your domain name.)
    gcloud compute ssl-certificates create CERT_NAME \
      --domains=example.com

    Replace CERT_NAME with the name you want the managed SSL certificate to have (e.g. myservice-cert).

  5. Create a target HTTPS proxy.
    gcloud compute target-https-proxies create HTTPS_PROXY_NAME \
      --ssl-certificates=CERT_NAME \
      --url-map=URLMAP_NAME

    Replace HTTPS_PROXY_NAME with the name you want to give to the target HTTPS proxy (e.g. myservice-https).

  6. Create a forwarding rule connecting the networking resources you created to the IP address.
    gcloud compute forwarding-rules create --global FORWARDING_RULE_NAME \
      --target-https-proxy=HTTPS_PROXY_NAME \
      --address=SERVICE_IP \
      --ports=443

    Replace FORWARDING_RULE_NAME with the name of the forwarding rule resource you want to create (e.g. myservice-lb).

Terraform

Alternatively to the steps described in this section, you can use the Global HTTP Load Balancer Terraform Module.

Add the following to your Terraform file (for example main.tf):

  1. Configure the IP address:

    resource "google_compute_global_address" "lb_default" {
      provider = google-beta
      name     = "myservice-service-ip"
    
      # Use an explicit depends_on clause to wait until API is enabled
      depends_on = [
        google_project_service.compute_api
      ]
    }
    output "load_balancer_ip_addr" {
      value = google_compute_global_address.lb_default.address
    }

    Configures your IP address resource name to be myservice-service-ip. You can change this to your own value. This IP address is a global anycast IPv4 address that routes to the Google data center or point of presence closest to your visitors.

  2. Create and configure the backend service:

    resource "google_compute_backend_service" "lb_default" {
      provider              = google-beta
      name                  = "myservice-backend"
      load_balancing_scheme = "EXTERNAL_MANAGED"
    
      backend {
        group = google_compute_region_network_endpoint_group.lb_default[0].id
      }
    
      backend {
        group = google_compute_region_network_endpoint_group.lb_default[1].id
      }
    
      # Use an explicit depends_on clause to wait until API is enabled
      depends_on = [
        google_project_service.compute_api,
      ]
    }

    This resource configures the backend service to be named myservice-backend. You can change this to your own value.

  3. Configure the URL map:

    resource "google_compute_url_map" "lb_default" {
      provider        = google-beta
      name            = "myservice-lb-urlmap"
      default_service = google_compute_backend_service.lb_default.id
    
      path_matcher {
        name            = "allpaths"
        default_service = google_compute_backend_service.lb_default.id
        route_rules {
          priority = 1
          url_redirect {
            https_redirect         = true
            redirect_response_code = "MOVED_PERMANENTLY_DEFAULT"
          }
        }
      }
    }

    Connects the backend service resource (myservice-backend) to the new URL map resource (myservice-lb-urlmap). You can change these to your own values.

  4. Create a managed TLS certificate for your domain to serve HTTPS traffic. Replace example.com with your domain name in the google_compute_managed_ssl_certificate resource:

    resource "google_compute_managed_ssl_certificate" "lb_default" {
      provider = google-beta
      name     = "myservice-ssl-cert"
    
      managed {
        domains = ["example.com"]
      }
    }
  5. Configure the HTTPS proxy:

    resource "google_compute_target_https_proxy" "lb_default" {
      provider = google-beta
      name     = "myservice-https-proxy"
      url_map  = google_compute_url_map.lb_default.id
      ssl_certificates = [
        google_compute_managed_ssl_certificate.lb_default.name
      ]
      depends_on = [
        google_compute_managed_ssl_certificate.lb_default
      ]
    }

    Creates google_compute_target_https_proxy resource with target name myservice-https-proxy and connects previously created TLS certificate (myservice-ssl-cert) and URL mapping resources (myservice-lb-urlmap). You can change these to your own values.

  6. Configure the forwarding rule:

    resource "google_compute_global_forwarding_rule" "lb_default" {
      provider              = google-beta
      name                  = "myservice-lb-fr"
      load_balancing_scheme = "EXTERNAL_MANAGED"
      target                = google_compute_target_https_proxy.lb_default.id
      ip_address            = google_compute_global_address.lb_default.id
      port_range            = "443"
      depends_on            = [google_compute_target_https_proxy.lb_default]
    }

    Creates google_compute_global_forwarding_rule resource with target name myservice-https-proxy and connects previously created HTTPS proxy target (myservice-https-proxy) and IP address resource (myservice-service-ip). You can change these to your own values.

  7. Apply this config:

    To apply your Terraform configuration in a Google Cloud project, complete the steps in the following sections.

    Prepare Cloud Shell

    1. Launch Cloud Shell.
    2. Set the default Google Cloud project where you want to apply your Terraform configurations.

      You only need to run this command once per project, and you can run it in any directory.

      export GOOGLE_CLOUD_PROJECT=PROJECT_ID

      Environment variables are overridden if you set explicit values in the Terraform configuration file.

    Prepare the directory

    Each Terraform configuration file must have its own directory (also called a root module).

    1. In Cloud Shell, create a directory and a new file within that directory. The filename must have the .tf extension—for example main.tf. In this tutorial, the file is referred to as main.tf.
      mkdir DIRECTORY && cd DIRECTORY && touch main.tf
    2. If you are following a tutorial, you can copy the sample code in each section or step.

      Copy the sample code into the newly created main.tf.

      Optionally, copy the code from GitHub. This is recommended when the Terraform snippet is part of an end-to-end solution.

    3. Review and modify the sample parameters to apply to your environment.
    4. Save your changes.
    5. Initialize Terraform. You only need to do this once per directory.
      terraform init

      Optionally, to use the latest Google provider version, include the -upgrade option:

      terraform init -upgrade

    Apply the changes

    1. Review the configuration and verify that the resources that Terraform is going to create or update match your expectations:
      terraform plan

      Make corrections to the configuration as necessary.

    2. Apply the Terraform configuration by running the following command and entering yes at the prompt:
      terraform apply

      Wait until Terraform displays the "Apply complete!" message.

    3. Open your Google Cloud project to view the results. In the Google Cloud console, navigate to your resources in the UI to make sure that Terraform has created or updated them.

Configure regional network endpoint groups

For each region you deployed to in the previous step, you must create serverless network endpoint groups (NEGs) and add them to the backend service by using the following instructions:

gcloud CLI

  1. Create a network endpoint group for the Cloud Run service in REGION:

    gcloud compute network-endpoint-groups create NEG_NAME \
      --region=REGION \
      --network-endpoint-type=SERVERLESS \
      --cloud-run-service=SERVICE_NAME

    Replace the following:

    • NEG_NAME with the name of the network endpoint group resource. (e.g. `myservice-neg-uscentral1`)
    • REGION with the [region][loc] your service is deployed in.
    • SERVICE_NAME with the name of your service.
  2. Add the network endpoint group to the backend service:

    gcloud compute backend-services add-backend --global BACKEND_NAME \
      --network-endpoint-group-region=REGION \
      --network-endpoint-group=NEG_NAME

    Specify the NEG_NAME you have created in the previous step for the region.

  3. Repeat the preceding steps for each region.

Terraform

  1. Configure a network endpoint group with name myservice-neg for the Cloud Run service for each region specified in run_regions variable:

    resource "google_compute_region_network_endpoint_group" "lb_default" {
      provider              = google-beta
      count                 = length(local.run_regions)
      name                  = "myservice-neg"
      network_endpoint_type = "SERVERLESS"
      region                = local.run_regions[count.index]
      cloud_run {
        service = google_cloud_run_v2_service.run_default[count.index].name
      }
    }
  2. Configure a backend service to attach the network endpoint group (myservice-neg):

    resource "google_compute_backend_service" "lb_default" {
      provider              = google-beta
      name                  = "myservice-backend"
      load_balancing_scheme = "EXTERNAL_MANAGED"
    
      backend {
        group = google_compute_region_network_endpoint_group.lb_default[0].id
      }
    
      backend {
        group = google_compute_region_network_endpoint_group.lb_default[1].id
      }
    
      # Use an explicit depends_on clause to wait until API is enabled
      depends_on = [
        google_project_service.compute_api,
      ]
    }

Configure DNS records on your domain

To point your domain name to the forwarding rule you created, you must update its DNS records with the IP address that you created.

  1. Find the reserved IP address of the load balancer by running the following command:

    gcloud compute addresses describe \
      --global SERVICE_IP \
      --format='value(address)'

    Replace SERVICE_IP with the name of the IP address you created previously. This command prints the IP address to the output.

  2. Update your domain's DNS records by adding an A record with this IP address.

Configure custom audience if using authenticated services

Authenticated services are protected by IAM. Such Cloud Run services require client authentication that declares the intended recipient of a request at credential generation time (the audience).

Audience is usually the full URL of the target service, which by default for Cloud Run services is a generated URL ending in run.app. However, in a multi-region deployment, it is not possible for a client to know in advance which regional service a request will be routed to. So, for a multi-region deployment, configure your service to use custom audiences.

Wait for load balancer to provision

After configuring the domain with the load balancer IP address, you must wait for DNS records to propagate. Similarly, you must wait for the managed TLS certificate to be issued for your domain and to become ready to start serving HTTPS traffic globally.

It might take up to 30 minutes for your load balancer to start serving traffic.

After it's ready, visit your website's URL with https:// prefix to try it out.

Verify status

  1. To check the status of your DNS record propagation, use the dig command-line utility:

    dig A +short example.com

    The output shows the IP address that you configured in your DNS records.

  2. Check the status of your managed certificate issuance by running the following command:

    gcloud compute ssl-certificates describe CERT_NAME

    Replace CERT_NAME with the name you previously chose for the SSL certificate resource.

    The output shows a line containing status: ACTIVE.

Set up HTTP-to-HTTPS redirect

By default, a forwarding rule only handles a single protocol and therefore requests to your http:// endpoints respond with "404 Not Found". If you need requests to your http:// URLs to be redirected to the https:// protocol, you must create an additional URL map and a forwarding rule by using the following instructions:

gcloud CLI

  1. Create a URL map with a redirect rule.

    gcloud compute url-maps import HTTP_URLMAP_NAME \
      --global \
      --source /dev/stdin <<EOF
            name: HTTP_URLMAP_NAME
            defaultUrlRedirect:
              redirectResponseCode: MOVED_PERMANENTLY_DEFAULT
              httpsRedirect: True
            EOF

    Replace the HTTP_URLMAP_NAME with the name of the URL map resource you will create (for example, myservice-httpredirect).

  2. Create a target HTTP proxy with the URL map.

    gcloud compute target-http-proxies create HTTP_PROXY_NAME \
      --url-map=HTTP_URLMAP_NAME

    Replace HTTP_PROXY_NAME with the name of the target HTTP proxy you will create (for example, myservice-http).

  3. Create a forwarding rule on port 80 with the same reserved IP address.

    gcloud compute forwarding-rules create --global HTTP_FORWARDING_RULE_NAME \
      --target-http-proxy=HTTP_PROXY_NAME \
      --address=SERVICE_IP \
      --ports=80
            

    Replace HTTP_FORWARDING_RULE_NAME with the name of the new forwarding rule you will create (for example, myservice-httplb).

Terraform

  1. Create a URL map resource with a redirect rule:

    resource "google_compute_url_map" "https_default" {
      provider = google-beta
      name     = "myservice-https-urlmap"
    
      default_url_redirect {
        redirect_response_code = "MOVED_PERMANENTLY_DEFAULT"
        https_redirect         = true
        strip_query            = false
      }
    }
  2. Create a target HTTP proxy with the newly created URL map resource (myservice-https-urlmap):

    resource "google_compute_target_http_proxy" "https_default" {
      provider = google-beta
      name     = "myservice-http-proxy"
      url_map  = google_compute_url_map.https_default.id
    
      depends_on = [
        google_compute_url_map.https_default
      ]
    }
  3. Create a forwarding rule on port 80 with the same reserved IP address resource (myservice-http-proxy):

    resource "google_compute_global_forwarding_rule" "https_default" {
      provider   = google-beta
      name       = "myservice-https-fr"
      target     = google_compute_target_http_proxy.https_default.id
      ip_address = google_compute_global_address.lb_default.id
      port_range = "80"
      depends_on = [google_compute_target_http_proxy.https_default]
    }

Use authenticated Pub/Sub push subscriptions with multi-region deployment

A Pub/Sub service by default delivers messages to push endpoints in the same Google Cloud region where the Pub/Sub service stores the messages. For a workaround to this behavior, refer to Using an authenticated Pub/Sub push subscription with a multi-region Cloud Rundeployment.