diff --git a/examples/cross-regional-failover-with-gxlb/README.md b/examples/cross-regional-failover-with-gxlb/README.md new file mode 100644 index 00000000..02c0f9a0 --- /dev/null +++ b/examples/cross-regional-failover-with-gxlb/README.md @@ -0,0 +1,36 @@ +# Cross-Regional Failover with GXLB Example + +This example demonstrates how to use the **terraform-google-lb-http** module (or a variant that supports GXLB) to set up a **Global HTTP Load Balancer** with **cross-regional failover** capabilities (GXLB). The idea is que tráfego enviado ao *Global Load Balancer* será roteado para backends regionais saudáveis, com failover automático entre regiões. + +Este projeto assume que sua versão do módulo *terraform-google-lb-http* (ou fork com suporte GXLB) já suporta a lógica de failover global entre regiões. + +--- + +## How it Works + +- **Backend module(s)**: serão criados recursos de backend (ex: *google_compute_backend_service*, instâncias, MIGs, health checks) em múltiplas regiões conforme definido nas variáveis. +- **Frontend / Global module**: cria os recursos do balanceador global — endereço IP global, regras de encaminhamento globais (*global forwarding rules*), proxy HTTP/HTTPS, URL map com lógica de failover entre regiões (prioridades ou condições de health). +- A lógica de failover global é configurada de modo que, se um backend em região A ficar indisponível, o tráfego será encaminhado para o backend em região B. + +--- + +## Inputs + + +| Name | Description | Type | Default | Required | +|---------------------|---------------------------------------------------------------|----------------|----------------------------------|:--------:| +| project_id | The GCP project ID | `string` | n/a | yes | +| project | Alias project ID (used in some resources) | `string` | n/a | yes | +| regions | Map of regions where regional ALBs / backends will be created | `map(string)` | see example default in variables | no | +| vm_subnet_cidrs | Map of VM subnet CIDRs per region | `map(string)` | default map | no | +| proxy_subnet_cidrs | Map of proxy-only subnet CIDRs per region | `map(string)` | default map | no | +| default_region | Default region used by the provider | `string` | `"us-central1"` | no | +| region_to_zone | Map region → zone for MIGs | `map(string)` | default map | no | +| instance_image | Image to use for backend instances | `string` | `"projects/debian-cloud/global/images/family/debian-11"` | no | +| instance_machine_type | Machine type for backend instances | `string` | `"e2-medium"` | no | +| target_size | Number of VMs per managed instance group | `number` | `2` | no | +| regional_hostname | DNS hostname used for certificates and DNS records | `string` | `"regional.example.com"` | no | +| enable_dns_records | Whether to create DNS records | `bool` | `true` | no | +| create_public_zone | Whether to create a new public managed DNS zone | `bool` | `true` | no | +| public_zone_name | Name of existing public zone (if `create_public_zone = false`) | `string` | `"public-example-zone"` | no | + diff --git a/examples/cross-regional-failover-with-gxlb/main.tf b/examples/cross-regional-failover-with-gxlb/main.tf new file mode 100644 index 00000000..236c26cd --- /dev/null +++ b/examples/cross-regional-failover-with-gxlb/main.tf @@ -0,0 +1,189 @@ +resource "google_compute_network" "global_lb_network" { + name = "global-lb-network" + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "vm_subnets" { + for_each = var.regions + name = "global-backend-${each.key}-vm-subnet" + region = each.key + network = google_compute_network.global_lb_network.self_link + ip_cidr_range = var.vm_subnet_cidrs[each.key] +} + +resource "google_compute_firewall" "allow_global_hc" { + name = "allow-global-lb-health-checks" + network = google_compute_network.global_lb_network.name + allow { + protocol = "tcp" + ports = ["80", "443"] + } + direction = "INGRESS" + source_ranges = ["130.211.0.0/22", "35.191.0.0/16"] + target_tags = ["allow-health-check"] +} + +resource "google_compute_instance_template" "global_backend_tmpl" { + for_each = var.regions + name_prefix = "global-backend-${each.key}-tmpl-" + machine_type = var.instance_machine_type + tags = ["allow-health-check"] + + disk { + source_image = var.instance_image + auto_delete = true + boot = true + } + + network_interface { + subnetwork = google_compute_subnetwork.vm_subnets[each.key].self_link + } + + metadata_startup_script = <<-EOT + #!/bin/bash + apt-get update -y + apt-get install -y nginx + echo "Hello from Global LB Backend in ${each.key}" > /var/www/html/index.html + systemctl enable nginx + systemctl restart nginx + EOT +} + +resource "google_compute_instance_group_manager" "global_backend_migs" { + for_each = var.regions + name = "global-backend-${each.key}-mig" + base_instance_name = "global-backend-${each.key}-vm" + zone = var.region_to_zone[each.key] + target_size = var.target_size + + version { + instance_template = google_compute_instance_template.global_backend_tmpl[each.key].self_link + } +} + +resource "google_compute_health_check" "global_lb_hc" { + name = "global-lb-health-check" + check_interval_sec = 10 + timeout_sec = 5 + healthy_threshold = 2 + unhealthy_threshold = 3 + + http_health_check { + port = 80 + request_path = "/" + } +} + +resource "google_compute_security_policy" "global_armor" { + name = "global-armor-policy" + rule { + action = "allow" + priority = 2147483647 + match { + versioned_expr = "SRC_IPS_V1" + config { + src_ip_ranges = ["*"] + } + } + description = "Default allow all rule" + } +} + +resource "google_compute_backend_service" "global_bs" { + name = "global-lb-backend-service" + protocol = "HTTP" + load_balancing_scheme = "EXTERNAL_MANAGED" + health_checks = [google_compute_health_check.global_lb_hc.self_link] + security_policy = google_compute_security_policy.global_armor.self_link + enable_cdn = true + + dynamic "backend" { + for_each = var.regions + content { + group = google_compute_instance_group_manager.global_backend_migs[backend.key].instance_group + } + } +} + +resource "google_compute_url_map" "global_um" { + name = "global-lb-url-map" + default_service = google_compute_backend_service.global_bs.id +} + +resource "google_compute_target_https_proxy" "global_https_proxy" { + name = "global-lb-https-proxy" + url_map = google_compute_url_map.global_um.id + certificate_map = "//certificatemanager.googleapis.com/${google_certificate_manager_certificate_map.global_cert_map.id}" +} + +resource "google_compute_global_address" "global_addr" { + name = "global-lb-ip" +} + +resource "google_compute_global_forwarding_rule" "global_fr" { + name = "global-lb-forwarding-rule" + ip_protocol = "TCP" + load_balancing_scheme = "EXTERNAL_MANAGED" + port_range = "443" + target = google_compute_target_https_proxy.global_https_proxy.id + ip_address = google_compute_global_address.global_addr.address +} + +locals { + dns_managed_zone_name = var.create_public_zone && var.enable_dns_records ? google_dns_managed_zone.public_new[0].name : var.public_zone_name +} + +resource "google_dns_managed_zone" "public_new" { + count = var.create_public_zone && var.enable_dns_records ? 1 : 0 + name = format("public-%s", replace(var.hostname, ".", "-")) + dns_name = "${var.hostname}." + description = "Public zone for ${var.hostname}" +} + +resource "google_certificate_manager_dns_authorization" "global_auth" { + provider = google-beta + name = "global-dns-auth" + domain = var.hostname +} + +resource "google_certificate_manager_certificate" "global_cert" { + provider = google-beta + name = "global-cm-cert" + managed { + domains = [var.hostname] + dns_authorizations = [google_certificate_manager_dns_authorization.global_auth.id] + } +} + +resource "google_certificate_manager_certificate_map" "global_cert_map" { + provider = google-beta + name = "global-lb-cert-map" +} + +resource "google_certificate_manager_certificate_map_entry" "global_cert_map_entry" { + provider = google-beta + name = "global-lb-cert-map-entry" + map = google_certificate_manager_certificate_map.global_cert_map.name + certificates = [google_certificate_manager_certificate.global_cert.id] + hostname = var.hostname +} + +resource "google_dns_record_set" "global_acme_txt" { + count = var.enable_dns_records && length(local.dns_managed_zone_name) > 0 ? 1 : 0 + + managed_zone = local.dns_managed_zone_name + name = google_certificate_manager_dns_authorization.global_auth.dns_resource_record[0].name + type = google_certificate_manager_dns_authorization.global_auth.dns_resource_record[0].type + ttl = 60 + rrdatas = [google_certificate_manager_dns_authorization.global_auth.dns_resource_record[0].data] +} + +resource "google_dns_record_set" "global_a" { + count = var.enable_dns_records && length(local.dns_managed_zone_name) > 0 ? 1 : 0 + + managed_zone = local.dns_managed_zone_name + name = "${var.hostname}." + type = "A" + ttl = 60 + rrdatas = [google_compute_global_address.global_addr.address] +} diff --git a/examples/cross-regional-failover-with-gxlb/outputs.tf b/examples/cross-regional-failover-with-gxlb/outputs.tf new file mode 100644 index 00000000..7e93af98 --- /dev/null +++ b/examples/cross-regional-failover-with-gxlb/outputs.tf @@ -0,0 +1,9 @@ +output "global_lb_ip" { + description = "The public IP address of the Global Load Balancer." + value = google_compute_global_address.global_addr.address +} + +output "hostname" { + description = "The domain name (hostname) configured for the Global Load Balancer." + value = var.hostname +} diff --git a/examples/cross-regional-failover-with-gxlb/variables.tf b/examples/cross-regional-failover-with-gxlb/variables.tf new file mode 100644 index 00000000..41a10335 --- /dev/null +++ b/examples/cross-regional-failover-with-gxlb/variables.tf @@ -0,0 +1,79 @@ +variable "project_id" { + description = "GCP project ID" + type = string +} + +variable "default_region" { + description = "Default region used for the provider" + type = string + default = "us-central1" +} + +variable "regions" { + description = "Regions to create backend groups (MIGs)" + type = map(string) + default = { + "us-central1" = "us-central1" + "us-east1" = "us-east1" + } +} + +variable "vm_subnet_cidrs" { + description = "VM subnet CIDRs per region" + type = map(string) + default = { + "us-central1" = "10.10.0.0/24" + "us-east1" = "10.20.0.0/24" + } +} + +variable "region_to_zone" { + description = "Region -> zone mapping for MIGs" + type = map(string) + default = { + "us-central1" = "us-central1-a" + "us-east1" = "us-east1-b" + } +} + +variable "instance_image" { + description = "Image for backend instances" + type = string + default = "projects/debian-cloud/global/images/family/debian-11" +} + +variable "instance_machine_type" { + description = "Machine type for backend instances" + type = string + default = "e2-medium" +} + +variable "target_size" { + description = "Number of VMs per MIG" + type = number + default = 2 +} + +variable "hostname" { + description = "The domain name (hostname) for the Global Load Balancer" + type = string + default = "global.example.com" +} + +variable "enable_dns_records" { + description = "Whether to create DNS zone and records" + type = bool + default = true +} + +variable "create_public_zone" { + description = "Whether to create a new public managed zone in Cloud DNS" + type = bool + default = true +} + +variable "public_zone_name" { + description = "Name of an existing public zone (used if create_public_zone=false)" + type = string + default = "public-example-zone" +}