搭配網域的靜態代管服務

+

架構

Static Hosting with Domain 是簡易的靜態網站建立工具,可使用 Storage Bucket 建立簡易網站,並提供網站服務:

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

開始使用

按一下以下連結,前往 Cloud Shell 中的原始碼副本。完成後,您只需執行單一指令,即可在專案中啟動應用程式的可用副本。

在 Cloud Shell 開啟

在 GitHub 上查看原始碼


使用網域元件進行靜態託管

使用 Static Hosting with Domain 架構可運用多項產品。以下列出這些元件,並提供相關資訊,包括相關影片、產品說明文件和互動式操作說明的連結。
影片 文件 逐步操作說明
Cloud Storage Cloud Storage 提供檔案儲存空間,並透過 http(s) 公開提供圖片。
Cloud DNS Cloud DNS 提供 DNS 管理功能,可讓您使用 Google 現有的 DNS 基礎架構,執行自己的 DNS 基礎架構。
Cloud Load Balancing Google Cloud Load Balancer 可讓您在 Storage 值區前端放置負載平衡器,以便使用 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",
        "appengine.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 憑證。這會產生一個後續指令中會附加至負載平衡器的值。

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"
}

建立儲存空間值區

這項操作會建立以網域命名的值區,然後設定值區並以適當的設定運作,以便充當網路伺服器。最後,它會複製網站的簡易範本。

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,
    ]
}

設定負載平衡器

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

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
}


結論

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