Statisches Hosting mit Domain

+

Architektur

Static Hosting with Domain ist ein einfacher Tool zum Erstellen statischer Websites, mit dem eine einfache Website mit einem Storage Bucket erstellt wird, um die Website bereitzustellen:

  • Speicher – Dateispeicher – Cloud-Speicher
  • Netzwerk – Load Balancing – Cloud Load Balancer
  • Netzwerk – DNS – Cloud DNS
  • Domainverwaltung – Registrar – Cloud Domains

Jetzt starten

Klicken Sie auf den folgenden Link, um eine Kopie des Quellcodes in Cloud Shell aufzurufen. Dort können Sie mit einem einzigen Befehl eine funktionierende Kopie der Anwendung in Ihrem Projekt erstellen.

In Cloud Shell öffnen

Quellcode auf GitHub ansehen


Statisches Hosting mit Domainkomponenten

Bei der Architektur „Static Hosting with Domain“ werden mehrere Produkte verwendet. Im Folgenden finden Sie eine Liste der Komponenten sowie weitere Informationen zu den Komponenten, einschließlich Links zu ähnlichen Videos, Produktdokumentationen und interaktiven Schritt-für-Schritt-Anleitungen.
Video Docs Schritt-für-Schritt-Anleitungen
Cloud Storage Cloud Storage bietet Dateispeicher und die öffentliche Bereitstellung von Bildern über http(s).
Cloud DNS Cloud DNS bietet DNS-Verwaltung. So können Sie Ihre eigene DNS-Infrastruktur mit der vorhandenen DNS-Infrastruktur von Google ausführen.
Cloud Load Balancing Mit dem Google Cloud Load Balancer können Sie einen Load Balancer vor den Speicher-Bucket platzieren und so SSL-Zertifikate, Logging und Monitoring verwenden.
Cloud Domains Cloud Domains ist ein Domain-Registrar, mit dem Sie Domains kaufen können. Anschließend können Sie sie über Ihr Google Cloud-Konto verwalten und die Abrechnung abwickeln.

Skripts

Das Installationsskript verwendet eine in go geschriebene ausführbare Datei und Terraform-Befehlszeilentools, um ein leeres Projekt zu erstellen und die Anwendung darin zu installieren. Die Ausgabe sollte eine funktionierende Anwendung und eine URL für die Load Balancing-IP-Adresse sein.

./main.tf

Dienste aktivieren

Google Cloud-Dienste sind in einem Projekt standardmäßig deaktiviert. Damit Sie eine der folgenden Lösungen verwenden können, müssen Sie Folgendes aktivieren:

  • Cloud Domains – Domainregistrierung
  • Cloud Storage: Hostet die statischen Dateien
  • Cloud Compute: Zugriff auf Load Balancer gewähren.
  • Cloud DNS: Ermöglicht die DNS-Verwaltung.
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-Zone erstellen

Erstellt eine DNS-Zone zum Verwalten von Einträgen, verweist sie auf Load Balancer, interagiert mit Domainregistratoren und stellt DNS-Anfragen an andere DNS-Server.

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-Zertifikat erstellen

SSL-Zertifikate sind für HTTPS-Protokollanfragen erforderlich. Dadurch wird eine generiert, die später mit einem Befehl dem Load Balancer hinzugefügt wird.

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

Externe IP-Adresse erstellen

Er ist erforderlich, um einen Host an den Domainnamen zu binden und allgemein im Internet zu kommunizieren.

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

Storage-Bucket erstellen

Dadurch wird ein Bucket mit dem Namen der Domain erstellt und dann so konfiguriert, dass er als Webserver dient. Anschließend wird die einfache Vorlage für die Website kopiert.

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

Load Balancer einrichten

Dadurch wird der Load Balancer erstellt und der Storage Bucket als Quelle der Inhalte eingerichtet, auf die der Load Balancer Zugriff gewährt.

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 aktivieren

Erstellen Sie die erforderlichen Netzwerkregeln, um Port 80 des Load Balancers auf den ausgeführten Dienst zu verweisen.

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 aktivieren

Erstellen Sie die erforderlichen Netzwerkregeln, um Port 443 des Load Balancers auf den von uns ausgeführten Dienst zu verweisen. Außerdem wird das Zertifikat richtig verknüpft.

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-Eintrag festlegen

Erstellen Sie die richtige Regel in Cloud DNS, damit der Domainname in die von uns erstellte IP-Adresse aufgelöst wird.

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

Verfügbarkeit von Domains abfragen

Ruft Informationen zur Verfügbarkeit der angeforderten Domain ab

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
}

Domaininhaberschaft abfragen

Gibt an, ob der aktuelle Nutzer der Inhaber der angeforderten Domain ist.

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
}

Domain bei Cloud Domains registrieren

Führt den Vorgang zum Kauf der Domain beim Registrar aus.

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
}


Fazit

Sie haben jetzt eine kleine Website mit einer Domain und einer sicheren, statischen Website eingerichtet. Außerdem sollten Sie den gesamten Code haben, um diese Lösung an Ihre Umgebung anzupassen oder zu erweitern.