Connecter une application Go sur Cloud Run à une base de données Cloud SQL pour PostgreSQL

1. Présentation

Le connecteur Cloud SQL Go est le moyen le plus simple de connecter de manière sécurisée votre application Go à votre base de données Cloud SQL. Cloud Run est une plate-forme sans serveur entièrement gérée qui vous permet d'exécuter des conteneurs sans état pouvant être appelés via des requêtes HTTP. Cet atelier de programmation vous montrera comment connecter une application Go sur Cloud Run à une base de données Cloud SQL pour PostgreSQL de manière sécurisée avec un compte de service utilisant l'authentification IAM.

Objectifs de l'atelier

Dans cet atelier, vous allez apprendre à effectuer les tâches suivantes :

  • Créer une base de données Cloud SQL pour PostgreSQL
  • Déployer une application Go sur Cloud Run
  • Connecter votre application à Cloud SQL à l'aide du connecteur Go

Prérequis

  • Dans cet atelier, nous considérons que vous connaissez la console Cloud et les environnements Cloud Shell.

2. Avant de commencer

Configuration du projet Cloud

  1. Connectez-vous à la console Google Cloud, puis créez un projet ou réutilisez un projet existant. Si vous ne possédez pas encore de compte Google, vous devez en créer un.

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • Le nom du projet est le nom à afficher pour les participants au projet. Il s'agit d'une chaîne de caractères non utilisée par les API Google. Vous pouvez le modifier à tout moment.
  • L'ID du projet est unique parmi tous les projets Google Cloud et non modifiable une fois défini. La console Cloud génère automatiquement une chaîne unique (en général, vous n'y accordez d'importance particulière). Dans la plupart des ateliers de programmation, vous devrez indiquer l'ID du projet (généralement identifié par PROJECT_ID). Si l'ID généré ne vous convient pas, vous pouvez en générer un autre de manière aléatoire. Vous pouvez également en spécifier un et voir s'il est disponible. Après cette étape, l'ID n'est plus modifiable et restera donc le même pour toute la durée du projet.
  • Pour information, il existe une troisième valeur (le numéro de projet) que certaines API utilisent. Pour en savoir plus sur ces trois valeurs, consultez la documentation.
  1. Vous devez ensuite activer la facturation dans la console Cloud pour utiliser les ressources/API Cloud. L'exécution de cet atelier de programmation est très peu coûteuse, voire sans frais. Pour désactiver les ressources et éviter ainsi que des frais ne vous soient facturés après ce tutoriel, vous pouvez supprimer le projet ou les ressources que vous avez créées. Les nouveaux utilisateurs de Google Cloud peuvent participer au programme d'essai sans frais pour bénéficier d'un crédit de 300$.

Configuration de l'environnement

Activez Cloud Shell en cliquant sur l'icône à droite de la barre de recherche.

ecdc43ada29e91b.png

Dans Cloud Shell, activez les API :

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

Si vous êtes invité à donner votre autorisation, cliquez sur "Autoriser" pour continuer.

6356559df3eccdda.png

L'exécution de cette commande peut prendre quelques minutes, mais un message semblable à celui qui suit devrait s'afficher pour vous indiquer que l'opération s'est correctement déroulée :

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

3. Configurer un compte de service

Créez et configurez un compte de service Google Cloud pour Cloud Run afin qu'il dispose des autorisations nécessaires pour se connecter à Cloud SQL.

  1. Exécutez la commande gcloud iam service-accounts create comme suit pour créer un compte de service :
    gcloud iam service-accounts create quickstart-service-account \
      --display-name="Quickstart Service Account"
    
  2. Exécutez la commande gcloud projects add-iam-policy-binding comme suit pour ajouter le rôle Client Cloud SQL au compte de service Google Cloud que vous venez de créer. Dans Cloud Shell, l'expression ${GOOGLE_CLOUD_PROJECT} sera remplacée par le nom de votre projet. Vous pouvez également effectuer ce remplacement manuellement si vous le souhaitez.
    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. Exécutez la commande gcloud projects add-iam-policy-binding comme suit pour ajouter le rôle Utilisateur de l'instance Cloud SQL au compte de service Google Cloud que vous venez de créer.
    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. Exécutez la commande gcloud projects add-iam-policy-binding comme suit pour ajouter le rôle Rédacteur de journal au compte de service Google Cloud que vous venez de créer.
    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. Configurer Cloud SQL

