搭配網域的靜態代管服務

架構

「透過網域託管靜態網站」是簡單的靜態網站建立工具,可使用 Storage Bucket 建立簡單的網站並提供服務:

  • 儲存空間 - 檔案儲存空間 - Cloud Storage
  • 網路 - 負載平衡 - Cloud Load Balancer
  • 網路 - DNS - Cloud DNS
  • 網域管理 - 註冊機構 - Cloud Domains

開始使用

按一下下列連結,即可在 Cloud Shell 中複製原始碼。完成後,只要執行單一指令,即可在專案中啟動應用程式的工作副本。

在 Cloud Shell 開啟

在 GitHub 上查看原始碼


使用網域元件的靜態託管

「使用網域的靜態託管」架構會用到多項產品。 下表列出各項元件,並提供元件的相關資訊,包括相關影片、產品說明文件和互動式導覽的連結。
影片 文件 逐步操作說明
Cloud Storage Cloud Storage 提供檔案儲存空間,並透過 http(s) 公開提供圖片。
Cloud DNS Cloud DNS 提供 DNS 管理功能,讓您使用 Google 現有的 DNS 基礎架構,執行自己的 DNS 基礎架構。
Cloud Load Balancing Google Cloud Load Balancer 可讓您在 Storage Bucket 前方放置負載平衡器,以便使用 SSL 憑證、記錄和監控功能。
Cloud Domains Cloud Domains 可讓您購買網域,就像網域註冊商一樣,但購買後,您可透過 Google Cloud 帳戶管理網域和處理帳單事宜。

指令碼

安裝指令碼會使用以 go 撰寫的可執行檔和 Terraform CLI 工具,在空白專案中安裝應用程式。輸出內容應為可運作的應用程式,以及負載平衡 IP 位址的網址。

./main.tf

啟用服務

專案預設會停用 Google Cloud 服務。如要使用這裡的任何解決方案,請先啟用下列項目:

  • Cloud Domains - 網域註冊
  • Cloud Storage - 託管靜態檔案
  • Cloud Compute - 提供負載平衡器的存取權。
  • Cloud DNS - 提供 DNS 管理服務
variable "gcp_service_list" {
    description = "The list of apis necessary for the project"
    type        = list(string)
    default = [
        "domains.googleapis.com",
        "storage.googleapis.com",
        "compute.googleapis.com",
        "dns.googleapis.com",
    ]
}

resource "google_project_service" "all" {
    for_each                   = toset(var.gcp_service_list)
    project                    = var.project_number
    service                    = each.key
    disable_dependent_services = false
    disable_on_destroy         = false
}

建立 DNS 區域

建立 DNS 區域,用於管理記錄、將記錄指向負載平衡器、與網域註冊機構互動,以及將 DNS 要求提供給其他 DNS 伺服器。

resource "google_dns_managed_zone" "dnszone" {
    project     = var.project_id
    name        = local.clouddnszone
    dns_name    = "${var.domain}."
    description = "A DNS Zone for managing ${var.domain}"
}

建立 SSL 憑證

https 通訊協定要求需要 SSL 憑證。這會產生一個稍後要附加至負載平衡器的 IP 位址。

resource "google_compute_managed_ssl_certificate" "cert" {
    name        = "${local.basename}-cert"
    description = "Cert for ${local.basename}-microsite"
    project     = var.project_id

    managed {
        domains = [var.domain]
    }

    lifecycle {
        create_before_destroy = true
    }
}

建立外部 IP 位址

將主機繫結至網域名稱,並在網際網路上進行一般通訊。

resource "google_compute_global_address" "ip" {
    project    = var.project_id
    name       = "${local.basename}-ip"
    ip_version = "IPV4"
}

建立儲存空間 bucket

這會建立以網域命名的值區,然後設定值區,使其具備適當的設定,可做為網路伺服器。最後,它會複製網站的簡單範本。

resource "google_storage_bucket" "http_bucket" {
    name     = local.bucket
    project  = var.project_id
    location = var.location
    
    website {
        main_page_suffix = "index.html"
        not_found_page   = "404.html"
    }
}

resource "google_storage_bucket_iam_binding" "policy" {
    bucket = google_storage_bucket.http_bucket.name
    role   = "roles/storage.objectViewer"
    members = [
      "allUsers",
    ]
    depends_on = [google_storage_bucket.http_bucket]
  }

resource "google_storage_bucket_object" "archive" {
    name   = "index.html"
    bucket = google_storage_bucket.http_bucket.name
    source = "code/${var.yesorno}/index.html"
    depends_on = [
        google_project_service.all,
        google_storage_bucket.http_bucket,
    ]
}

啟動負載平衡器

這會建立負載平衡器,並將儲存空間 bucket 設為負載平衡器提供存取權的內容來源。

resource "google_compute_backend_bucket" "be" {
    project     = var.project_id
    name        = "${local.basename}-be"
    bucket_name = google_storage_bucket.http_bucket.name
    depends_on = [google_storage_bucket.http_bucket]
}

resource "google_compute_url_map" "lb" {
    project         = var.project_id
    name            = "${local.basename}-lb"
    default_service = google_compute_backend_bucket.be.id
    depends_on = [google_compute_backend_bucket.be]
}

啟用 HTTP

建立必要的網路規則,將負載平衡器上的通訊埠 80 指向我們執行的服務。

