איך מקשרים אפליקציה של Go ב-Cloud Run למסד נתונים של Cloud SQL ל-PostgreSQL

1. סקירה כללית

המחבר Cloud SQL Go הוא הדרך הקלה ביותר לחבר בצורה מאובטחת את אפליקציית Go למסד הנתונים של Cloud SQL. ‫Cloud Run היא פלטפורמה מנוהלת באופן מלא ללא שרת (serverless) שמאפשרת להריץ קונטיינרים ללא שמירת מצב שאפשר להפעיל באמצעות בקשות HTTP. Codelab זה ידגים איך לחבר אפליקציית Go ב-Cloud Run למסד נתונים של Cloud SQL ל-PostgreSQL באופן מאובטח באמצעות חשבון שירות ואימות IAM.

מה תלמדו

בשיעור Lab זה תלמדו איך:

  • יצירת מסדי נתונים של Cloud SQL ל-PostgreSQL
  • פריסת אפליקציית Go ב-Cloud Run
  • חיבור האפליקציה ל-Cloud SQL באמצעות Go Connector

דרישות מוקדמות

  • ההנחה בשיעור ה-Lab הזה היא שאתם מכירים את הסביבות של Cloud Console ו-Cloud Shell.

‫2. לפני שמתחילים

הגדרה של פרויקט ב-Cloud

  1. נכנסים ל-מסוף Google Cloud ויוצרים פרויקט חדש או משתמשים בפרויקט קיים. אם עדיין אין לכם חשבון Google, אתם צריכים ליצור חשבון.

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • שם הפרויקט הוא השם המוצג של הפרויקט הזה למשתתפים. זו מחרוזת תווים שלא נמצאת בשימוש ב-Google APIs. אפשר לעדכן את המיקום הזה בכל שלב.
  • מזהה הפרויקט הוא ייחודי לכל הפרויקטים ב-Google Cloud, והוא קבוע (אי אפשר לשנות אותו אחרי שהוא מוגדר). מסוף Cloud יוצר באופן אוטומטי מחרוזת ייחודית, ובדרך כלל לא צריך לדעת מה היא. ברוב ה-Codelabs, תצטרכו להפנות למזהה הפרויקט (בדרך כלל הוא מסומן כ-PROJECT_ID). אם אתם לא אוהבים את המזהה שנוצר, אתם יכולים ליצור מזהה אקראי אחר. אפשר גם לנסות שם משתמש משלכם ולבדוק אם הוא זמין. אי אפשר לשנות את ההגדרה הזו אחרי השלב הזה, והיא תישאר כזו למשך הפרויקט.
  • לידיעתכם, יש ערך שלישי, מספר פרויקט, שחלק מממשקי ה-API משתמשים בו. במאמרי העזרה מפורט מידע נוסף על שלושת הערכים האלה.
  1. בשלב הבא, תצטרכו להפעיל את החיוב במסוף Cloud כדי להשתמש במשאבי Cloud או בממשקי API של Cloud. העלות של התרגול הזה לא אמורה להיות גבוהה, ואולי אפילו לא תצטרכו לשלם בכלל. כדי להשבית את המשאבים ולא לחייב אתכם מעבר למדריך הזה, אתם יכולים למחוק את המשאבים שיצרתם או למחוק את כל הפרויקט. משתמשים חדשים ב-Google Cloud זכאים לתוכנית תקופת ניסיון בחינם בשווי 300$.

הגדרת הסביבה

לוחצים על הסמל משמאל לסרגל החיפוש כדי להפעיל את Cloud Shell.

ecdc43ada29e91b.png

מפעילים את ממשקי ה-API מ-Cloud Shell:

gcloud services enable compute.googleapis.com sqladmin.googleapis.com \
  run.googleapis.com artifactregistry.googleapis.com \
  cloudbuild.googleapis.com servicenetworking.googleapis.com

אם מתבקשים לאשר, לוחצים על 'אישור' כדי להמשיך.

6356559df3eccdda.png

הפקודה הזו עשויה להימשך כמה דקות, אבל בסופו של דבר היא אמורה להציג הודעה על הצלחה שדומה להודעה הזו:

Operation "operations/acf.p2-327036483151-73d90d00-47ee-447a-b600-a6badf0eceae" finished successfully.

3. הגדרה של חשבון שירות

