使用域名的静态托管

使用集合让一切井井有条 根据您的偏好保存内容并对其进行分类。

架构

带有网站的静态托管是一种简单的静态网站创建者,它使用存储分区构建一个简单的网站来托管网站:

  • 存储 - 文件存储 - Cloud Storage
  • 网络 - 负载均衡 - Cloud 负载平衡器
  • 网络 - 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 负载均衡器允许您将负载均衡器放置在存储分区的前面,以便您能够使用 SSL 证书、日志记录和监控功能。
Cloud 网域 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,
    ]
}

立式负载平衡器

这会创建负载均衡器,并将 Storage 存储分区设置为负载均衡器将为其提供访问权限的内容的来源。

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
}


总结

您现在有一个包含网域和静态静态网站的小型网站。此外,您应该可以使用所有代码修改或扩展此解决方案,以适应您的环境。