resource "google_compute_target_http_proxy" "lb-proxy" {
    project = var.project_id
    name    = "${local.basename}-lb-proxy"
    url_map = google_compute_url_map.lb.id
    depends_on = [google_compute_url_map.lb]
}

resource "google_compute_forwarding_rule" "http-lb-forwarding-rule" {
    project               = var.project_id
    name                  = "${local.basename}-http-lb-forwarding-rule"
    provider              = google-beta
    region                = "none"
    load_balancing_scheme = "EXTERNAL"
    port_range            = "80"
    target                = google_compute_target_http_proxy.lb-proxy.id
    ip_address            = google_compute_global_address.ip.id
    depends_on = [google_compute_target_http_proxy.lb-proxy]
}

啟用 HTTPS

建立必要的網路規則,將負載平衡器上的通訊埠 443 指向我們執行的服務。並正確建立憑證關聯。

resource "google_compute_target_https_proxy" "ssl-lb-proxy" {
    project          = var.project_id
    name             = "${local.basename}-ssl-lb-proxy"
    url_map          = google_compute_url_map.lb.id
    ssl_certificates = [google_compute_managed_ssl_certificate.cert.id]
    depends_on = [google_compute_url_map.lb,google_compute_managed_ssl_certificate.cert ]
}

resource "google_compute_forwarding_rule" "https-lb-forwarding-rule" {
    project               = var.project_id
    name                  = "${local.basename}-https-lb-forwarding-rule"
    provider              = google-beta
    region                = "none"
    load_balancing_scheme = "EXTERNAL"
    port_range            = "443"
    target                = google_compute_target_https_proxy.ssl-lb-proxy.id
    ip_address            = google_compute_global_address.ip.id
    depends_on = [google_compute_target_https_proxy.ssl-lb-proxy]
}

設定 A 記錄

在 Cloud DNS 中建立適當的規則,讓網域名稱解析為我們建立的 IP 位址。

resource "google_dns_record_set" "a" {
    project      = var.project_id
    name         = "${var.domain}."
    managed_zone = google_dns_managed_zone.dnszone.name
    type         = "A"
    ttl          = 60


    rrdatas = [google_compute_global_address.ip.address]
    depends_on = [google_compute_global_address.ip]
}

./deploystack.go

查詢網域可用性

取得所要求網域的可用性資訊

func domainsSearch(project, domain string) ([]*domainspb.RegisterParameters, error) {
    ctx := context.Background()

    c, err := domains.NewClient(ctx)
    if err != nil {
        return nil, err
    }
    defer c.Close()

    req := &domainspb.SearchDomainsRequest{
        Query:    domain,
        Location: fmt.Sprintf("projects/%s/locations/global", project),
    }
    resp, err := c.SearchDomains(ctx, req)
    if err != nil {
        return nil, err
    }

    return resp.RegisterParameters, nil
}

func domainIsAvailable(project, domain string) (*domainspb.RegisterParameters, error) {
    list, err := domainsSearch(project, domain)
    if err != nil {
        return nil, err
    }
    for _, v := range list {
        if v.DomainName == domain {
            return v, err
        }
    }

    return nil, err
}

查詢網域擁有權

取得目前使用者是否擁有要求網域的資訊。

func domainsIsVerified(project, domain string) (bool, error) {
    ctx := context.Background()

    c, err := domains.NewClient(ctx)
    if err != nil {
        return false, err
    }
    defer c.Close()

    req := &domainspb.ListRegistrationsRequest{
        Filter: fmt.Sprintf("domainName=\"%s\"", domain),
        Parent: fmt.Sprintf("projects/%s/locations/global", project),
    }
    it := c.ListRegistrations(ctx, req)
    for {
        resp, err := it.Next()
        if err == iterator.Done {
            break
        }
        if err != nil {
            return false, err
        }

        if resp.DomainName == domain {
            return true, nil
        }
    }

    return false, nil
}

透過 Cloud Domains 註冊網域

實際執行向註冊商購買網域的操作。

func domainRegister(project string, domaininfo *domainspb.RegisterParameters, contact ContactData) error {
    ctx := context.Background()

    parent := fmt.Sprintf("projects/%s/locations/global", project)

    c, err := domains.NewClient(ctx)
    if err != nil {
        return err
    }
    defer c.Close()

    dnscontact, err := contact.DomainContact()
    if err != nil {
        return err
    }

    req := &domainspb.RegisterDomainRequest{
        Registration: &domainspb.Registration{
            Name:       fmt.Sprintf("%s/registrations/%s", parent, domaininfo.DomainName),
            DomainName: domaininfo.DomainName,
            DnsSettings: &domainspb.DnsSettings{
                DnsProvider: &domainspb.DnsSettings_CustomDns_{
                    CustomDns: &domainspb.DnsSettings_CustomDns{
                        NameServers: []string{
                            "ns-cloud-e1.googledomains.com",
                            "ns-cloud-e2.googledomains.com",
                            "ns-cloud-e3.googledomains.com",
                            "ns-cloud-e4.googledomains.com",
                        },
                    },
                },
            },
            ContactSettings: &dnscontact,
        },
        Parent:      parent,
        YearlyPrice: domaininfo.YearlyPrice,
    }

    if _, err := c.RegisterDomain(ctx, req); err != nil {
        return err
    }

    return nil
}


結論

您現在已設定好小型網站,並擁有網域和安全的靜態網站。 此外,您應該擁有所有程式碼,可修改或擴充這個解決方案,以配合您的環境。