Jak połączyć aplikację w języku Go w Cloud Run z bazą danych Cloud SQL for PostgreSQL

1. Przegląd

Oprogramowanie sprzęgające Cloud SQL Go to najprostszy sposób bezpiecznego łączenia aplikacji Go z bazą danych Cloud SQL. Cloud Run to w pełni zarządzana platforma bezserwerowa, która umożliwia uruchamianie bezstanowych kontenerów wywoływanych przez żądania HTTP. To ćwiczenie pokazuje, jak bezpiecznie połączyć aplikację Go w Cloud Run z bazą danych Cloud SQL for PostgreSQL za pomocą konta usługi z uwierzytelnianiem IAM.

Czego się nauczysz

W tym module nauczysz się:

  • Tworzenie bazy danych Cloud SQL for PostgreSQL
  • Wdrażanie aplikacji w Go w Cloud Run
  • Łączenie aplikacji z Cloud SQL za pomocą oprogramowania sprzęgającego Go

Wymagania wstępne

  • Zakładamy, że użytkownik zna środowiska konsoli Cloud i Cloud Shell.

2. Zanim zaczniesz

Konfigurowanie projektu Cloud

  1. Zaloguj się w konsoli Google Cloud i utwórz nowy projekt lub użyj istniejącego. Jeśli nie masz jeszcze konta Google, musisz je utworzyć.

b35bf95b8bf3d5d8.pnga99b7ace416376c4.pngbd84a6d3004737c5.png

  • Nazwa projektu to wyświetlana nazwa dla uczestników tego projektu. Jest to ciąg znaków, który nie jest używany przez interfejsy API Google. Możesz ją zaktualizować w dowolnym momencie.
  • Identyfikator projektu jest unikalny we wszystkich projektach Google Cloud i nie można go zmienić po ustawieniu. Konsola Cloud automatycznie generuje unikalny ciąg znaków. Zwykle nie musisz się nim przejmować. W większości przewodników programowania musisz odwoływać się do identyfikatora projektu (zwykle jest on oznaczony jako PROJECT_ID). Jeśli wygenerowany identyfikator Ci się nie podoba, możesz wygenerować inny losowy identyfikator. Możesz też spróbować utworzyć własny adres i sprawdzić, czy jest dostępny. Po tym kroku nie można go zmienić i będzie obowiązywać przez cały czas trwania projektu.
  • Warto wiedzieć, że istnieje trzecia wartość, numer projektu, której używają niektóre interfejsy API. Więcej informacji o tych 3 wartościach znajdziesz w dokumentacji.
  1. Następnie musisz włączyć płatności w konsoli Cloud, aby korzystać z zasobów i interfejsów API Google Cloud. Ukończenie tego laboratorium nie powinno wiązać się z dużymi kosztami, a nawet z żadnymi. Aby wyłączyć zasoby i uniknąć naliczania opłat po zakończeniu tego samouczka, możesz usunąć utworzone zasoby lub cały projekt. Nowi użytkownicy Google Cloud mogą skorzystać z programu bezpłatnego okresu próbnego, w którym mają do dyspozycji środki w wysokości 300 USD.

Konfiguracja środowiska

Aktywuj Cloud Shell, klikając ikonę po prawej stronie paska wyszukiwania.

ecdc43ada29e91b.png

Włącz interfejsy API w Cloud Shell:

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

Jeśli pojawi się prośba o autoryzację, kliknij „Autoryzuj”, aby kontynuować.

6356559df3eccdda.png

Wykonanie tego polecenia może potrwać kilka minut, ale powinno ostatecznie wyświetlić komunikat o sukcesie podobny do tego:

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

3. Konfigurowanie konta usługi

Utwórz i skonfiguruj konto usługi Google Cloud, które będzie używane przez Cloud Run, aby miało odpowiednie uprawnienia do łączenia się z Cloud SQL.

  1. Aby utworzyć nowe konto usługi, uruchom polecenie gcloud iam service-accounts create w ten sposób:
    gcloud iam service-accounts create quickstart-service-account \
      --display-name="Quickstart Service Account"
    
  2. Aby dodać do utworzonego właśnie konta usługi Google Cloud rolę Klient Cloud SQL, uruchom polecenie gcloud projects add-iam-policy-binding w ten sposób: W Cloud Shell wyrażenie ${GOOGLE_CLOUD_PROJECT} zostanie zastąpione nazwą Twojego projektu. Możesz też dokonać tej zamiany ręcznie, jeśli wolisz.
    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. Aby dodać do utworzonego właśnie konta usługi Google Cloud rolę Użytkownik instancji Cloud SQL, uruchom to polecenie gcloud projects add-iam-policy-binding:
    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. Aby dodać rolę Zapisujący dzienniki do utworzonego przed chwilą konta usługi Google Cloud, uruchom polecenie gcloud projects add-iam-policy-binding w ten sposób:
    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. Konfigurowanie Cloud SQL

