كيفية ربط تطبيق Go على Cloud Run بقاعدة بيانات Cloud SQL لقاعدة بيانات PostgreSQL

1. نظرة عامة

يُعد موصل Cloud SQL Go أسهل طريقة لربط تطبيق Go بقاعدة بيانات Cloud SQL بأمان. التشغيل في السحابة الإلكترونية هو نظام أساسي مُدار بالكامل بدون خادم يتيح لك تشغيل حاويات بدون حالة قابلة للإلغاء من خلال طلبات HTTP. سيوضح هذا الدرس التطبيقي حول الترميز كيفية ربط تطبيق Go على Cloud Run بقاعدة بيانات Cloud SQL لخدمة PostgreSQL بأمان باستخدام حساب خدمة باستخدام "مصادقة إدارة الهوية وإمكانية الوصول".

ما سوف تتعلمه

ستتعلم في هذا التمرين المعملي كيفية القيام بما يلي:

  • إنشاء Cloud SQL لقاعدة بيانات PostgreSQL
  • نشر تطبيق Go في Cloud Run
  • ربط تطبيقك بخدمة Cloud SQL باستخدام موصِّل Go

المتطلبات الأساسية

  • يفترض هذا التمرين المعملي الإلمام ببيئة Cloud Console وCloud Shell.

2. قبل البدء

إعداد مشروع Cloud

  1. سجِّل الدخول إلى Google Cloud Console وأنشئ مشروعًا جديدًا أو أعِد استخدام مشروع حالي. إذا لم يكن لديك حساب على Google، عليك إنشاء حساب.

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • اسم المشروع هو الاسم المعروض للمشاركين في هذا المشروع. وهي سلسلة أحرف لا تستخدمها Google APIs. ويمكنك تعديله في أي وقت.
  • يكون رقم تعريف المشروع فريدًا في جميع مشاريع Google Cloud وغير قابل للتغيير (لا يمكن تغييره بعد تحديده). تنشئ Cloud Console سلسلة فريدة تلقائيًا. فعادةً لا تهتم بما هو. في معظم الدروس التطبيقية حول الترميز، يجب الإشارة إلى رقم تعريف المشروع (يتم تحديده عادةً على أنّه PROJECT_ID). وإذا لم يعجبك المعرّف الذي تم إنشاؤه، يمكنك إنشاء رقم تعريف عشوائي آخر. ويمكنك بدلاً من ذلك تجربة طلبك الخاص ومعرفة ما إذا كان متوفّرًا. ولا يمكن تغييره بعد هذه الخطوة وسيبقى طوال مدة المشروع.
  • لمعلوماتك، هناك قيمة ثالثة، وهي رقم المشروع الذي تستخدمه بعض واجهات برمجة التطبيقات. اطّلِع على مزيد من المعلومات حول هذه القيم الثلاث في المستندات.
  1. بعد ذلك، عليك تفعيل الفوترة في Cloud Console لاستخدام الموارد/واجهات برمجة التطبيقات في Cloud. إنّ تنفيذ هذا الدرس التطبيقي حول الترميز لن يكون مكلفًا أو مكلفًا على الإطلاق. لإيقاف تشغيل الموارد حتى لا تتحمل الفوترة بعد هذا البرنامج التعليمي، يمكنك حذف الموارد التي أنشأتها أو حذف المشروع بالكامل. يكون مستخدمو Google Cloud الجدد مؤهَّلون للانضمام إلى برنامج فترة تجريبية مجانية بقيمة 300 دولار أمريكي.

إعداد البيئة

يمكنك تفعيل Cloud Shell من خلال النقر على الرمز على يسار شريط البحث.

ecdc43ada29e91b.png

من 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. شغِّل الأمر add-iam-policy-binding في مشاريع gcloud على النحو التالي لإضافة دور عميل Cloud SQL إلى حساب خدمة 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. شغِّل الأمر add-iam-policy-binding في مشاريع gcloud على النحو التالي لإضافة دور مستخدم مثيل 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. شغِّل الأمر add-iam-policy-binding في مشاريع gcloud على النحو التالي لإضافة دور 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: نوع محرك قاعدة البيانات وإصداره. في حال ترك هذه السياسة بدون تحديد، يتم استخدام الإعدادات التلقائية لواجهة برمجة التطبيقات. راجِع وثائق إصدارات قاعدة بيانات gcloud للاطّلاع على الإصدارات المتاحة حاليًا.
  • –cpu: عدد النوى المطلوبة في الجهاز.
  • –memory: قيمة العدد الكامل التي تشير إلى حجم الذاكرة المطلوبة في الجهاز. يجب تقديم وحدة حجم (على سبيل المثال، 3072 ميغابايت أو 9 غيغابايت). إذا لم يتم تحديد أي وحدات، يتم افتراض غيغابايت.
  • –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.
    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 التي تم إنشاؤها في بداية هذا الدرس التطبيقي حول الترميز.
  • –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 SQL باستخدام موصِّل Go

تَنظيم

لتجنُّب تحمُّل الرسوم المفروضة على حسابك على Google Cloud مقابل الموارد المُستخدَمة في هذا الدليل التوجيهي، يمكنك إما حذف المشروع الذي يحتوي على الموارد أو الاحتفاظ بالمشروع وحذف الموارد الفردية. إذا كنت ترغب في حذف المشروع بأكمله، يمكنك تشغيل:

gcloud projects delete ${GOOGLE_CLOUD_PROJECT}