יוצרים ומגדירים חשבון שירות ב-Google Cloud לשימוש ב-Cloud Run, כדי שיהיו לו ההרשאות הנכונות להתחבר ל-Cloud SQL.

  1. כדי ליצור חשבון שירות חדש, מריצים את הפקודה gcloud iam service-accounts create באופן הבא:
    gcloud iam service-accounts create quickstart-service-account \
      --display-name="Quickstart Service Account"
    
  2. מריצים את הפקודה gcloud projects add-iam-policy-binding באופן הבא כדי להוסיף את התפקיד Cloud SQL Client לחשבון השירות של Google Cloud שיצרתם. ב-Cloud Shell, הביטוי ${GOOGLE_CLOUD_PROJECT} יוחלף בשם הפרויקט. אפשר גם להחליף את התמונה באופן ידני אם זה יותר נוח לכם.
    gcloud projects add-iam-policy-binding ${GOOGLE_CLOUD_PROJECT} \
      --member="serviceAccount:quickstart-service-account@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com" \
      --role="roles/cloudsql.client"
    
  3. מריצים את הפקודה gcloud projects add-iam-policy-binding באופן הבא כדי להוסיף את התפקיד משתמש במכונת Cloud SQL לחשבון השירות של Google Cloud שיצרתם.
    gcloud projects add-iam-policy-binding ${GOOGLE_CLOUD_PROJECT} \
      --member="serviceAccount:quickstart-service-account@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com" \
      --role="roles/cloudsql.instanceUser"
    
  4. מריצים את הפקודה gcloud projects add-iam-policy-binding באופן הבא כדי להוסיף את התפקיד Log Writer לחשבון השירות ב-Google Cloud שיצרתם.
    gcloud projects add-iam-policy-binding ${GOOGLE_CLOUD_PROJECT} \
      --member="serviceAccount:quickstart-service-account@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com" \
      --role="roles/logging.logWriter"
    

4. הגדרת Cloud SQL

מריצים את הפקודה gcloud sql instances create כדי ליצור מכונה של Cloud SQL.

  • ‎–database-version: סוג המנוע של מסד הנתונים והגרסה שלו. אם לא מציינים ערך, המערכת משתמשת בערך ברירת המחדל של ה-API. במאמרי העזרה בנושא גרסאות מסדי נתונים של gcloud אפשר לראות את הגרסאות הזמינות כרגע.
  • ‎–cpu: מספר ליבות המעבד הרצוי במכונה.
  • ‎–memory: ערך של מספר שלם שמציין כמה זיכרון רוצים במכונה. צריך לציין יחידת גודל (לדוגמה, 3072MB או 9GB). אם לא מציינים יחידות, המערכת מניחה שמדובר ב-GB.
  • ‎–region: מיקום אזורי של המופע (לדוגמה: us-central1, asia-east1, us-east1).
  • ‎–database-flags: מאפשר להגדיר דגלים. במקרה הזה, אנחנו מפעילים את cloudsql.iam_authentication כדי לאפשר ל-Cloud Run להתחבר ל-Cloud SQL באמצעות חשבון השירות שיצרנו קודם.
    gcloud sql instances create quickstart-instance \
      --database-version=POSTGRES_14 \
      --cpu=1 \
      --memory=4GB \
      --region=us-central1 \
      --database-flags=cloudsql.iam_authentication=on
    

יכול להיות שיעברו כמה דקות עד שהפקודה הזו תסתיים.

מריצים את הפקודה gcloud sql databases create כדי ליצור מסד נתונים ב-Cloud SQL בתוך quickstart-instance.

gcloud sql databases create quickstart_db \
  --instance=quickstart-instance

יוצרים משתמש במסד נתונים של PostgreSQL עבור חשבון השירות שיצרתם קודם כדי לגשת למסד הנתונים.

gcloud sql users create quickstart-service-account@${GOOGLE_CLOUD_PROJECT}.iam \
  --instance=quickstart-instance \
  --type=cloud_iam_service_account

5. הכנת הבקשה

