From e4902a4dd4de6357710fde94e46f1fe6f17b994f Mon Sep 17 00:00:00 2001 From: Julio Diez Date: Sun, 15 Oct 2023 13:20:02 +0200 Subject: [PATCH] Two CR services talking, initial commit --- .../cloud-run-microservices/main.tf | 272 ++++++++++++++++++ .../cloud-run-microservices/outputs.tf | 25 ++ .../cloud-run-microservices/variables.tf | 76 +++++ 3 files changed, 373 insertions(+) create mode 100644 blueprints/serverless/cloud-run-microservices/main.tf create mode 100644 blueprints/serverless/cloud-run-microservices/outputs.tf create mode 100644 blueprints/serverless/cloud-run-microservices/variables.tf diff --git a/blueprints/serverless/cloud-run-microservices/main.tf b/blueprints/serverless/cloud-run-microservices/main.tf new file mode 100644 index 000000000..5c93b6e0a --- /dev/null +++ b/blueprints/serverless/cloud-run-microservices/main.tf @@ -0,0 +1,272 @@ +/** + * Copyright 2023 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 + * + * 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. + */ + +locals { + cloud_run_domain = "run.app." +} + +############################################################################### +# Projects # +############################################################################### + +# Main project +module "project_main" { + source = "../../../modules/project" + name = var.prj_main_id + project_create = var.prj_main_create != null + billing_account = try(var.prj_main_create.billing_account_id, null) + parent = try(var.prj_main_create.parent, null) + # Enable Shared VPC by default, some use cases will use this project as host + shared_vpc_host_config = { + enabled = true + } + services = [ + "run.googleapis.com", + "compute.googleapis.com", + "dns.googleapis.com", + "vpcaccess.googleapis.com" + # "cloudresourcemanager.googleapis.com" + ] + skip_delete = true +} + +# Service Project 1 +module "project_svc1" { + source = "../../../modules/project" + count = var.prj_svc1_id != null ? 1 : 0 + name = var.prj_svc1_id + project_create = var.prj_svc1_create != null + billing_account = try(var.prj_svc1_create.billing_account_id, null) + parent = try(var.prj_svc1_create.parent, null) + shared_vpc_service_config = { + host_project = module.project_main.project_id + # service_identity_iam = { + # "roles/compute.networkUser" = [ + # "vpcaccess" + # ], + # "roles/editor" = [ + # "cloudservices" + # ] + # } + } + services = [ + "compute.googleapis.com", + # "dns.googleapis.com", + "run.googleapis.com", + ] + skip_delete = true +} + +############################################################################### +# Cloud Run # +############################################################################### + +# Cloud Run service acting as client +module "cloud_run_client" { + source = "../../../modules/cloud-run" + project_id = module.project_main.project_id + name = "client" + region = var.region + containers = { + default = { + image = var.image + } + } + iam = { + "roles/run.invoker" = ["allUsers"] + } + ingress_settings = "all" + revision_annotations = { + vpcaccess_connector = try(google_vpc_access_connector.connector[0].name, null) + } +} + +# Cloud Run service acting as server +module "cloud_run_server" { + source = "../../../modules/cloud-run" + project_id = try(module.project_svc1[0].project_id, module.project_main.project_id) + name = "server" + region = var.region + containers = { + default = { + image = var.image + } + } + iam = { + "roles/run.invoker" = ["allUsers"] + } + ingress_settings = "internal" +} + +# VPC Access connector +# The use case where both Cloud Run services are in the same project uses +# a VPC access connector to connect from client to server service. +# The use case with Shared VPC and internal ALB uses Direct VPC Egress. +resource "google_vpc_access_connector" "connector" { + count = var.prj_svc1_id == null ? 1 : 0 + name = "connector" + project = module.project_main.project_id + region = var.region + subnet { + name = module.vpc_main.subnets["${var.region}/subnet-vpc-access"].name + project_id = module.project_main.project_id + } +} + +############################################################################### +# VPCs # +############################################################################### + +# VPC in main project +module "vpc_main" { + source = "../../../modules/net-vpc" + project_id = module.project_main.project_id + name = "vpc-main" + subnets = [ + { # regular subnet + ip_cidr_range = var.ip_ranges["main"].subnet + name = "subnet-main" + region = var.region + }, + { # subnet for the VPC access connector + ip_cidr_range = var.ip_ranges["main"].subnet_vpc_access + name = "subnet-vpc-access" + region = var.region + }, + { # subnet for use in Direct VPC Egress + ip_cidr_range = var.ip_ranges["main"].subnet_vpc_direct + name = "subnet-vpc-direct" + region = var.region + } + ] + subnets_proxy_only = [ + { # subnet for internal ALB + ip_cidr_range = var.ip_ranges["main"].subnet_proxy + name = "subnet-proxy" + region = var.region + active = true + } + ] +} + +# # Main VPC Firewall with default config, IAP for SSH enabled +# module "firewall_main" { +# source = "../../../modules/net-vpc-firewall" +# project_id = module.project_main.project_id +# network = module.vpc_main.name +# default_rules_config = { +# http_ranges = [] +# https_ranges = [] +# } +# } + +############################################################################### +# PSC # +############################################################################### + +# PSC configured in the main project +module "psc_addr_main" { + source = "../../../modules/net-address" + project_id = module.project_main.project_id + psc_addresses = { + psc-addr = { + address = var.ip_ranges["main"].psc_addr + network = module.vpc_main.self_link + } + } +} + +resource "google_compute_global_forwarding_rule" "psc_endpoint_main" { + provider = google-beta + project = module.project_main.project_id + name = "pscaddr" + network = module.vpc_main.self_link + ip_address = module.psc_addr_main.psc_addresses["psc-addr"].self_link + target = "vpc-sc" + load_balancing_scheme = "" +} + +############################################################################### +# internal ALB # +############################################################################### + +module "int-alb" { + source = "../../../modules/net-lb-app-int" + count = var.prj_svc1_id != null ? 1 : 0 + project_id = module.project_main.project_id + name = "int-alb-cr" + region = var.region + backend_service_configs = { + default = { + project_id = module.project_svc1[0].project_id + backends = [{ + group = "cr-neg" + }] + health_checks = [] + } + } + health_check_configs = {} + neg_configs = { + cr-neg = { + project_id = module.project_svc1[0].project_id + cloudrun = { + region = var.region + target_service = { + name = "server" + } + } + } + } + vpc_config = { + network = module.vpc_main.self_link + subnetwork = module.vpc_main.subnet_self_links["${var.region}/subnet-main"] + } +} + +############################################################################### +# DNS # +############################################################################### + +module "private_dns_main" { + source = "../../../modules/dns" + project_id = module.project_main.project_id + name = "cloud-run" + zone_config = { + domain = local.cloud_run_domain + private = { + client_networks = [module.vpc_main.self_link] + } + } + recordsets = { + "A *" = { records = [module.psc_addr_main.psc_addresses["psc-addr"].address] } + } +} + +module "private_dns_main_custom" { + source = "../../../modules/dns" + count = var.prj_svc1_id != null ? 1 : 0 + project_id = module.project_main.project_id + name = "cloud-run-custom" + zone_config = { + domain = format("%s.", var.custom_domain) + private = { + client_networks = [module.vpc_main.self_link] + } + } + recordsets = { + "A " = { records = [module.int-alb[0].address] } + } +} diff --git a/blueprints/serverless/cloud-run-microservices/outputs.tf b/blueprints/serverless/cloud-run-microservices/outputs.tf new file mode 100644 index 000000000..2511dac4d --- /dev/null +++ b/blueprints/serverless/cloud-run-microservices/outputs.tf @@ -0,0 +1,25 @@ +/** + * Copyright 2023 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 + * + * 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. + */ + +output "default_URL_client" { + description = "Client Cloud Run service default URL." + value = module.cloud_run_client.service.status[0].url +} + +output "load_balancer_ip" { + description = "Load Balancer IP address." + value = var.prj_svc1_id != null ? module.int-alb[0].address : "none" +} diff --git a/blueprints/serverless/cloud-run-microservices/variables.tf b/blueprints/serverless/cloud-run-microservices/variables.tf new file mode 100644 index 000000000..8eab4991f --- /dev/null +++ b/blueprints/serverless/cloud-run-microservices/variables.tf @@ -0,0 +1,76 @@ +/** + * Copyright 2023 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 + * + * 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. + */ + +variable "custom_domain" { + description = "Custom domain for the Load Balancer." + type = string + default = "server.example.org" +} + +variable "image" { + description = "Container image to deploy." + type = string + default = "us-docker.pkg.dev/cloudrun/container/hello" +} + +variable "ip_ranges" { + description = "IPs or IP ranges used by VPCs." + type = map(map(string)) + default = { + main = { + subnet = "10.0.1.0/24" + subnet_proxy = "10.10.0.0/24" + subnet_vpc_access = "10.10.10.0/28" + subnet_vpc_direct = "10.8.0.0/28" + psc_addr = "10.0.0.100" + } + } +} + +variable "prj_main_create" { + description = "Parameters for the creation of the main project." + type = object({ + billing_account_id = string + parent = string + }) + default = null +} + +variable "prj_main_id" { + description = "Main Project ID." + type = string +} + +variable "prj_svc1_create" { + description = "Parameters for the creation of service project 1." + type = object({ + billing_account_id = string + parent = string + }) + default = null +} + +variable "prj_svc1_id" { + description = "Service Project 1 ID." + type = string + default = null +} + +variable "region" { + description = "Cloud region where resources will be deployed." + type = string + default = "europe-west1" +}