Hosting statico con dominio

Architettura

Static Hosting with Domain è un semplice strumento per la creazione di siti web statici che crea un semplice sito utilizzando un bucket di archiviazione per gestire il sito:

  • Archiviazione - Archiviazione di file - Cloud Storage
  • Networking - Bilanciamento del carico - Bilanciatore del carico Cloud
  • Networking - DNS - Cloud DNS
  • Gestione del dominio - Registrar - Cloud Domains

Inizia

Fai clic sul link seguente a una copia del codice sorgente in Cloud Shell. Da lì, un singolo comando avvierà una copia funzionante dell'applicazione nel tuo progetto.

Apri in Cloud Shell

Visualizza il codice sorgente su GitHub


Hosting statico con componenti di dominio

L'architettura di hosting statico con dominio utilizza diversi prodotti. Di seguito sono elencati i componenti, insieme a ulteriori informazioni sui componenti, tra cui link a video correlati, documentazione del prodotto e procedure dettagliate interattive.
Video Documenti Procedure dettagliate
Cloud Storage Cloud Storage offre archiviazione di file e pubblicazione pubblica di immagini su http.
Cloud DNS Cloud DNS offre la gestione del DNS, consentendoti di eseguire la tua infrastruttura DNS utilizzando l'infrastruttura DNS esistente di Google.
Cloud Load Balancing Il bilanciatore del carico Google Cloud ti consente di posizionare un bilanciatore del carico davanti al bucket di archiviazione, utilizzando così i certificati SSL, Logging e Monitoring.
Domini Cloud Cloud Domains ti consente di acquistare domini, agendo come un registrar di domini, ma, una volta fatto, puoi gestirli e gestire la fatturazione tramite il tuo account Google Cloud.

Script

Lo script di installazione utilizza un eseguibile scritto in go e negli strumenti dell'interfaccia a riga di comando di Terraform per acquisire un progetto vuoto e installare l'applicazione al suo interno. L'output deve essere un'applicazione funzionante e un URL per l'indirizzo IP di bilanciamento del carico.

./main.tf

Attiva i servizi

I servizi Google Cloud sono disabilitati in un progetto per impostazione predefinita. Per utilizzare una qualsiasi delle soluzioni qui riportate, dobbiamo attivare quanto segue:

  • Cloud Domains: registrazione del dominio
  • Cloud Storage: hosting dei file statici
  • Cloud Compute: fornisci l'accesso ai bilanciatori del carico.
  • Cloud DNS: consente di gestire il 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
}

Crea zona DNS

Crea una zona DNS per la gestione dei record, indirizzandoli ai bilanciatori del carico, interagisce con i registrar di dominio e gestisce richieste DNS ad altri server 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}"
}

Crea certificato SSL

Per le richieste del protocollo https sono richiesti certificati SSL. Questo ne genera uno che verrà collegato al bilanciatore del carico in un comando successivo.

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

Crea indirizzo IP esterno

È necessario associare un host al nome di dominio e comunicare in generale su internet.

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

Crea bucket di archiviazione

Viene creato un bucket con nome in base al dominio e poi il bucket viene configurato con la configurazione corretta in modo che funzioni come server web. Infine, copia il modello semplice per il sito.

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

Bilanciatore del carico in piedi

Questo crea il bilanciatore del carico e imposta il bucket di archiviazione come origine dei contenuti a cui il bilanciatore del carico fornirà l'accesso.

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

Abilita HTTP

Crea le regole di networking necessarie per indirizzare la porta 80 sul bilanciatore del carico al servizio in esecuzione.

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

Attiva HTTPS

Crea le regole di networking necessarie per indirizzare la porta 443 sul bilanciatore del carico al servizio in esecuzione. Inoltre, associa correttamente il certificato.

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

Imposta un record

Crea la regola adeguata in Cloud DNS che farà risolvere il nome di dominio nell'indirizzo IP che abbiamo creato.

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

Disponibilità domini di query

Recupera informazioni sulla disponibilità del dominio richiesto

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
}

Proprietà dominio query

Recupera le informazioni indipendentemente dal fatto che l'utente corrente sia proprietario o meno del dominio richiesto.

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
}

Registra dominio con Cloud Domains

Esegue effettivamente l'operazione per acquistare il dominio dal registrar.

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
}


Conclusione

Ora hai un sito web di piccole dimensioni con un dominio e un sito statico sicuro. Inoltre, dovresti disporre di tutto il codice per modificare o estendere questa soluzione in modo che si adatti al tuo ambiente.