מכינים אפליקציית Go שמגיבה לבקשות HTTP.

  1. ב-Cloud Shell, יוצרים ספרייה חדשה בשם helloworld ועוברים אליה:
    mkdir helloworld
    cd helloworld
    
  2. מריצים את הפקודה go mod init כדי לאתחל אפליקציית Go חדשה.
    go mod init github.com/GoogleCloudPlatform/golang-samples/run/helloworld
    
  3. מתקינים את התלות Cloud SQL Go Connector.
    go get cloud.google.com/go/cloudsqlconn
    go get cloud.google.com/go/cloudsqlconn/postgres/pgxv4
    
  4. יוצרים קובץ main.go עם קוד האפליקציה. הקוד הזה יכול:
    • אישור בקשות HTTP
    • התחברות למסד הנתונים
    • אחסון השעה של בקשת ה-HTTP במסד הנתונים
    • החזרת הזמנים של חמש הבקשות האחרונות
    מריצים את הפקודה הבאה ב-Cloud Shell:
    cat > main.go << "EOF"
    package main
    
    import (
      "database/sql"
      "encoding/json"
      "fmt"
      "log"
      "net/http"
      "os"
      "time"
    
      "cloud.google.com/go/cloudsqlconn"
      "cloud.google.com/go/cloudsqlconn/postgres/pgxv4"
    )
    
    // visitData is used to pass data to the HTML template.
    type visitData struct {
      RecentVisits []visit
    }
    
    // visit contains a single row from the visits table in the database.
    // Each visit includes a timestamp.
    type visit struct {
      VisitTime time.Time
    }
    
    // getDB creates a connection to the database
    // based on environment variables.
    func getDB() (*sql.DB, func() error) {
      cleanup, err := pgxv4.RegisterDriver("cloudsql-postgres", cloudsqlconn.WithIAMAuthN())
      if err != nil {
        log.Fatalf("Error on pgxv4.RegisterDriver: %v", err)
      }
    
      dsn := fmt.Sprintf("host=%s user=%s dbname=%s sslmode=disable", os.Getenv("INSTANCE_CONNECTION_NAME"), os.Getenv("DB_USER"), os.Getenv("DB_NAME"))
      db, err := sql.Open("cloudsql-postgres", dsn)
      if err != nil {
        log.Fatalf("Error on sql.Open: %v", err)
      }
    
      createVisits := `CREATE TABLE IF NOT EXISTS visits (
        id SERIAL NOT NULL,
        created_at timestamp NOT NULL,
        PRIMARY KEY (id)
      );`
      _, err = db.Exec(createVisits)
      if err != nil {
        log.Fatalf("unable to create table: %s", err)
      }
    
      return db, cleanup
    }
    
    func main() {
      port := os.Getenv("PORT")
      if port == "" {
        port = "8080"
      }
      log.Printf("Listening on port %s", port)
      db, cleanup := getDB()
      defer cleanup()
    
      http.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) {
        // Insert current visit
        _, err := db.Exec("INSERT INTO visits(created_at) VALUES(NOW())")
        if err != nil {
          log.Fatalf("unable to save visit: %v", err)
        }
    
        // Get the last 5 visits
        rows, err := db.Query("SELECT created_at FROM visits ORDER BY created_at DESC LIMIT 5")
        if err != nil {
          log.Fatalf("DB.Query: %v", err)
        }
        defer rows.Close()
    
        var visits []visit
        for rows.Next() {
          var visitTime time.Time
          err := rows.Scan(&visitTime)
          if err != nil {
            log.Fatalf("Rows.Scan: %v", err)
          }
          visits = append(visits, visit{VisitTime: visitTime})
        }
        response, err := json.Marshal(visitData{RecentVisits: visits})
        if err != nil {
          log.Fatalf("renderIndex: failed to parse totals with json.Marshal: %v", err)
        }
        w.Write(response)
      })
      if err := http.ListenAndServe(":"+port, nil); err != nil {
        log.Fatal(err)
      }
    }
    
    EOF
    

הקוד הזה יוצר שרת אינטרנט בסיסי שמקשיב ליציאה שמוגדרת על ידי משתנה הסביבה PORT. האפליקציה מוכנה עכשיו לפריסה.

6. פריסת אפליקציית Cloud Run

מריצים את הפקודה הבאה כדי לפרוס את האפליקציה:

  • ‎–region: מיקום אזורי של המופע (לדוגמה: us-central1, asia-east1, us-east1).
  • ‎–source: קוד המקור שרוצים לפרוס. במקרה הזה, . מתייחס לקוד המקור בתיקייה הנוכחית helloworld.
  • ‎–set-env-vars: מגדיר משתני סביבה שהאפליקציה משתמשת בהם כדי להפנות את האפליקציה למסד הנתונים של Cloud SQL.
  • ‎–service-account: מקשר את הפריסה של Cloud Run לחשבון השירות עם הרשאות להתחבר למסד הנתונים של Cloud SQL שנוצר בתחילת ה-Codelab הזה.
  • ‎–allow-unauthenticated: מאפשר בקשות לא מאומתות כדי שהאפליקציה תהיה נגישה מהאינטרנט.
gcloud run deploy helloworld \
  --region=us-central1 \
  --source=. \
  --set-env-vars INSTANCE_CONNECTION_NAME="${GOOGLE_CLOUD_PROJECT}:us-central1:quickstart-instance" \
  --set-env-vars DB_NAME="quickstart_db" \
  --set-env-vars DB_USER="quickstart-service-account@${GOOGLE_CLOUD_PROJECT}.iam" \
  --service-account="quickstart-service-account@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com" \
  --allow-unauthenticated

אם מוצגת הנחיה, מקישים על y ועל Enter כדי לאשר שרוצים להמשיך:

Do you want to continue (Y/n)? y

אחרי כמה דקות, האפליקציה אמורה לספק כתובת URL שאפשר להיכנס אליה.

עוברים לכתובת ה-URL כדי לראות את האפליקציה בפעולה. בכל פעם שתבקרו בכתובת ה-URL או תרעננו את הדף, יוצגו חמשת הביקורים האחרונים בפורמט JSON.

7. מזל טוב

פרסתם אפליקציית Go ב-Cloud Run שיכולה להתחבר למסד נתונים של PostgreSQL שפועל ב-Cloud SQL.

הנושאים שדיברנו עליהם:

  • יצירת מסד נתונים ב-Cloud SQL ל-PostgreSQL
  • פריסת אפליקציית Go ב-Cloud Run
  • חיבור האפליקציה ל-Cloud SQL באמצעות מחבר Go

הסרת המשאבים

כדי להימנע מחיובים בחשבון Google Cloud בגלל השימוש במשאבים שנעשה במסגרת המדריך הזה, אפשר למחוק את הפרויקט שמכיל את המשאבים, או להשאיר את הפרויקט ולמחוק את המשאבים בנפרד. כדי למחוק את הפרויקט כולו, אפשר להריץ את הפקודה:

gcloud projects delete ${GOOGLE_CLOUD_PROJECT}