FAQ | This is a LIVE service | Changelog

Commit 20d138e7 authored by Dr Rich Wareham's avatar Dr Rich Wareham
Browse files

Merge branch '24-add-lb-config' into 'v4'

Resolve "Adding LB config for load-balanced Cloud Run services"

See merge request !32
parents 9409efef 15a19906
Pipeline #103918 passed with stage
in 48 seconds
......@@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [4.1.0] - 2021-07-28
### Added
- Support load balancer ingress style alongside Cloud Run domain mapping.
## [4.0.1] - 2021-07-15
### Changed
- Surface Cloud NAT variable for minimum number of SNAT tuples, supporting a larger
......
......@@ -24,14 +24,24 @@ The `master` branch contains the tip of development and corresponds to the `v2`
branch. The `v1` branch will maintain source compatibility with the initial
release.
## Custom domain mapping
## Ingress style
There are two supported ingress styles depending on `var.ingress_style` variable.
Setting the `dns_name` will create a domain mapping for the webapp. Before
setting this value you *must* have verified ownership of the domain with Google.
[Instructions on how to do
`var.ingress_style` can be:
- `domain-mapping` (default): passing DNS domains as `var.dns_names` or `var.dns_name`,
which takes precedence over `var.dns_names`, will create domain mappings to the Cloud
Run service. Before setting this, you *must* have verified ownership of the provided
domains with Google. [Instructions on how to do
this](https://guidebook.devops.uis.cam.ac.uk/en/latest/notes/google-domain-verification/)
can be found in the DevOps division guidebook.
- `load-balancer`: a load balancer will be configured instead of a domain mapping. The
DNS domains in `var.dns_names` or `var.dns_name`, which takes precedence over `var.dns_names`,
will get Google-managed or custom TLS certificates depending on `var.use_ssl_certificates`
and `var.ssl_certificates`. An IPv6 address can also be allocated to the load balancer if
`var.enable_ipv6` is `true`.
## Monitoring and Alerting
If the variable [alerting_email_address](variables.tf) is set, the module adds
......
# load_balancer.tf configures Cloud Load Balancer resources for the Cloud Run
# service if var.ingress_style == "load-balancer".
# A network endpoint group for the "webapp" application.
resource "google_compute_region_network_endpoint_group" "webapp" {
count = var.ingress_style == "load-balancer" ? 1 : 0
name = var.name
network_endpoint_type = "SERVERLESS"
region = var.cloud_run_region
cloud_run {
service = google_cloud_run_service.webapp.name
}
provider = google-beta
}
# A load balancer for the "webapp" application. This is just a set of sane
# defaults. See the full documentation at [1] for customisation.
#
# [1] https://registry.terraform.io/modules/GoogleCloudPlatform/lb-http/google/latest/submodules/serverless_negs
module "webapp_http_load_balancer" {
for_each = toset([for neg in google_compute_region_network_endpoint_group.webapp : neg.id])
# The double slash is important(!)
source = "GoogleCloudPlatform/lb-http/google//modules/serverless_negs"
version = "~> 5.0"
project = var.project
name = var.name
ssl = true
https_redirect = true
# Use custom TLS certs if var.use_ssl_certificates is true, otherwise, use the Google-managed certs.
use_ssl_certificates = var.use_ssl_certificates
ssl_certificates = var.ssl_certificates
managed_ssl_certificate_domains = local.dns_names
# Whether to create an IPv6 address to the load balancer.
enable_ipv6 = var.enable_ipv6
create_ipv6_address = var.create_ipv6_address
backends = {
default = {
description = null
enable_cdn = false
custom_request_headers = null
security_policy = null
log_config = {
enable = true
sample_rate = 1.0
}
groups = [
{
group = each.key
}
]
# Currently Cloud IAP is not supported for Cloud Run endpoints. We still
# need to specify that we don't want to use it though :).
iap_config = {
enable = false
oauth2_client_id = null
oauth2_client_secret = null
}
}
}
}
......@@ -5,7 +5,39 @@ locals {
sql_instance_project = coalesce(var.sql_instance_project, var.project)
# Should a DNS domain mapping be created?
domain_mapping_present = var.dns_name != ""
domain_mapping_present = anytrue([for dm in google_cloud_run_domain_mapping.webapp : true])
# DNS names for web app
dns_names = var.dns_name != "" ? [var.dns_name] : var.dns_names
# DNS records for webapp. Merge records from any domain mappings or load balancers.
dns_records = flatten(concat(
[
for domain_mapping in google_cloud_run_domain_mapping.webapp : [
{
type = domain_mapping.status[0].resource_records[0].type
rrdata = domain_mapping.status[0].resource_records[0].rrdata
}
]
],
[
for load_balancer in module.webapp_http_load_balancer : [
{
type = "A"
rrdata = load_balancer.external_ip
},
{
type = "AAAA"
rrdata = load_balancer.external_ipv6_address
}
]
]
))
# Certain ingress styles imply that we disallow external access to the base Cloud Run service.
webapp_allowed_ingress = lookup({
load-balancer = "internal-and-cloud-load-balancing"
}, var.ingress_style, var.allowed_ingress)
# Do we need to enable the 'beta' launch stage - only required if certain beta
# functionality is being used, or if `enable_beta_launch_stage` is set downstream.
......@@ -13,14 +45,10 @@ locals {
var.enable_beta_launch_stage || length(var.secrets_volume) != 0 || length(var.secrets_envars) != 0
)
# Whether we should monitor the custom domain - only possible if there is a dns_name
# set and unauthenticated invocation is enabled
can_monitor_custom_dns = var.dns_name != "" && var.allow_unauthenticated_invocations
# Hosts to monitor. We use the automatic host from Cloud Run and any custom
# domain mapped host, if can_monitor_custom_dns is true
# domain mapped host.
monitor_hosts = var.disable_monitoring ? [] : concat(
[trimsuffix(trimprefix(google_cloud_run_service.webapp.status[0].url, "https://"), "/")],
local.can_monitor_custom_dns ? [var.dns_name] : []
var.allow_unauthenticated_invocations ? local.dns_names : [],
)
}
......@@ -51,7 +51,7 @@ resource "google_cloud_run_service" "webapp" {
# Specify the allowable ingress types.
{
"run.googleapis.com/ingress" : var.allowed_ingress,
"run.googleapis.com/ingress" : local.webapp_allowed_ingress,
},
var.service_annotations,
......@@ -216,11 +216,11 @@ resource "google_cloud_run_service_iam_member" "webapp_all_users_invoker" {
# the domain mapping if the domain is *not* verified because Google won't let
# us.
resource "google_cloud_run_domain_mapping" "webapp" {
count = local.domain_mapping_present ? 1 : 0
for_each = toset(var.ingress_style == "domain-mapping" ? local.dns_names : [])
location = var.cloud_run_region
name = var.dns_name
name = each.key
metadata {
# For managed Cloud Run, the namespace *must* be the project name.
......
......@@ -16,15 +16,22 @@ output "domain_mapping_present" {
}
output "domain_mapping_resource_record" {
value = try(local.dns_records[0], {})
description = <<EOI
Resource record for domain mapping. If a domain mapping is configured the
following keys will be set: type and rrdata. If no mapping is configured, the
map will be empty.
EOI
value = local.domain_mapping_present ? {
type = google_cloud_run_domain_mapping.webapp[0].status[0].resource_records[0].type
rrdata = google_cloud_run_domain_mapping.webapp[0].status[0].resource_records[0].rrdata
} : {}
Deprecated. Use dns_resource_records output instead.
Resource record for DNS hostnames. If a domain mapping or load balancing is configured
the following keys will be set: type and rrdata. If no mapping is configured, the
map will be empty.
EOI
}
output "dns_resource_records" {
value = local.dns_records
description = <<EOI
List of DNS records for web application. Each element is an object with "type" and "rrdata"
keys.
EOI
}
output "domain_mapping_dns_name" {
......
......@@ -73,17 +73,80 @@ EOI
default = true
}
variable "ingress_style" {
type = string
default = "domain-mapping"
description = "Whether to configure a load balancer or create a domain mapping"
validation {
condition = contains(["domain-mapping", "load-balancer"], var.ingress_style)
error_message = "Ingress style must be one of 'domain-mapping' or 'load-balancer'."
}
}
variable "dns_name" {
default = ""
description = <<EOI
If non-empty, a domain mapping will be created for the webapp from this domain
to point to the webapp. The domain must first have been verified by Google and
the account being used by the google provider must have been added as an owner.
Deprecated: use the dns_names variable instead.
If and only if a domain mapping has been created, the
"domain_mapping_resource_record" output will be a non-empty map and the
"domain_mapping_present" output will be true.
EOI
default = ""
If non-empty, var.dns_names will be ignored.
If non-empty, a domain mapping will be created for the webapp from this host
to point to the webapp or a load balancer will be created for this host depending
on the value of the ingress_style variable.
The domain must first have been verified by Google and the account being used by
the google provider must have been added as an owner.
If and only if a domain mapping has been created, the
"domain_mapping_present" output will be true.
If a domain mapping or load balancer has been created, the "dns_resource_records"
output contains the appropriate DNS records.
EOI
}
variable "dns_names" {
type = list(any)
default = []
description = <<EOI
List of DNS names for web application. Note that no records are created,
the records to be created can be found in the dns_resource_records output.
Ignored if var.dns_name is non-empty.
EOI
}
variable "use_ssl_certificates" {
type = bool
default = false
description = <<EOI
Whether to use the custom TLS certs in var.ssl_certificates for the load balancer
or the Google-managed certs for the specified var.dns_names.
EOI
}
variable "ssl_certificates" {
type = list(any)
default = []
description = <<EOI
A list of self-links to any custom TLS certificates to add to the load balancer.
Requires that var.ingress_style be "load-balancer". The self-link is available as
the "self_link" attribute of "google_compute_ssl_certificate" resources.
EOI
}
variable "enable_ipv6" {
type = bool
default = false
description = "Whether to enable IPv6 address on the CDN load-balancer."
}
variable "create_ipv6_address" {
type = bool
default = false
description = "Allocate an IPv6 address to the load balancer if var.enable_ipv6 is true."
}
variable "service_account_id" {
......@@ -153,6 +216,9 @@ variable "allowed_ingress" {
Specify the allowed ingress to the service. Should be one of:
"all", "internal" or "internal-and-cloud-load-balancing".
If var.ingress_style == "load-balancer", the provided var.allowed_ingress will be ignored
and the allowed ingress will be set automatically to "internal-and-cloud-load-balancing".
Setting this to a value other than "all" implies that the service will be
moved to the "beta" launch stage. See
https://cloud.google.com/run/docs/troubleshooting#launch-stage-validation.
......@@ -177,7 +243,6 @@ variable "template_annotations" {
EOL
}
variable "enable_beta_launch_stage" {
default = false
description = "Force use of the 'BETA' launch stage for the service."
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment