如何將 Cloud Run 中的 Go 應用程式連線至 PostgreSQL 適用的 Cloud SQL 資料庫

1. 總覽

您可以使用 Cloud SQL Go 連接器,安全地將 Go 應用程式連線至 Cloud SQL 資料庫。Cloud Run 是全代管的無伺服器平台,能夠讓您執行可透過 HTTP 要求叫用的無狀態容器。這個程式碼研究室將示範如何使用 IAM 驗證功能,將 Cloud Run 上的 Go 應用程式安全地連結至 PostgreSQL 適用的 Cloud SQL 資料庫,以及使用 IAM 驗證功能。

學習目標

在本研究室中,您將瞭解如何執行下列操作:

  • 建立 PostgreSQL 適用的 Cloud SQL 資料庫
  • 將 Go 應用程式部署至 Cloud Run
  • 使用 Go 連接器將應用程式連結至 Cloud SQL

必要條件

  • 本研究室假設您熟悉 Cloud 控制台和 Cloud Shell 環境。

2. 事前準備

Cloud 專案設定

  1. 登入 Google Cloud 控制台,建立新專案或重複使用現有專案。如果您還沒有 Google 帳戶,請先建立帳戶

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • 「專案名稱」是這項專案參與者的顯示名稱。這是 Google API 未使用的字元字串。您隨時可以更新這項資訊。
  • 所有 Google Cloud 專案的專案 ID 均不得重複,而且設定後即無法變更。Cloud 控制台會自動產生一個不重複的字串。但通常是在乎它何在在大部分的程式碼研究室中,您必須參照專案 ID (通常為 PROJECT_ID)。如果您對產生的 ID 不滿意,可以隨機產生一個 ID。此外,您也可以自行嘗試,看看系統是否提供該付款方式。在完成這個步驟後就無法變更,而且在專案期間仍會保持有效。
  • 資訊中的第三個值是專案編號,部分 API 會使用這個編號。如要進一步瞭解這三個值,請參閱說明文件
  1. 接下來,您需要在 Cloud 控制台中啟用計費功能,才能使用 Cloud 資源/API。執行這個程式碼研究室並不會產生任何費用,如果有的話。如要關閉資源,以免系統產生本教學課程結束後產生的費用,您可以刪除自己建立的資源,或刪除整個專案。Google Cloud 的新使用者符合 $300 美元免費試用計畫的資格。

環境設定

如要啟用 Cloud Shell,請按一下搜尋列右側的圖示。

ecdc43ada29e91b.png

在 Cloud Shell 中啟用 API:

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. 設定服務帳戶

建立並設定 Cloud Run 要使用的 Google Cloud 服務帳戶,讓該帳戶具備連線至 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 用戶端角色新增至您剛建立的 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 指令,將記錄寫入者角色新增至您剛建立的 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:整數值,表示機器所需的記憶體大小。必須提供尺寸單位 (例如 3072 MB 或 9 GB)。如未指定單位,則會採用 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 指令,在 quickstart-instance 中建立 Cloud SQL 資料庫。

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. 準備申請

準備回應 HTTP 要求的 Go 應用程式。

  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 要求的時間儲存在資料庫中
    • 傳回最後 5 個要求的時間
    ,瞭解如何調查及移除這項存取權。 在 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

如果出現提示訊息,請按下 yEnter 鍵確認要繼續操作:

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

幾分鐘後,應用程式應該會提供一個網址,供您瀏覽。

前往該網址即可查看應用程式的實際運作情形。每次造訪網址或重新整理網頁時,系統都會以 JSON 格式顯示最近五次造訪。

7. 恭喜

您已在 Cloud Run 上部署 Go 應用程式,該應用程式可以連線至在 Cloud SQL 上執行的 PostgreSQL 資料庫。

本文涵蓋的內容:

  • 建立 PostgreSQL 適用的 Cloud SQL 資料庫
  • 將 Go 應用程式部署至 Cloud Run
  • 使用 Go 連接器將應用程式連線至 Cloud SQL

清除所用資源

如要避免系統向您的 Google Cloud 帳戶收取本教學課程所用資源的費用,請刪除含有相關資源的專案,或者保留專案但刪除個別資源。如要刪除整個專案,可以執行下列指令:

gcloud projects delete ${GOOGLE_CLOUD_PROJECT}