Cloud Run'daki bir Go uygulamasını PostgreSQL için Cloud SQL veritabanına bağlama

1. Genel Bakış

Cloud SQL Go bağlayıcısı, Go uygulamanızı Cloud SQL veritabanınıza güvenli bir şekilde bağlamanın en kolay yoludur. Cloud Run, HTTP istekleriyle çağrılabilen durum bilgisiz container'lar çalıştırmanıza olanak tanıyan, tümüyle yönetilen bir sunucusuz platformdur. Bu Codelab'de, IAM kimlik doğrulamasını kullanarak bir hizmet hesabıyla Cloud Run'daki bir Go uygulamasını PostgreSQL İçin Cloud SQL veritabanına güvenli bir şekilde bağlama işlemi gösterilmektedir.

Öğrenecekleriniz

Bu laboratuvarda şunları yapmayı öğreneceksiniz:

  • PostgreSQL İçin Cloud SQL veritabanı oluşturma
  • Cloud Run'a Go uygulaması dağıtma
  • Go bağlayıcısını kullanarak uygulamanızı Cloud SQL'e bağlama

Ön koşullar

  • Bu laboratuvarda, Cloud Console ve Cloud Shell ortamlarına aşina olduğunuz varsayılır.

2. Başlamadan önce

Cloud projesi kurulumu

  1. Google Cloud Console'da oturum açın ve yeni bir proje oluşturun veya mevcut bir projeyi yeniden kullanın. Google Hesabınız yoksa hesap oluşturmanız gerekir.

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • Proje adı, bu projenin katılımcıları için görünen addır. Google API'leri tarafından kullanılmayan bir karakter dizesidir. Dilediğiniz zaman bunu güncelleyebilirsiniz.
  • Proje kimliği, tüm Google Cloud projelerinde benzersizdir ve sabittir (ayarlandıktan sonra değiştirilemez). Cloud Console, benzersiz bir dizeyi otomatik olarak oluşturur. Genellikle bu dizenin ne olduğuyla ilgilenmezsiniz. Çoğu codelab'de proje kimliğine (genellikle PROJECT_ID olarak tanımlanır) başvurmanız gerekir. Oluşturulan kimliği beğenmezseniz başka bir rastgele kimlik oluşturabilirsiniz. Dilerseniz kendi adınızı deneyerek kullanılabilir olup olmadığını kontrol edebilirsiniz. Bu adımdan sonra değiştirilemez ve proje süresince geçerli kalır.
  • Bazı API'lerin kullandığı üçüncü bir değer olan Proje Numarası da vardır. Bu üç değer hakkında daha fazla bilgiyi belgelerde bulabilirsiniz.
  1. Ardından, Cloud kaynaklarını/API'lerini kullanmak için Cloud Console'da faturalandırmayı etkinleştirmeniz gerekir. Bu codelab'i tamamlamak neredeyse hiç maliyetli değildir. Bu eğitimin ötesinde faturalandırma ücreti alınmaması için kaynakları kapatmak üzere oluşturduğunuz kaynakları veya projenin tamamını silebilirsiniz. Google Cloud'un yeni kullanıcıları 300 ABD doları değerinde ücretsiz deneme programından yararlanabilir.

Ortam Kurulumu

Arama çubuğunun sağındaki simgeyi tıklayarak Cloud Shell'i etkinleştirin.

ecdc43ada29e91b.png

Cloud Shell'den API'leri etkinleştirin:

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

Yetkilendirmeniz istenirse devam etmek için "Yetkilendir"i tıklayın.

6356559df3eccdda.png

Bu komutun tamamlanması birkaç dakika sürebilir ancak sonunda aşağıdakine benzer bir başarılı mesaj üretmesi gerekir:

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

3. Hizmet hesabı oluşturma

Cloud Run tarafından kullanılacak bir Google Cloud hizmet hesabı oluşturup yapılandırın. Bu hizmet hesabının Cloud SQL'e bağlanmak için doğru izinlere sahip olması gerekir.

  1. Yeni bir hizmet hesabı oluşturmak için gcloud iam service-accounts create komutunu aşağıdaki gibi çalıştırın:
    gcloud iam service-accounts create quickstart-service-account \
      --display-name="Quickstart Service Account"
    
  2. Yeni oluşturduğunuz Google Cloud hizmet hesabına Cloud SQL İstemcisi rolünü eklemek için gcloud projects add-iam-policy-binding komutunu aşağıdaki gibi çalıştırın. Cloud Shell'de ${GOOGLE_CLOUD_PROJECT} ifadesinin yerine projenizin adı yazılır. Dilerseniz bu işlemi manuel olarak da yapabilirsiniz.
    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. Yeni oluşturduğunuz Google Cloud hizmet hesabına Cloud SQL Örneği Kullanıcısı rolünü eklemek için gcloud projects add-iam-policy-binding komutunu aşağıdaki gibi çalıştırın.
    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. Yeni oluşturduğunuz Google Cloud hizmet hesabına Log Writer rolünü eklemek için gcloud projects add-iam-policy-binding komutunu aşağıdaki gibi çalıştırın.
    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'i ayarlama

