433 lines
19 KiB
Markdown
433 lines
19 KiB
Markdown
# Internal (HTTP/S) Load Balancer Module
|
|
|
|
The module allows managing Internal HTTP/HTTPS Load Balancers (HTTP(S) ILBs), integrating the forwarding rule, the url-map, the backends, optional health checks and SSL certificates.
|
|
It's designed to be a simple match for the [`vpc`](../net-vpc) and the [`compute-mig`](../compute-mig) modules, which can be used to manage VPCs and instance groups.
|
|
|
|
## Examples
|
|
|
|
### Minimal Example
|
|
|
|
An HTTP ILB with a backend service pointing to a GCE instance group:
|
|
|
|
```hcl
|
|
module "ilb" {
|
|
source = "./modules/net-ilb-l7"
|
|
name = "ilb-test"
|
|
project_id = var.project_id
|
|
region = "europe-west1"
|
|
network = var.vpc.self_link
|
|
subnetwork = var.subnet.self_link
|
|
|
|
backend_services_config = {
|
|
my-backend-svc = {
|
|
backends = [
|
|
{
|
|
group = "projects/my-project/zones/europe-west1-a/instanceGroups/my-ig"
|
|
options = null
|
|
}
|
|
]
|
|
health_checks = []
|
|
log_config = null
|
|
options = null
|
|
}
|
|
}
|
|
}
|
|
# tftest modules=1 resources=5
|
|
```
|
|
|
|
Network and subnetwork can be entered using their name (if present in the same project) or leveraging their link id. The latter is mandatory if you're trying to deploy an ILB in a shared VPC environment.
|
|
|
|
```hcl
|
|
module "ilb" {
|
|
source = "./modules/net-ilb-l7"
|
|
name = "ilb-test"
|
|
project_id = var.project_id
|
|
region = "europe-west1"
|
|
network = "projects/my-host-project/global/networks/my-shared-vpc"
|
|
subnetwork = "projects/my-host-project/regions/europe-west1/subnetworks/my-shared-subnet"
|
|
|
|
backend_services_config = {
|
|
my-backend-svc = {
|
|
backends = [
|
|
{
|
|
group = "projects/my-project/zones/europe-west1-a/instanceGroups/my-ig"
|
|
options = null
|
|
}
|
|
]
|
|
health_checks = []
|
|
log_config = null
|
|
options = null
|
|
}
|
|
}
|
|
}
|
|
# tftest modules=1 resources=5
|
|
```
|
|
|
|
### Defining Health Checks
|
|
|
|
If no health checks are specified, a default health check is created and associated to each backend service without health checks already associated. The default health check configuration can be modified through the `health_checks_config_defaults` variable.
|
|
|
|
If the `health_checks_config_defaults` variable is set to null, no default health checks will be automatically associted to backend services.
|
|
|
|
Alternatively, one or more health checks can be either contextually created or attached, if existing. If the id of the health checks specified is equal to one of the keys of the `health_checks_config` variable, the health check is contextually created; otherwise, the health check id is used as is, assuming an health check with that id alredy exists.
|
|
|
|
For example, to contextually create a health check and attach it to the backend service:
|
|
|
|
```hcl
|
|
module "ilb" {
|
|
source = "./modules/net-ilb-l7"
|
|
name = "ilb-test"
|
|
project_id = var.project_id
|
|
region = "europe-west1"
|
|
network = var.vpc.self_link
|
|
subnetwork = var.subnet.self_link
|
|
|
|
backend_services_config = {
|
|
my-backend-svc = {
|
|
backends = [
|
|
{
|
|
group = "projects/my-project/zones/europe-west1-a/instanceGroups/my-ig"
|
|
options = null
|
|
}
|
|
],
|
|
health_checks = ["hc-1"]
|
|
log_config = null
|
|
options = null
|
|
}
|
|
}
|
|
|
|
health_checks_config = {
|
|
hc-1 = {
|
|
type = "http"
|
|
logging = true
|
|
options = {
|
|
timeout_sec = 5
|
|
}
|
|
check = {
|
|
port_specification = "USE_SERVING_PORT"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
# tftest modules=1 resources=5
|
|
```
|
|
|
|
### Network Endpoint Groups (NEGs)
|
|
|
|
Zonal Network Endpoint Groups (NEGs) can also be used, as shown in the example below.
|
|
|
|
```hcl
|
|
module "ilb" {
|
|
source = "./modules/net-ilb-l7"
|
|
name = "ilb-test"
|
|
project_id = var.project_id
|
|
region = "europe-west1"
|
|
network = var.vpc.self_link
|
|
subnetwork = var.subnet.self_link
|
|
|
|
backend_services_config = {
|
|
my-backend-svc = {
|
|
backends = [
|
|
{
|
|
group = google_compute_network_endpoint_group.my-neg.id
|
|
options = {
|
|
balancing_mode = "RATE"
|
|
capacity_scaler = 1.0
|
|
max_connections = null
|
|
max_connections_per_instance = null
|
|
max_connections_per_endpoint = null
|
|
max_rate = 100
|
|
max_rate_per_endpoint = null
|
|
max_rate_per_instance = null
|
|
max_utilization = null
|
|
}
|
|
}
|
|
],
|
|
health_checks = []
|
|
log_config = null
|
|
options = null
|
|
}
|
|
}
|
|
}
|
|
|
|
resource "google_compute_network_endpoint_group" "my-neg" {
|
|
name = "my-neg"
|
|
project = var.project_id
|
|
network = var.vpc.self_link
|
|
subnetwork = var.subnet.self_link
|
|
default_port = "90"
|
|
zone = "europe-west1-b"
|
|
}
|
|
# tftest modules=1 resources=5
|
|
```
|
|
-->
|
|
|
|
### Url-map
|
|
|
|
The url-map can be customized with lots of different configurations. This includes leveraging multiple backends in different parts of the configuration.
|
|
Given its complexity, it's left to the user passing the right data structure.
|
|
|
|
For simplicity, *if no configurations are given* the first backend service defined (in alphabetical order, with priority to bucket backend services, if any) is used as the *default_service*, thus answering to the root (*/*) path.
|
|
|
|
Backend services can be specified as needed in the url-map configuration, referencing the id used to declare them in the backend services map. If a corresponding backend service is found, their object id is automatically used; otherwise, it is assumed that the string passed is the id of an already existing backend and it is given to the provider as it was passed.
|
|
|
|
In this example, we're using a backend service as the default backend
|
|
|
|
```hcl
|
|
module "ilb" {
|
|
source = "./modules/net-ilb-l7"
|
|
name = "ilb-test"
|
|
project_id = var.project_id
|
|
region = "europe-west1"
|
|
network = var.vpc.self_link
|
|
subnetwork = var.subnet.self_link
|
|
|
|
url_map_config = {
|
|
default_service = "my-backend-svc"
|
|
default_url_redirect = null
|
|
tests = null
|
|
host_rules = []
|
|
path_matchers = [
|
|
{
|
|
name = "my-example-page"
|
|
path_rules = [
|
|
{
|
|
paths = ["/my-example-page"]
|
|
service = "another-group-backend"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
|
|
backend_services_config = {
|
|
my-backend-svc = {
|
|
backends = [
|
|
{
|
|
group = "projects/my-project/zones/europe-west1-a/instanceGroups/my-ig"
|
|
options = null
|
|
}
|
|
],
|
|
health_checks = []
|
|
log_config = null
|
|
options = null
|
|
},
|
|
my-example-page = {
|
|
backends = [
|
|
{
|
|
group = "projects/my-project/zones/europe-west1-a/instanceGroups/another-ig"
|
|
options = null
|
|
}
|
|
],
|
|
health_checks = []
|
|
log_config = null
|
|
options = null
|
|
}
|
|
}
|
|
}
|
|
# tftest modules=1 resources=6
|
|
```
|
|
|
|
### Reserve a static IP address
|
|
|
|
Optionally, a static IP address can be reserved:
|
|
|
|
```hcl
|
|
module "ilb" {
|
|
source = "./modules/net-ilb-l7"
|
|
name = "ilb-test"
|
|
project_id = var.project_id
|
|
region = "europe-west1"
|
|
network = var.vpc.self_link
|
|
subnetwork = var.subnet.self_link
|
|
|
|
static_ip_config = {
|
|
reserve = true
|
|
options = null
|
|
}
|
|
|
|
backend_services_config = {
|
|
my-backend-svc = {
|
|
backends = [
|
|
{
|
|
group = "projects/my-project/zones/europe-west1-a/instanceGroups/my-ig"
|
|
options = null
|
|
}
|
|
],
|
|
health_checks = []
|
|
log_config = null
|
|
options = null
|
|
}
|
|
}
|
|
}
|
|
# tftest modules=1 resources=6
|
|
```
|
|
|
|
### HTTPS And SSL Certificates
|
|
|
|
HTTPS is disabled by default but it can be optionally enabled.
|
|
|
|
When HTTPS is enabled, if the ids specified in the `target_proxy_https_config` variable are not found in the `ssl_certificates_config` map, they are used as is, assuming the ssl certificates already exist:
|
|
|
|
```hcl
|
|
module "ilb" {
|
|
source = "./modules/net-ilb-l7"
|
|
name = "ilb-test"
|
|
project_id = var.project_id
|
|
region = "europe-west1"
|
|
network = var.vpc.self_link
|
|
subnetwork = var.subnet.self_link
|
|
|
|
https = true
|
|
|
|
target_proxy_https_config = {
|
|
ssl_certificates = [
|
|
"an-existing-cert"
|
|
]
|
|
}
|
|
|
|
backend_services_config = {
|
|
my-backend-svc = {
|
|
backends = [
|
|
{
|
|
group = "projects/my-project/zones/europe-west1-a/instanceGroups/my-ig"
|
|
options = null
|
|
}
|
|
]
|
|
health_checks = []
|
|
log_config = null
|
|
options = null
|
|
}
|
|
}
|
|
}
|
|
# tftest modules=1 resources=5
|
|
```
|
|
|
|
Otherwise, unmanaged certificates can also be contextually created:
|
|
|
|
```hcl
|
|
module "ilb" {
|
|
source = "./modules/net-ilb-l7"
|
|
name = "ilb-test"
|
|
project_id = var.project_id
|
|
region = "europe-west1"
|
|
network = var.vpc.self_link
|
|
subnetwork = var.subnet.self_link
|
|
|
|
https = true
|
|
|
|
ssl_certificates_config = {
|
|
my-domain = {
|
|
domains = [
|
|
"my-domain.com"
|
|
],
|
|
tls_private_key = tls_private_key.self_signed_key.private_key_pem
|
|
tls_self_signed_cert = tls_self_signed_cert.self_signed_cert.cert_pem
|
|
}
|
|
}
|
|
|
|
target_proxy_https_config = {
|
|
ssl_certificates = [
|
|
"my-domain"
|
|
]
|
|
}
|
|
|
|
backend_services_config = {
|
|
my-backend-svc = {
|
|
backends = [
|
|
{
|
|
group = "projects/my-project/zones/europe-west1-a/instanceGroups/my-ig"
|
|
options = null
|
|
}
|
|
],
|
|
health_checks = []
|
|
log_config = null
|
|
options = null
|
|
}
|
|
}
|
|
}
|
|
|
|
resource "tls_private_key" "self_signed_key" {
|
|
algorithm = "RSA"
|
|
rsa_bits = 2048
|
|
}
|
|
|
|
resource "tls_self_signed_cert" "self_signed_cert" {
|
|
key_algorithm = tls_private_key.self_signed_key.algorithm
|
|
private_key_pem = tls_private_key.self_signed_key.private_key_pem
|
|
validity_period_hours = 12
|
|
early_renewal_hours = 3
|
|
dns_names = ["example.com"]
|
|
allowed_uses = [
|
|
"key_encipherment",
|
|
"digital_signature",
|
|
"server_auth"
|
|
]
|
|
subject {
|
|
common_name = "example.com"
|
|
organization = "My Test Org"
|
|
}
|
|
}
|
|
# tftest modules=1 resources=6
|
|
```
|
|
|
|
## Components And Files Mapping
|
|
|
|
An Internal HTTP Load Balancer is made of multiple components, that change depending on the configurations. Sometimes, it may be tricky to understand what they are, and how they relate to each other. Following, we provide a very brief overview to become more familiar with them.
|
|
|
|
- The global load balancer [forwarding rule](forwarding-rule.tf) binds a frontend public Virtual IP (VIP) to an HTTP(S) [target proxy](target-proxy.tf).
|
|
- If the target proxy is HTTPS, it requires one or more unmanaged [SSL certificates](ssl-certificates.tf).
|
|
- Target proxies leverage [url-maps](url-map.tf): a set of L7 rules that create a mapping between specific hostnames, URIs (and more) to one or more [backends services](backend-services.tf).
|
|
- [Backend services](backend-services.tf) link to one or multiple infrastructure groups (GCE instance groups or NEGs). It is assumed in this module that groups have been previously created through other modules, and referenced in the input variables.
|
|
- Backend services support one or more [health checks](health-checks.tf), used to verify that the backend is indeed healthy, so that traffic can be forwarded to it. Health checks currently supported in this module are HTTP, HTTPS, HTTP2, SSL, TCP.
|
|
|
|
<!-- TFDOC OPTS files:1 -->
|
|
<!-- BEGIN TFDOC -->
|
|
|
|
## Files
|
|
|
|
| name | description | resources |
|
|
|---|---|---|
|
|
| [backend-services.tf](./backend-services.tf) | Bucket and group backend services. | <code>google_compute_region_backend_service</code> |
|
|
| [forwarding-rule.tf](./forwarding-rule.tf) | IP Address and forwarding rule. | <code>google_compute_address</code> · <code>google_compute_forwarding_rule</code> |
|
|
| [health-checks.tf](./health-checks.tf) | Health checks. | <code>google_compute_region_health_check</code> |
|
|
| [outputs.tf](./outputs.tf) | Module outputs. | |
|
|
| [ssl-certificates.tf](./ssl-certificates.tf) | SSL certificates. | <code>google_compute_region_ssl_certificate</code> |
|
|
| [target-proxy.tf](./target-proxy.tf) | HTTP and HTTPS target proxies. | <code>google_compute_region_target_http_proxy</code> · <code>google_compute_region_target_https_proxy</code> |
|
|
| [url-map.tf](./url-map.tf) | URL maps. | <code>google_compute_region_url_map</code> |
|
|
| [variables.tf](./variables.tf) | Module variables. | |
|
|
| [versions.tf](./versions.tf) | Version pins. | |
|
|
|
|
## Variables
|
|
|
|
| name | description | type | required | default |
|
|
|---|---|:---:|:---:|:---:|
|
|
| [name](variables.tf#L17) | Load balancer name. | <code>string</code> | ✓ | |
|
|
| [project_id](variables.tf#L22) | Project id. | <code>string</code> | ✓ | |
|
|
| [region](variables.tf#L157) | The region where to allocate the ILB resources. | <code>string</code> | ✓ | |
|
|
| [subnetwork](variables.tf#L187) | The subnetwork where the ILB VIP is allocated. | <code>string</code> | ✓ | |
|
|
| [backend_services_config](variables.tf#L27) | The backends services configuration. | <code title="map(object({ backends = list(object({ group = string # The instance group link id options = object({ balancing_mode = string # Can be UTILIZATION, RATE capacity_scaler = number # Valid range is [0.0,1.0] max_connections = number max_connections_per_instance = number max_connections_per_endpoint = number max_rate = number max_rate_per_instance = number max_rate_per_endpoint = number max_utilization = number }) })) health_checks = list(string) log_config = object({ enable = bool sample_rate = number # must be in [0, 1] }) options = object({ affinity_cookie_ttl_sec = number custom_request_headers = list(string) custom_response_headers = list(string) connection_draining_timeout_sec = number locality_lb_policy = string port_name = string protocol = string session_affinity = string timeout_sec = number circuits_breakers = object({ max_requests_per_connection = number # Set to 1 to disable keep-alive max_connections = number # Defaults to 1024 max_pending_requests = number # Defaults to 1024 max_requests = number # Defaults to 1024 max_retries = number # Defaults to 3 }) consistent_hash = object({ http_header_name = string minimum_ring_size = string http_cookie = object({ name = string path = string ttl = object({ seconds = number nanos = number }) }) }) iap = object({ oauth2_client_id = string oauth2_client_secret = string oauth2_client_secret_sha256 = string }) }) }))">map(object({…}))</code> | | <code>{}</code> |
|
|
| [forwarding_rule_config](variables.tf#L98) | Forwarding rule configurations. | <code title="object({ ip_version = string labels = map(string) network_tier = string port_range = string })">object({…})</code> | | <code title="{ allow_global_access = true ip_version = "IPV4" labels = {} network_tier = "PREMIUM" port_range = null }">{…}</code> |
|
|
| [health_checks_config](variables.tf#L116) | Custom health checks configuration. | <code title="map(object({ type = string # http https tcp ssl http2 check = map(any) # actual health check block attributes options = map(number) # interval, thresholds, timeout logging = bool }))">map(object({…}))</code> | | <code>{}</code> |
|
|
| [health_checks_config_defaults](variables.tf#L127) | Auto-created health check default configuration. | <code title="object({ check = map(any) # actual health check block attributes logging = bool options = map(number) # interval, thresholds, timeout type = string # http https tcp ssl http2 })">object({…})</code> | | <code title="{ type = "http" logging = false options = {} check = { port_specification = "USE_SERVING_PORT" } }">{…}</code> |
|
|
| [https](variables.tf#L145) | Whether to enable HTTPS. | <code>bool</code> | | <code>false</code> |
|
|
| [network](variables.tf#L151) | The network where the ILB is created. | <code>string</code> | | <code>"default"</code> |
|
|
| [ssl_certificates_config](variables.tf#L162) | The SSL certificates configuration. | <code title="map(object({ domains = list(string) tls_private_key = string tls_self_signed_cert = string }))">map(object({…}))</code> | | <code>{}</code> |
|
|
| [static_ip_config](variables.tf#L172) | Static IP address configuration. | <code title="object({ reserve = bool options = object({ address = string subnetwork = string # The subnet id }) })">object({…})</code> | | <code title="{ reserve = false options = null }">{…}</code> |
|
|
| [target_proxy_https_config](variables.tf#L192) | The HTTPS target proxy configuration. | <code title="object({ ssl_certificates = list(string) })">object({…})</code> | | <code>null</code> |
|
|
| [url_map_config](variables.tf#L200) | The url-map configuration. | <code title="object({ default_service = string default_url_redirect = map(any) host_rules = list(any) path_matchers = list(any) tests = list(map(string)) })">object({…})</code> | | <code>null</code> |
|
|
|
|
## Outputs
|
|
|
|
| name | description | sensitive |
|
|
|---|---|:---:|
|
|
| [backend_services](outputs.tf#L22) | Backend service resources. | |
|
|
| [forwarding_rule](outputs.tf#L55) | The forwarding rule. | |
|
|
| [health_checks](outputs.tf#L17) | Health-check resources. | |
|
|
| [ip_address](outputs.tf#L41) | The reserved IP address. | |
|
|
| [ssl_certificate_link_ids](outputs.tf#L34) | The SSL certificate. | |
|
|
| [target_proxy](outputs.tf#L46) | The target proxy. | |
|
|
| [url_map](outputs.tf#L29) | The url-map. | |
|
|
|
|
<!-- END TFDOC -->
|