☁️Static Pages Hosting by Cloud Storage and Load Balancer

the example of gcs static site

Overview 

This page explains how to build a static page site with Google Cloud Storage.

The system includes resources in the following and the structure diagram is below.

Overview

Prerequisite 

NOTE

This system takes a cost for the network transfer

How to build the Static Pages Site 

  1. Enable API
  2. Set up network
  3. Create a Bucket of Google Cloud Storage
  4. Set up a Load balancer to publish pages

1. Enable API 

To use the Cloud DNS service and manage the resource by the Tofu or Terraform or something, a developer need to enable the Cloud DNS service.

 1// Variable for GCP
 2variable "gcp_project" {
 3  type = object({
 4    project     = string   // The gcp project name
 5    region      = string   // The region of gcp project
 6  })
 7}
 8
 9variable "gcp_services" {
10  type = list(string)      // Enabling the service name of api
11}
12
13// Enable APIs
14resource "google_project_service" "api_enable" {
15  for_each = toset(var.gcp_services)
16  project  = var.gcp_project.project
17  service  = each.value
18}

2. Networking 

To expose the static content, set up a VPC network and DNS.

 1// VPC Network
 2resource "google_compute_network" "content" {
 3  name                    = "content"
 4  auto_create_subnetworks = false
 5}
 6
 7
 8// DNS zone
 9resource "google_dns_managed_zone" "content" {
10  project     = var.gcp_project.project
11  name        = "content-media"
12  dns_name    = local.content_domain
13  description = "Media Service"
14  labels = {
15    domain = "media"
16  }
17}
18
19// DNS A Records

3. Cloud Storage 

This part shows how to create Google Cloud Storage to store the static website content files, access control configuration, and network components.

 1# Create Cloud Storage Bucket suffix name
 2resource "random_id" "bucket_prefix" {
 3  for_each    = var.buckets
 4  byte_length = 16
 5}
 6
 7# Create Cloud Storage Bucket
 8resource "google_storage_bucket" "web_content" {
 9  depends_on                  = [random_id.bucket_prefix]
10  for_each                    = var.buckets
11  location                    = var.gcp_project.region
12  name                        = "${random_id.bucket_prefix[each.key].hex}-${each.value.name}"
13  uniform_bucket_level_access = true
14  storage_class               = "STANDARD"
15  // delete bucket and contents on destroy.
16  force_destroy = true
17}
18
19# Create Backend Service
20resource "google_compute_backend_bucket" "backend" {
21  depends_on  = [google_storage_bucket.web_content]
22  for_each    = var.buckets
23  name        = format("bsrv-%s", each.value.name)
24  description = "${each.value.name} Static Content Service"
25  bucket_name = google_storage_bucket.web_content[each.key].name
26}

4. Load balancer 

This part explains how to set up the network component to allow traffic between the internet and the prepared the content and backend service at previous section.

 1resource "google_compute_global_address" "ip" {
 2  for_each = { for k, v in var.buckets : k => v if contains(keys(v), "default_service") }
 3  name     = format("%s_%s_addr", local.resource_base_name, each.key)
 4}
 5
 6resource "google_compute_managed_ssl_certificate" "ssl" {
 7  for_each = { for k, v in var.buckets : k => v if contains(keys(v), "default_service") }
 8  name     = format("%s_%s_ssl", local.resource_base_name, each.key)
 9  managed {
10    domains = [local.content_domain]
11  }
12}
13
14resource "google_compute_url_map" "umap" {
15  depends_on      = [google_compute_backend_bucket.backend, google_compute_network.content]
16  for_each        = { for k, v in var.buckets : k => v if contains(keys(v), "default_service") }
17  name            = format("umap-lb-%s", local.resource_base_name)
18  default_service = google_compute_backend_bucket.backend[each.key].id
19
20  host_rule {
21    hosts        = [each.value.default_service.domain]
22    path_matcher = each.value.default_service.path_matcher_name
23  }
24
25  path_matcher {
26    name            = each.value.default_service.path_matcher_name
27    default_service = google_compute_backend_bucket.backend[each.key].id
28
29    dynamic "path_rule" {
30      for_each = { for k, v in var.buckets : k => v if contains(keys(v), "path_matcher") }
31      content {
32        paths   = [path_rule.value.path]
33        service = google_compute_backend_bucket.backend[path_rule.key]
34      }
35    }
36  }
37}
38
39resource "google_compute_target_https_proxy" "proxy" {
40  depends_on       = [google_compute_managed_ssl_certificate.ssl]
41  for_each         = { for k, v in var.buckets : k => v if contains(keys(v), "default_service") }
42  name             = format("%s-%s-https-proxy", local.resource_base_name, each.key)
43  url_map          = google_compute_url_map.umap[each.key].id
44  ssl_certificates = [google_compute_managed_ssl_certificate.ssl[each.key].id]
45}
46
47resource "google_compute_global_forwarding_rule" "default" {
48  depends_on            = [google_compute_url_map.umap, google_compute_target_https_proxy.proxy]
49  for_each              = { for k, v in var.buckets : k => v if contains(keys(v), "default_service") }
50  name                  = format("%s-%s-https-lb-forwarding", local.resource_base_name, each.key)
51  ip_protocol           = "TCP"
52  load_balancing_scheme = "EXTERNAL_MANAGED"
53  port_range            = "443"
54  target                = google_compute_target_https_proxy.proxy[each.key].id
55  ip_address            = google_compute_global_address.ip[each.key].id
56}

SEE ALSO 

GCP   StaticPages  

Memo / Google Cloud Platform / Static Pages Hosting by Cloud Storage and Load Balancer