Files
Compass/backend/api/main.tf

333 lines
8.0 KiB
HCL

variable "image_url" {
description = "Docker image URL"
type = string
default = "us-west1-docker.pkg.dev/compass-130ba/builds/api:latest"
}
variable "env" {
description = "Environment (env or prod)"
type = string
default = "prod"
}
locals {
project = "compass-130ba"
region = "us-west1"
zone = "us-west1-b"
service_name = "api"
machine_type = "e2-small"
}
terraform {
backend "gcs" {
bucket = "compass-130ba-terraform-state"
prefix = "api"
}
}
provider "google" {
project = local.project
region = local.region
zone = local.zone
}
# Firebase Storage Buckets
# Note you still have to deploy the rules: `firebase deploy --only storage`
resource "google_storage_bucket" "public_storage" {
# /!\ That bucket is different from the one in firebase (compass-130ba.firebasestorage.app)
# as it errors when trying to do so:
# Error: googleapi: Error 403: Another user owns the domain compass-130ba.firebasestorage.app or a parent domain. You can either verify domain ownership at https://search.google.com/search-console/welcome?new_domain_name=compass-130ba.firebasestorage.app or find the current owner and ask that person to create the bucket for you, forbidden
# To be fixed later if they must be the same bucket (shared resources)
name = "compass-130ba"
location = "US"
force_destroy = false
uniform_bucket_level_access = true
cors {
origin = ["*"]
method = ["GET", "HEAD", "PUT", "POST", "DELETE"]
response_header = ["*"]
max_age_seconds = 3600
}
}
# static IPs
resource "google_compute_global_address" "api_lb_ip" {
name = "api-lb-ip-2"
address_type = "EXTERNAL"
}
resource "google_compute_managed_ssl_certificate" "api_cert" {
name = "api-lb-cert-1"
managed {
domains = ["api.compassmeet.com"]
}
}
# Instance template with your Docker container
resource "google_compute_instance_template" "api_template" {
name_prefix = "${local.service_name}-"
machine_type = local.machine_type
tags = ["lb-health-check"]
disk {
source_image = "cos-cloud/cos-stable" # Container-Optimized OS
auto_delete = true
boot = true
}
network_interface {
network = "default"
subnetwork = "default"
access_config {
network_tier = "PREMIUM"
}
}
service_account {
scopes = ["cloud-platform"]
}
metadata = {
gce-container-declaration = <<EOF
spec:
containers:
- image: '${var.image_url}'
env:
- name: NEXT_PUBLIC_FIREBASE_ENV
value: ${upper(var.env)}
- name: GOOGLE_CLOUD_PROJECT
value: ${local.project}
ports:
- containerPort: 80
EOF
}
lifecycle {
create_before_destroy = true
}
}
# Managed instance group (for 1 VM)
resource "google_compute_region_instance_group_manager" "api_group" {
name = "${local.service_name}-group"
base_instance_name = "${local.service_name}-group"
region = local.region
target_size = 1
version {
instance_template = google_compute_instance_template.api_template.id
name = "primary"
}
update_policy {
type = "PROACTIVE"
minimal_action = "REPLACE"
max_unavailable_fixed = 0
max_surge_fixed = 3
}
named_port {
name = "http"
port = 80
}
auto_healing_policies {
health_check = google_compute_health_check.api_health_check.id
initial_delay_sec = 300
}
}
resource "google_compute_health_check" "api_health_check" {
name = "${local.service_name}-health-check"
check_interval_sec = 5
timeout_sec = 5
healthy_threshold = 2
unhealthy_threshold = 10
tcp_health_check {
port = "80"
}
}
# Backend service
resource "google_compute_backend_service" "api_backend" {
name = "${local.service_name}-backend"
protocol = "HTTP"
port_name = "http"
timeout_sec = 30
health_checks = [google_compute_health_check.api_health_check.id]
backend {
group = google_compute_region_instance_group_manager.api_group.instance_group
}
log_config {
enable = true
}
}
# URL map
resource "google_compute_url_map" "api_url_map" {
name = "${local.service_name}-url-map"
default_service = google_compute_backend_service.api_backend.self_link
host_rule {
hosts = ["*"]
path_matcher = "allpaths"
}
path_matcher {
name = "allpaths"
default_service = google_compute_backend_service.api_backend.self_link
#
# # Priority 0: passthrough /v0/* requests
# route_rules {
# priority = 1
# match_rules {
# prefix_match = "/v0"
# }
# service = google_compute_backend_service.api_backend.self_link
# }
#
# # Priority 1: rewrite everything else to /v0
# route_rules {
# priority = 2
# match_rules {
# prefix_match = "/"
# }
# route_action {
# url_rewrite { # This may break websockets (the Upgrade and Connection headers must pass through untouched).
# path_prefix_rewrite = "/v0/"
# }
# }
# service = google_compute_backend_service.api_backend.self_link
# }
}
}
# HTTPS proxy
resource "google_compute_target_https_proxy" "api_https_proxy" {
name = "${local.service_name}-https-proxy"
url_map = google_compute_url_map.api_url_map.id
ssl_certificates = [google_compute_managed_ssl_certificate.api_cert.id]
}
# Global forwarding rule (load balancer frontend)
resource "google_compute_global_forwarding_rule" "api_https_forwarding_rule" {
name = "${local.service_name}-https-forwarding-rule-2"
target = google_compute_target_https_proxy.api_https_proxy.id
port_range = "443"
ip_address = google_compute_global_address.api_lb_ip.id
}
# HTTP-to-HTTPS redirect
resource "google_compute_url_map" "api_http_redirect" {
name = "${local.service_name}-http-redirect"
default_url_redirect {
https_redirect = true
redirect_response_code = "MOVED_PERMANENTLY_DEFAULT"
strip_query = false
}
}
resource "google_compute_target_http_proxy" "api_http_proxy" {
name = "${local.service_name}-http-proxy"
url_map = google_compute_url_map.api_http_redirect.id
}
resource "google_compute_global_forwarding_rule" "api_http_forwarding_rule" {
name = "${local.service_name}-http-forwarding-rule"
target = google_compute_target_http_proxy.api_http_proxy.id
port_range = "80"
ip_address = google_compute_global_address.api_lb_ip.id
}
# Firewalls
resource "google_compute_firewall" "allow_health_check" {
name = "allow-health-check-${local.service_name}"
network = "default"
allow {
protocol = "tcp"
ports = ["80"]
}
source_ranges = ["130.211.0.0/22", "35.191.0.0/16"]
target_tags = ["lb-health-check"]
}
resource "google_compute_firewall" "default_allow_https" {
name = "default-allow-http"
network = "default"
priority = 1000
direction = "INGRESS"
allow {
protocol = "tcp"
ports = ["80", "443"] # ["443", "8090-8099"]
}
source_ranges = ["0.0.0.0/0"]
}
# resource "google_compute_firewall" "default_allow_ssh" {
# name = "default-allow-ssh"
# network = "default"
# priority = 65534
# direction = "INGRESS"
#
# allow {
# protocol = "tcp"
# ports = ["22"]
# }
#
# source_ranges = ["0.0.0.0/0"]
# }
#
# resource "google_compute_firewall" "default_allow_internal" {
# name = "default-allow-internal"
# network = "default"
# priority = 65534
# direction = "INGRESS"
#
# allow {
# protocol = "tcp"
# ports = ["0-65535"]
# }
#
# allow {
# protocol = "udp"
# ports = ["0-65535"]
# }
#
# allow {
# protocol = "icmp"
# }
#
# source_ranges = ["10.128.0.0/9"]
# }
#
# # Allow ICMP (ping)
# resource "google_compute_firewall" "default_allow_icmp" {
# name = "default-allow-icmp"
# network = "default"
# priority = 65534
# direction = "INGRESS"
#
# allow {
# protocol = "icmp"
# }
#
# source_ranges = ["0.0.0.0/0"]
# }