Alojamento estático com domínio

+

Arquitetura

O alojamento estático com domínio é um criador de Websites estáticos simples que cria um site simples usando um contentor de armazenamento para publicar o Website:

  • Armazenamento – Armazenamento de ficheiros – Cloud Storage
  • Redes – Balanceamento de carga – Balanceador de carga da nuvem
  • Rede – DNS – Cloud DNS
  • Gestão de domínios – Entidade de registo – Cloud Domains

Começar

Clique no seguinte link para aceder a uma cópia do código fonte no Cloud Shell. Quando estiver lá, um único comando vai iniciar uma cópia funcional da aplicação no seu projeto.

Abra no Cloud Shell

Veja o código fonte no GitHub


Alojamento estático com componentes de domínio

A arquitetura de alojamento estático com domínio usa vários produtos. A lista seguinte apresenta os componentes, juntamente com mais informações sobre os componentes, incluindo links para vídeos relacionados, documentação do produto e visitas guiadas interativas.
Vídeo Docs Instruções passo a passo
Cloud Storage O Cloud Storage oferece armazenamento de ficheiros e publicação pública de imagens através de http(s).
Cloud DNS O Cloud DNS oferece gestão de DNS, o que lhe permite executar a sua própria infraestrutura de DNS através da infraestrutura de DNS existente da Google.
Cloud Load Balancing O Google Cloud Load Balancer permite-lhe colocar um balanceador de carga à frente do contentor de armazenamento, o que lhe permite usar certificados SSL, registo e monitorização.
Cloud Domains O Cloud Domains permite-lhe comprar domínios, funcionando como uma entidade de registo de domínios. No entanto, depois de o fazer, pode geri-los e processar a faturação através da sua conta do Google Cloud.

Scripts

O script de instalação usa um executável escrito em go e ferramentas da CLI do Terraform para usar um projeto vazio e instalar a aplicação no mesmo. A saída deve ser uma aplicação funcional e um URL para o endereço IP de equilíbrio de carga.

./main.tf

Ative os serviços

Os serviços Google Cloud estão desativados num projeto por predefinição. Para usar qualquer uma das soluções aqui, temos de ativar o seguinte:

  • Cloud Domains: registo de domínios
  • Cloud Storage: alojamento dos ficheiros estáticos
  • Cloud Compute: fornece acesso a balanceadores de carga.
  • Cloud DNS: oferece gestão de 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
}

Crie uma zona DNS

Cria uma zona DNS para gerir registos, direcionando-os para equilibradores de carga, interagindo com registadores de domínios e atendendo a pedidos DNS para outros servidores 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}"
}

Crie um certificado SSL

Os certificados SSL são necessários para pedidos de protocolo https. Isto gera um que vai ser anexado ao equilibrador de carga num comando posterior.

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

Crie um endereço IP externo

Necessário para associar um anfitrião ao nome do domínio e comunicar em geral na Internet.

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

Crie um contentor de armazenamento

Esta ação cria um contentor com o nome do domínio e, em seguida, configura o contentor com a configuração adequada para funcionar como um servidor Web. Por último, copia o modelo simples para o site.

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

Balanceador de carga autónomo

Isto cria o balanceador de carga e configura o contentor de armazenamento como a origem do conteúdo ao qual o balanceador de carga vai fornecer acesso.

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

Ative o HTTP

Cria as regras de rede necessárias para direcionar a porta 80 no balanceador de carga para o serviço que estamos a executar.

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

Ative o HTTPS

Cria as regras de rede necessárias para direcionar a porta 443 no balanceador de carga para o serviço que estamos a executar. Também associa o certificado corretamente.

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

Defina uma gravação

Cria a regra adequada no Cloud DNS que fará com que o nome de domínio seja resolvido para o endereço IP que criámos.

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

Consultar a disponibilidade de domínios

Obtém informações sobre a disponibilidade do domínio pedido

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
}

Consultar propriedade do domínio

Obtém informações sobre se o utilizador atual é ou não proprietário do domínio pedido.

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
}

Registe um domínio com o Cloud Domains

Executa efetivamente a operação para comprar o domínio à entidade de registo.

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
}


Conclusão

Agora, tem um pequeno Website configurado com um domínio e um site estático seguro. Além disso, deve ter todo o código para modificar ou expandir esta solução de forma a adequar-se ao seu ambiente.