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ızı sağlayan, tümüyle yönetilen, sunucusuz bir platformdur. Bu Codelab, Cloud Run'daki bir Go uygulamasını PostgreSQL için Cloud SQL veritabanına IAM Kimlik Doğrulaması kullanarak bir hizmet hesabıyla güvenli şekilde nasıl bağlayacağınızı gösterir.

Öğrenecekleriniz

Bu laboratuvarda aşağıdakileri nasıl yapacağınızı öğreneceksiniz:

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

Ön koşullar

  • Bu laboratuvarda, Cloud Console ve Cloud Shell ortamlarıyla ilgili bilgi sahibi olmanız gerekir.

2. Başlamadan önce

Cloud projesi kurulumu

  1. Google Cloud Console'da oturum açıp yeni bir proje oluşturun veya mevcut bir projeyi yeniden kullanın. Henüz 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. İstediğiniz zaman güncelleyebilirsiniz.
  • Proje Kimliği, tüm Google Cloud projelerinde benzersizdir ve değiştirilemez (belirlendikten sonra değiştirilemez). Cloud Console, otomatik olarak benzersiz bir dize oluşturur. bunun ne olduğunu umursamıyorsunuz. Çoğu codelab'de proje kimliğini (genellikle PROJECT_ID olarak tanımlanır) referans almanız gerekir. Oluşturulan kimliği beğenmezseniz rastgele bir kimlik daha oluşturabilirsiniz. Alternatif olarak, kendi ölçümünüzü deneyip mevcut olup olmadığına bakabilirsiniz. Bu adımdan sonra değiştirilemez ve proje süresince kalır.
  • Bilginiz için bazı API'lerin kullandığı üçüncü bir değer, yani Proje Numarası daha vardır. Bu değerlerin üçü hakkında daha fazla bilgiyi belgelerde bulabilirsiniz.
  1. Sonraki adımda, Cloud kaynaklarını/API'lerini kullanmak için Cloud Console'da faturalandırmayı etkinleştirmeniz gerekir. Bu codelab'i çalıştırmanın maliyeti, yüksek değildir. Bu eğitim dışında faturalandırma yapılmaması için kaynakları kapatmak isterseniz oluşturduğunuz kaynakları silebilir veya projenin tamamını silebilirsiniz. Yeni Google Cloud kullanıcıları, 300 ABD doları değerindeki ücretsiz denemeden 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

Yetki vermeniz istenirse "Yetkilendir"i tıklayın seçeneğini tıklayın.

6356559df3eccdda.png

Bu komutun tamamlanması birkaç dakika sürebilir ancak sonunda şuna benzer başarılı bir mesaj oluşturacaktır:

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

3. Hizmet Hesabı oluşturun

Cloud Run tarafından kullanılacak bir Google Cloud hizmet hesabı oluşturup yapılandırın. Bu hesap, Cloud SQL'e bağlanmak için gerekli izinlere sahip olmalıdır.

  1. Yeni bir hizmet hesabı oluşturmak için gcloud iam service-accounts create komutunu şu şekilde çalıştırın:
    gcloud iam service-accounts create quickstart-service-account \
      --display-name="Quickstart Service Account"
    
  2. Cloud SQL İstemcisi rolünü, yeni oluşturduğunuz Google Cloud hizmet hesabına eklemek için gcloud projects add-iam-policy-binding komutunu aşağıdaki gibi çalıştırın. Cloud Shell'de ${GOOGLE_CLOUD_PROJECT} ifadesi projenizin adıyla değiştirilir. Daha rahat hissediyorsanız bu değişikliği 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. Cloud SQL Örneği Kullanıcısı rolünü, yeni oluşturduğunuz Google Cloud hizmet hesabına 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. Log Writer rolünü, az önce oluşturduğunuz Google Cloud hizmet hesabına 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 kurun

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ü. Belirtilmemişse varsayılan API kullanılır. Mevcut sürümleri görmek için gcloud veritabanı sürümleri belgelerine bakın.
  • –cpu: Makinede istenen çekirdek sayısı.
  • -bellek: Makinede ne kadar bellek istendiğini gösteren tam sayı değeridir. Bir boyut birimi sağlanmalıdır (örneğin, 3072 MB veya 9 GB). Birim belirtilmezse GB olarak kabul edilir.
  • –region: Örneğin, bölgesel konumu (ör. us-central1, asia-east1, us-east1).
  • –database-flags: İşaretlerin ayarlanmasına olanak tanır. Bu durumda, Cloud Run'ın daha önce oluşturduğumuz hizmet hesabını kullanarak Cloud SQL'e bağlanmasını sağlamak için cloudsql.iam_authentication hizmetini 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.

quickstart-instance içinde Cloud SQL veritabanı oluşturmak için gcloud sql databases create komutunu çalıştırın.

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

Veritabanına erişmek amacıyla, 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. Başvuruyu Hazırla

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

  1. Cloud Shell'de helloworld adında yeni bir dizin oluşturun ve bu dizinde değişiklik yapın:
    mkdir helloworld
    cd helloworld
    
  2. Yeni bir Go uygulamasını 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ısı bağımlılığını yükleyin.
    go get cloud.google.com/go/cloudsqlconn
    go get cloud.google.com/go/cloudsqlconn/postgres/pgxv4
    
  4. Uygulama kodunu içeren bir main.go dosyası oluşturun. Bu kodla:
    • HTTP isteklerini kabul et
    • Veritabanına bağlanın
    • HTTP isteğinin zamanını veritabanında depolama
    • Son beş isteğin zamanlarını döndürür
    ziyaret edin. 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şkeni tarafından tanımlanan 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 ., mevcut helloworld klasöründeki kaynak koduna başvurur.
  • –set-env-vars: Uygulamanın Cloud SQL veritabanına yönlendirilmesi için kullandığı 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 olan hizmet hesabına bağlar.
  • –allow-unauthenticated: Uygulamaya internetten erişilebilmesi için kimliği doğrulanmamış isteklere izin verir.
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 uygulamanın, ziyaret etmeniz için bir URL sağlaması gerekir.

Uygulamanızın nasıl çalıştığını görmek için URL'ye gidin. URL'yi her ziyaret ettiğinizde veya sayfayı her yenilediğinizde, JSON biçiminde döndürülen son beş ziyareti görürsünüz.

7. Tebrikler

Cloud SQL'de çalışan PostgreSQL veritabanına bağlanabilen bir Go uygulamasını Cloud Run'a dağıttınız.

İşlediğimiz konular:

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

Temizleme

Bu eğiticide kullanılan kaynaklar için Google Cloud hesabınızın ücretlendirilmesini istemiyorsanız kaynakları içeren projeyi silin veya projeyi tutup tek tek kaynakları silin. Projeyi tamamen silmek istiyorsanız aşağıdaki komutu çalıştırabilirsiniz:

gcloud projects delete ${GOOGLE_CLOUD_PROJECT}