Uruchom polecenie gcloud sql instances create, aby utworzyć instancję Cloud SQL.

  • –database-version: typ i wersja silnika bazy danych. Jeśli nie zostanie określony, używana będzie wartość domyślna interfejsu API. Aktualnie dostępne wersje znajdziesz w dokumentacji gcloud dotyczącej wersji bazy danych.
  • –cpu: pożądana liczba rdzeni na maszynie.
  • –memory: liczba całkowita wskazująca ilość pamięci, która ma być dostępna na maszynie. Należy podać jednostkę rozmiaru (np. 3072 MB lub 9 GB). Jeśli nie podasz jednostek, przyjmuje się GB.
  • –region: regionalna lokalizacja instancji (np. us-central1, asia-east1, us-east1).
  • –database-flags: umożliwia ustawianie flag. W tym przypadku włączamy cloudsql.iam_authentication, aby umożliwić Cloud Run łączenie się z Cloud SQL za pomocą utworzonego wcześniej konta usługi.
    gcloud sql instances create quickstart-instance \
      --database-version=POSTGRES_14 \
      --cpu=1 \
      --memory=4GB \
      --region=us-central1 \
      --database-flags=cloudsql.iam_authentication=on
    

Wykonanie tego polecenia może potrwać kilka minut.

Uruchom polecenie gcloud sql databases create, aby utworzyć bazę danych Cloud SQL w quickstart-instance.

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

Utwórz użytkownika bazy danych PostgreSQL dla utworzonego wcześniej konta usługi, aby uzyskać dostęp do bazy danych.

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

5. Przygotowywanie aplikacji

Przygotuj aplikację w Go, która odpowiada na żądania HTTP.

  1. W Cloud Shell utwórz nowy katalog o nazwie helloworld, a następnie przejdź do niego:
    mkdir helloworld
    cd helloworld
    
  2. Uruchom go mod init, aby zainicjować nową aplikację w języku Go.
    go mod init github.com/GoogleCloudPlatform/golang-samples/run/helloworld
    
  3. Zainstaluj zależność Cloud SQL Go Connector.
    go get cloud.google.com/go/cloudsqlconn
    go get cloud.google.com/go/cloudsqlconn/postgres/pgxv4
    
  4. Utwórz plik main.go z kodem aplikacji. Ten kod może:
    • Akceptowanie żądań HTTP
    • Łączenie z bazą danych
    • Zapisywanie czasu żądania HTTP w bazie danych
    • Zwraca czasy ostatnich 5 żądań
    Uruchom to polecenie w 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
    

Ten kod tworzy podstawowy serwer WWW, który nasłuchuje na porcie określonym przez zmienną środowiskową PORT. Aplikacja jest teraz gotowa do wdrożenia.

6. Wdrażanie aplikacji Cloud Run

Aby wdrożyć aplikację, uruchom to polecenie:

  • –region: regionalna lokalizacja instancji (np. us-central1, asia-east1, us-east1).
  • –source: kod źródłowy do wdrożenia. W tym przypadku . odnosi się do kodu źródłowego w bieżącym folderze helloworld.
  • –set-env-vars: ustawia zmienne środowiskowe używane przez aplikację do kierowania jej do bazy danych Cloud SQL.
  • –service-account: łączy wdrożenie Cloud Run z kontem usługi z uprawnieniami do łączenia się z bazą danych Cloud SQL utworzoną na początku tego Codelabu.
  • –allow-unauthenticated: zezwala na nieuwierzytelnione żądania, dzięki czemu aplikacja jest dostępna w internecie.
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

Jeśli pojawi się taka prośba, naciśnij yEnter, aby potwierdzić, że chcesz kontynuować:

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

Po kilku minutach aplikacja powinna podać adres URL, który możesz otworzyć.

Otwórz adres URL, aby zobaczyć działanie aplikacji. Za każdym razem, gdy otworzysz adres URL lub odświeżysz stronę, zobaczysz 5 ostatnich wizyt zwróconych w formacie JSON.

7. Gratulacje

Aplikacja Go została wdrożona w Cloud Run i może łączyć się z bazą danych PostgreSQL działającą w Cloud SQL.

Omówione zagadnienia:

  • Tworzenie bazy danych Cloud SQL for PostgreSQL
  • Wdrażanie aplikacji w Go w Cloud Run
  • Łączenie aplikacji z Cloud SQL za pomocą oprogramowania sprzęgającego Go

Czyszczenie danych

Aby uniknąć obciążenia konta Google Cloud opłatami za zasoby zużyte w tym samouczku, możesz usunąć projekt zawierający te zasoby lub zachować projekt i usunąć poszczególne zasoby. Jeśli chcesz usunąć cały projekt, możesz uruchomić to polecenie:

gcloud projects delete ${GOOGLE_CLOUD_PROJECT}