אירוח סטטי עם דומיין

ארכיטקטורה

‫Static Hosting with Domain הוא כלי פשוט ליצירת אתרים סטטיים, שיוצר אתר פשוט באמצעות קטגוריית אחסון לאירוח האתר:

  • אחסון – אחסון קבצים – Cloud Storage
  • Networking - Load Balancing - Cloud Load Balancer
  • Networking - DNS - Cloud DNS
  • ניהול דומיינים – רשם – Cloud Domains

שנתחיל?

כדי להעתיק את קוד המקור ב-Cloud Shell, לוחצים על הקישור הבא. אחרי שמגיעים לשם, פקודה אחת תתחיל הרצה של עותק עובד של האפליקציה בפרויקט.

Cloud Shell-פתיחה ב

צפייה בקוד המקור ב-GitHub


אירוח סטטי עם רכיבי דומיין

ארכיטקטורת האירוח הסטטי עם דומיין משתמשת בכמה מוצרים. ברשימה הבאה מפורטים הרכיבים, וגם מידע נוסף על הרכיבים, כולל קישורים לסרטונים קשורים, למסמכי מוצר ולמדריכים אינטראקטיביים.
וידאו Docs הדרכות מפורטות
Cloud Storage ‫Cloud Storage מספק אחסון קבצים והצגה ציבורית של תמונות באמצעות http(s).
Cloud DNS ‫Cloud DNS מספק ניהול DNS – הוא מאפשר לכם להפעיל תשתית DNS משלכם באמצעות תשתית ה-DNS הקיימת של Google.
Cloud Load Balancing מאזן העומסים של Google Cloud מאפשר לכם להציב מאזן עומסים לפני קטגוריית האחסון, וכך להשתמש באישור SSL, ביומנים ובמעקב.
Cloud Domains שירות Cloud Domains מאפשר לכם לקנות דומיינים, והוא פועל כמו רשם דומיינים. אחרי שאתם קונים דומיין, אתם יכולים לנהל אותו ולטפל בחיוב דרך חשבון Google Cloud שלכם.

סקריפטים

סקריפט ההתקנה משתמש בקובץ הפעלה שנכתב ב-go ובכלים של Terraform CLI כדי לקחת פרויקט ריק ולהתקין בו את האפליקציה. הפלט צריך להיות אפליקציה פעילה וכתובת URL לכתובת ה-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",
    ]
}

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

נדרשים אישורי SSL לבקשות פרוטוקול https. הפעולה הזו יוצרת אחד שיוצמד למאזן העומסים בפקודה מאוחרת יותר.

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

מאזן עומסים של Stand Up

הפעולה הזו יוצרת את מאזן העומסים ומגדירה את קטגוריית האחסון כמקור התוכן שלמאזן העומסים תהיה גישה אליו.

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

הגדרת שיא

המערכת יוצרת את הכלל המתאים ב-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
}


סיכום

עכשיו יש לכם אתר קטן עם דומיין ואתר סטטי מאובטח. בנוסף, צריך שיהיה לכם את כל הקוד כדי לשנות או להרחיב את הפתרון הזה כך שיתאים לסביבה שלכם.