cloud-foundation-fabric/blueprints/serverless/cloud-run-microservices
Julio Diez 8435ad85f3 Address some style comments 2024-01-05 21:48:02 +01:00
..
images Add README content 2023-10-27 11:13:43 +02:00
README.md Address some style comments 2024-01-05 21:48:02 +01:00
alb.tf Use of new module cloud-run-v2 2023-12-28 17:30:41 +01:00
cloudrun.tf Address some style comments 2024-01-05 21:48:02 +01:00
dns.tf Use of new module cloud-run-v2 2023-12-28 17:30:41 +01:00
main.tf Use of new module cloud-run-v2 2023-12-28 17:30:41 +01:00
outputs.tf Use of new module cloud-run-v2 2023-12-28 17:30:41 +01:00
psc.tf Rename to ip_configs to follow same naming 2023-11-02 13:40:31 +01:00
variables.tf Rename to ip_configs to follow same naming 2023-11-02 13:40:31 +01:00
vpc.tf Rename to ip_configs to follow same naming 2023-11-02 13:40:31 +01:00

README.md

Cloud Run Microservices

Introduction

This blueprint contains all the necessary Terraform modules to deploy two microservices running in Cloud Run and communicating with each other.

The content of this blueprint corresponds to the chapter 'Microservices architectures - Developing Microservices applications' of the Serverless Networking Guide. This guide is an easy to follow introduction to Cloud Run, where a couple of friendly characters will guide you from the basics to more advanced topics with a very practical approach and in record time! The code here complements this learning and allows you to test the scenarios presented and your knowledge.

If you are interested in following this guide, take a look to the chapters' blueprints:

Prerequisites

Depending on the use case, you will need one or two projects with billing enabled and a user with the “Project owner” IAM role on those projects. You can use existing projects or let the blueprint create them for you but in that case you will need to add extra information for each project. E.g.:

project_configs = {
  main = {
    billing_account_id = "ABCDE-12345-ABCDE"
    parent             = "organizations/0123456789"
    project_id         = "spiritual-hour-331417"
  }
}

How to set this information is explained below.

Spinning up the architecture

General steps

  1. Clone the repo to your local machine or Cloud Shell:
git clone https://github.com/GoogleCloudPlatform/cloud-foundation-fabric
  1. Change to the directory of the blueprint:
cd cloud-foundation-fabric/blueprints/serverless/cloud-run-microservices

You should see this README and some terraform files.

  1. To deploy a specific use case, you will need to create a file in this directory called terraform.tfvars and follow the corresponding instructions to set variables. Values that are meant to be substituted will be shown inside brackets but you need to omit these brackets. E.g.:
project_configs = {
  main = {
    project_id = "[project_id]"
  }
}

may become

project_configs = {
  main = {
    project_id = "spiritual-hour-331417"
  }
}

Use cases are self-contained so you can deploy any of them at will.

  1. The usual terraform commands will do the work:
terraform init
terraform plan
terraform apply

It will take a few minutes. When complete, you should see an output stating the command completed successfully, a list of the created resources, and some output variables with information to access your services.

Congratulations! You have successfully deployed the use case you chose based on the variables configuration.

Use case 1: Service to service communication in the same project

This use case deploys two Cloud Run services in the same project. Service B is protected as an internal only service and communication between Cloud Run services, even in the same project, is not considered internal by default. To communicate them, one option is to use PSC/PGA (the second option is shown in the use case 2). We will use a PSC endpoint and a Serverless VPC connector to reach Service B. A DNS record for the PSC endpoint is created.

Service A uses an application with a GUI to test connectivity. You can find its source code in:

https://github.com/willypalacin/vpc-network-tester/tree/main

You will need to build an image and push it to Artifact Registry, setting the corresponding Terraform variable to its URL. Add the main project ID in terraform.tfvars. E.g.:

image_configs = {
  svc_a = "us-docker.pkg.dev/[project-id]/[repo-name]/[tester-app]"
}
prefix = "[prefix]"
project_configs = {
  main = {
    project_id = "[project_id]"
  }
}

Note that final project ids will be of the form "[prefix]-[project-id]".

The service B default URL is created and shown as a terraform output variable. It will be similar to the one shown in the picture above. Get into service A and try to reach service B URL as shown below:

You can see service A is resolving service B to an internal IP, 10.0.0.100, the PSC endpoint (see variable 'ip_configs'). Public access is restricted, if you try to e.g. curl from your laptop you will get an error.

Use case 2: Service to service communication in different projects

The second option for internal service to service communication is to use an internal Application Load Balancer (ALB). This use case extends the previous architecture using a Shared VPC and a service project. Instead of a VPC connector, it uses Direct VPC Egress which allows Cloud Run to directly use IPs from a subnet. And the ALB allows you to use a custom domain.

Set the following in terraform.tfvars:

image_configs = {
  svc_a = "us-docker.pkg.dev/[project-id]/[repo-name]/[tester-app]"
}
prefix = "[prefix]"
project_configs = {
  main = { # Used as host project
    project_id = "[project_id]"
  }
  service = {
    project_id = "[project_id]"
  }
}

The blueprint uses an HTTP connection to the ALB to avoid management of SSL certificates. Try to reach service B custom URL as shown below:

Cleaning up your environment

The easiest way to remove all the deployed resources is to run the following command:

terraform destroy

The above command will delete the associated resources so there will be no billable charges afterwards. Projects are removed from Terraform state but not deleted from Google Cloud.

Files

name description modules resources
alb.tf Internal Application Load Balancer resource. net-lb-app-int
cloudrun.tf Cloud Run services. cloud-run-v2
dns.tf DNS resources. dns
main.tf Project resources. project
outputs.tf Module outputs.
psc.tf Private Service Connect resources. net-address google_compute_global_forwarding_rule
variables.tf Module variables.
vpc.tf VPC resources. net-vpc

Variables

name description type required default
image_configs Container images for Cloud Run services. object({…})
prefix Prefix used for project names. string
custom_domain Custom domain for the Load Balancer. string "service-b.acme.org"
ip_configs IP ranges or IPs used by the VPC. map(string) {…}
project_configs Projects to use, one project or host and service projects. map(object({…})) {…}
region Cloud region where resources will be deployed. string "europe-west1"

Outputs

name description sensitive
custom_domain Custom domain for the Application Load Balancer.
default_URLs Cloud Run services default URLs.
load_balancer_ip Load Balancer IP address.

Tests

module "test" {
  source = "./fabric/blueprints/serverless/cloud-run-microservices"
  image_configs = {
    svc_a = "cloud-run-image"
  }
  prefix = "prefix"
  project_configs = {
    main = {
      billing_account_id = "ABCDE-12345-ABCDE"
      parent             = "organizations/0123456789"
      project_id         = "main-project-id"
    }
  }
}

# tftest modules=7 resources=22
module "test" {
  source = "./fabric/blueprints/serverless/cloud-run-microservices"
  image_configs = {
    svc_a = "cloud-run-image"
  }
  prefix = "prefix"
  project_configs = {
    main = { # Used as host project
      billing_account_id = "ABCDE-12345-ABCDE"
      parent             = "organizations/0123456789"
      project_id         = "main-project-id"
    }
    service = {
      billing_account_id = "ABCDE-12345-ABCDE"
      parent             = "organizations/0123456789"
      project_id         = "service-project-id"
    }
  }
}

# tftest modules=10 resources=32