Cloud SQL örneği oluşturmak için gcloud sql instances create komutunu çalıştırın.

  • –database-version: Veritabanı motoru türü ve sürümü. Belirtilmezse API varsayılanı kullanılır. Mevcut sürümleri görmek için gcloud veritabanı sürümleri dokümanlarına bakın.
  • –cpu: Makinede istenen çekirdek sayısı.
  • –memory: Makinede ne kadar bellek istendiğini gösteren tam sayı değeri. Bir boyut birimi sağlanmalıdır (örneğin, 3072 MB veya 9 GB). Bir birim belirtilmezse GB olduğu varsayılır.
  • –region: Örneğin bölgesel konumu (ör. us-central1, asia-east1, us-east1).
  • –database-flags: İşaretlerin ayarlanmasına izin verir. Bu durumda, daha önce oluşturduğumuz hizmet hesabını kullanarak Cloud Run'ın Cloud SQL'e bağlanmasını sağlamak için cloudsql.iam_authentication seçeneğini etkinleştiriyoruz.
    gcloud sql instances create quickstart-instance \
      --database-version=POSTGRES_14 \
      --cpu=1 \
      --memory=4GB \
      --region=us-central1 \
      --database-flags=cloudsql.iam_authentication=on
    

Bu komutun tamamlanması birkaç dakika sürebilir.

gcloud sql databases create komutunu çalıştırarak quickstart-instance içinde bir Cloud SQL veritabanı oluşturun.

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

Veritabanına erişmek için daha önce oluşturduğunuz hizmet hesabı için bir PostgreSQL veritabanı kullanıcısı oluşturun.

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

5. Uygulamayı hazırlama

HTTP isteklerine yanıt veren bir Go uygulaması hazırlayın.

  1. Cloud Shell'de helloworld adlı yeni bir dizin oluşturun ve bu dizine geçin:
    mkdir helloworld
    cd helloworld
    
  2. Yeni bir Go uygulaması başlatmak için go mod init komutunu çalıştırın.
    go mod init github.com/GoogleCloudPlatform/golang-samples/run/helloworld
    
  3. Cloud SQL Go Bağlayıcı bağımlılığını yükleyin.
    go get cloud.google.com/go/cloudsqlconn
    go get cloud.google.com/go/cloudsqlconn/postgres/pgxv4
    
  4. Uygulama koduyla bir main.go dosyası oluşturun. Bu kod şunları yapabilir:
    • HTTP isteklerini kabul etme
    • Veritabanına bağlanma
    • HTTP isteğinin zamanını veritabanında saklama
    • Son beş isteğin zamanlarını döndürür.
    Cloud Shell'de aşağıdaki komutu çalıştırın:
    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
    

Bu kod, PORT ortam değişkeninin tanımladığı bağlantı noktasında dinleme yapan temel bir web sunucusu oluşturur. Uygulama artık dağıtılmaya hazır.

6. Cloud Run uygulamasını dağıtma

Uygulamanızı dağıtmak için aşağıdaki komutu çalıştırın:

  • –region: Örneğin bölgesel konumu (ör. us-central1, asia-east1, us-east1).
  • –source: Dağıtılacak kaynak kodu. Bu durumda, ., geçerli klasördeki helloworld kaynak kodunu ifade eder.
  • –set-env-vars: Uygulamayı Cloud SQL veritabanına yönlendirmek için uygulama tarafından kullanılan ortam değişkenlerini ayarlar.
  • –service-account: Cloud Run dağıtımını, bu Codelab'in başında oluşturulan Cloud SQL veritabanına bağlanma izinlerine sahip hizmet hesabına bağlar.
  • –allow-unauthenticated: Kimliği doğrulanmamış isteklere izin vererek uygulamaya internetten erişilmesini sağlar.
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

İstenirse devam etmek istediğinizi onaylamak için y ve Enter tuşlarına basın:

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

Birkaç dakika sonra uygulama, ziyaret etmeniz için bir URL sağlar.

Uygulamanızı çalışırken görmek için URL'ye gidin. URL'yi her ziyaret ettiğinizde veya sayfayı her yenilediğinizde, en son beş ziyaret JSON olarak döndürülür.

7. Tebrikler

Cloud Run'da, Cloud SQL'de çalışan bir PostgreSQL veritabanına bağlanabilen bir Go uygulaması dağıtmış olmanız gerekir.

İşlediğimiz konular:

  • PostgreSQL İçin Cloud SQL veritabanı oluşturma
  • Cloud Run'a Go uygulaması dağıtma
  • Go bağlayıcısını kullanarak uygulamanızı Cloud SQL'e bağlama

Temizleme

Bu eğitimde kullanılan kaynaklar için Google Cloud hesabınızın ücretlendirilmesini önlemek amacıyla kaynakları içeren projeyi silin veya projeyi koruyup tek tek kaynakları silin. Projenin tamamını silmek isterseniz şu komutu çalıştırabilirsiniz:

gcloud projects delete ${GOOGLE_CLOUD_PROJECT}