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 den Quellcode in Cloud Shell zu kopieren. Einmal können Sie mit einem einzigen Befehl eine Arbeitskopie der Anwendung in Ihrem Projekt...

In Cloud Shell öffnen

Quellcode auf GitHub ansehen


Statisches Hosting mit Domainkomponenten

Bei der Architektur für statisches Hosting mit 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 öffentliche Bereitstellung von Bildern über HTTP(s).
Cloud DNS Cloud DNS bietet DNS-Verwaltung, mit der Sie Ihre eigene DNS-Infrastruktur mit der vorhandenen DNS-Infrastruktur von Google ausführen können.
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 ermöglicht es Ihnen, Domains zu kaufen und dabei wie ein Domain-Registrar zu handeln. Danach können Sie diese Domains jedoch über Ihr Google Cloud-Konto verwalten und die Abrechnung abwickeln.

Skripts

Das Installationsskript verwendet eine ausführbare Datei, die in go geschrieben ist, und die Terraform-Befehlszeilentools, um ein leeres Projekt zur Installation der darin enthaltenen Anwendung. Die Ausgabe sollte eine eine funktionierende Anwendung und eine URL für die Load-Balancing-IP-Adresse.

./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 zur Verwaltung von Einträgen und verweist sie auf Load-Balancer, die Interaktion mit Domain-Registraren und die Bereitstellung von 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 ein der in einem späteren Befehl an den Load-Balancer angehängt 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 erstellt, der nach der Domain benannt ist, und den Bucket mit Konfiguration, um als Webserver fungieren zu können. 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,
    ]
}

Stand-up-Load-Balancer

Dadurch wird der Load-Balancer erstellt und der Storage-Bucket wird als Quelle für auf den 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

Erstellt die erforderlichen Netzwerkregeln, um Port 443 des Load-Balancers auf den 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

Erstellt 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

Domainverfügbarkeit abfragen

Informationen zur Verfügbarkeit der angeforderten Domain abrufen

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

Ruft Informationen darüber ab, ob der aktuelle Nutzer Inhaber der angeforderten Domain ist oder nicht.

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 vom 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.