Exécutez la commande gcloud sql instances create pour créer une instance Cloud SQL.

  • --database-version : type et version du moteur de base de données. Si aucune valeur n'est spécifiée, la valeur par défaut de l'API est utilisée. Consultez la documentation sur les versions de base de données gcloud pour afficher les versions actuellement disponibles.
  • --cpu : nombre de cœurs souhaités dans la machine.
  • –memory : nombre entier indiquant la quantité de mémoire souhaitée sur la machine. Une unité de taille doit être fournie (par exemple, 3072 Mo ou 9 Go). Si aucune unité n'est spécifiée, la valeur par défaut est Go.
  • –region : emplacement régional de l'instance (par exemple, us-central1, asia-east1, us-east1).
  • --database-flags : permet de définir des indicateurs. Dans ce cas, nous activons cloudsql.iam_authentication pour permettre à Cloud Run de se connecter à Cloud SQL à l'aide du compte de service que nous avons créé précédemment.
    gcloud sql instances create quickstart-instance \
      --database-version=POSTGRES_14 \
      --cpu=1 \
      --memory=4GB \
      --region=us-central1 \
      --database-flags=cloudsql.iam_authentication=on
    

L'exécution de cette commande peut prendre quelques minutes.

Exécutez la commande gcloud sql databases create pour créer une base de données Cloud SQL dans quickstart-instance.

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

Créez un utilisateur de base de données PostgreSQL pour que le compte de service que vous avez créé précédemment puisse accéder à la base de données.

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

5. Préparer l'application

Préparez une application Go qui répond aux requêtes HTTP.

  1. Dans Cloud Shell, créez un répertoire nommé helloworld, puis accédez-y :
    mkdir helloworld
    cd helloworld
    
  2. Exécutez go mod init pour initialiser une application Go.
    go mod init github.com/GoogleCloudPlatform/golang-samples/run/helloworld
    
  3. Installez la dépendance du connecteur Go Cloud SQL.
    go get cloud.google.com/go/cloudsqlconn
    go get cloud.google.com/go/cloudsqlconn/postgres/pgxv4
    
  4. Créez un fichier main.go avec le code de l'application. Ce code est capable de :
    • Accepter les requêtes HTTP
    • Se connecter à la base de données
    • Stocker l'heure de la requête HTTP dans la base de données
    • Renvoie les heures des cinq dernières requêtes
    Exécutez la commande suivante dans 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
    

Ce code crée un serveur Web de base qui écoute le port défini par la variable d'environnement PORT. L'application est maintenant prête à être déployée.

6. Déployer l'application Cloud Run

Exécutez la commande ci-dessous pour déployer votre application :

  • –region : emplacement régional de l'instance (par exemple, us-central1, asia-east1, us-east1).
  • –source : code source à déployer. Dans ce cas, . fait référence au code source du dossier actuel helloworld.
  • –set-env-vars : définit les variables d'environnement utilisées par l'application pour la diriger vers la base de données Cloud SQL.
  • --service-account : associe le déploiement Cloud Run au compte de service disposant des autorisations nécessaires pour se connecter à la base de données Cloud SQL créée au début de cet atelier de programmation.
  • --allow-unauthenticated : autorise les requêtes non authentifiées afin que l'application soit accessible depuis Internet.
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

Si vous y êtes invité, appuyez sur y et Enter pour confirmer que vous souhaitez continuer :

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

Après quelques minutes, l'application devrait vous fournir une URL à consulter.

Accédez à l'URL pour voir votre application en action. Chaque fois que vous accédez à l'URL ou que vous actualisez la page, les cinq visites les plus récentes sont renvoyées au format JSON.

7. Félicitations

Vous avez déployé une application Go sur Cloud Run, qui peut se connecter à une base de données PostgreSQL exécutée sur Cloud SQL.

Points abordés

  • Créer une base de données Cloud SQL pour PostgreSQL
  • Déployer une application Go sur Cloud Run
  • Connecter votre application à Cloud SQL à l'aide du connecteur Go

Effectuer un nettoyage

Pour éviter que les ressources utilisées lors de ce tutoriel soient facturées sur votre compte Google Cloud, supprimez le projet contenant les ressources, ou conservez le projet et supprimez chaque ressource individuellement. Si vous souhaitez supprimer l'intégralité du projet, vous pouvez exécuter la commande suivante :

gcloud projects delete ${GOOGLE_CLOUD_PROJECT}