Como conectar um aplicativo Go no Cloud Run a um banco de dados do Cloud SQL para PostgreSQL

1. Visão geral

O conector do Cloud SQL Go é a maneira mais fácil de conectar o aplicativo Go ao banco de dados do Cloud SQL com segurança. O Cloud Run é uma plataforma sem servidor totalmente gerenciada que permite executar contêineres sem estado que podem ser invocados usando solicitações HTTP. Este codelab vai demonstrar como conectar um aplicativo Go no Cloud Run a um banco de dados do Cloud SQL para PostgreSQL de forma segura com uma conta de serviço usando a autenticação do IAM.

O que você vai aprender

Você vai aprender a:

  • Criar um banco de dados do Cloud SQL para PostgreSQL
  • Implantar um aplicativo Go no Cloud Run
  • Conecte seu aplicativo ao Cloud SQL usando o Go Connector

Pré-requisitos

  • Para fazer este laboratório, é preciso ter familiaridade com o console do Cloud e os ambientes do Cloud Shell.

2. Antes de começar

Configuração do projeto do Google Cloud

  1. Faça login no Console do Google Cloud e crie um novo projeto ou reutilize um existente. Se você ainda não tiver uma Conta do Google, crie uma.

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • O Nome do projeto é o nome de exibição para os participantes do projeto. É uma string de caracteres não usada pelas APIs do Google Você pode atualizar a qualquer momento.
  • O ID do projeto precisa ser exclusivo em todos os projetos do Google Cloud e não pode ser mudado após a definição. O console do Cloud gera automaticamente uma string exclusiva. normalmente você não se importa com o que seja. Na maioria dos codelabs, é necessário fazer referência ao ID do projeto, que normalmente é identificado como PROJECT_ID. Se você não gostar do ID gerado, poderá gerar outro ID aleatório. Como alternativa, você pode tentar o seu próprio e ver se ele está disponível. Ela não pode ser alterada após essa etapa e permanecerá durante a duração do projeto.
  • Para sua informação, há um terceiro valor, um Número de projeto, que algumas APIs usam. Saiba mais sobre esses três valores na documentação.
  1. Em seguida, ative o faturamento no console do Cloud para usar os recursos/APIs do Cloud. A execução deste codelab não será muito cara, se tiver algum custo. Para encerrar os recursos e não gerar faturamento além deste tutorial, exclua os recursos criados ou exclua o projeto inteiro. Novos usuários do Google Cloud estão qualificados para o programa de US$ 300 de avaliação sem custos.

Configuração do ambiente

Ative o Cloud Shell clicando no ícone à direita da barra de pesquisa.

ecdc43ada29e91b.png

No Cloud Shell, ative as APIs:

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

Se for preciso autorizar, clique em "Autorizar" para continuar.

6356559df3eccdda.png

Esse comando pode levar alguns minutos para ser concluído, mas em algum momento ele vai produzir uma mensagem de sucesso parecida com esta:

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

3. Configurar uma conta de serviço

Criar e configurar uma conta de serviço do Google Cloud para ser usada pelo Cloud Run e ter as permissões corretas para se conectar ao Cloud SQL.

  1. Execute o comando gcloud iam service-accounts create da seguinte maneira para criar uma nova conta de serviço:
    gcloud iam service-accounts create quickstart-service-account \
      --display-name="Quickstart Service Account"
    
  2. Execute o comando gcloud projects add-iam-policy-binding da seguinte forma para adicionar o papel Cloud SQL Client à conta de serviço do Google Cloud que você acabou de criar. No Cloud Shell, a expressão ${GOOGLE_CLOUD_PROJECT} será substituída pelo nome do projeto. Também é possível fazer essa substituição manualmente, caso você se sinta mais confortável.
    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. Execute o comando gcloud projects add-iam-policy-binding da seguinte forma para adicionar o papel Usuário da instância do Cloud SQL à conta de serviço do Google Cloud que você acabou de criar.
    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. Execute o comando gcloud projects add-iam-policy-binding da seguinte maneira para adicionar o papel Gravador de registros à conta de serviço do Google Cloud que você acabou de criar.
    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. Configurar o Cloud SQL

Execute o comando gcloud sql instances create para criar uma instância do Cloud SQL.

  • –database-version: o tipo e a versão do mecanismo do banco de dados. Se não for especificado, a API padrão será usada. Consulte a documentação de versões do banco de dados gcloud para conferir as versões atuais disponíveis.
  • –cpu: o número desejado de núcleos na máquina.
  • –memory: valor numérico inteiro que indica a quantidade de memória desejada na máquina. É preciso fornecer uma unidade de tamanho (por exemplo, 3.072 MB ou 9 GB). Se nenhuma unidade for especificada, será usado o GB.
  • –region: local regional da instância (por exemplo: us-central1, asia-east1, us-east1).
  • –database-flags: permite configurar sinalizações. Neste caso, estamos ativando cloudsql.iam_authentication para permitir que o Cloud Run se conecte ao Cloud SQL usando a conta de serviço que criamos antes.
    gcloud sql instances create quickstart-instance \
      --database-version=POSTGRES_14 \
      --cpu=1 \
      --memory=4GB \
      --region=us-central1 \
      --database-flags=cloudsql.iam_authentication=on
    

Esse comando pode levar alguns minutos para ser concluído.

Execute o comando gcloud sql databases create para criar um banco de dados do Cloud SQL no quickstart-instance.

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

Para acessar o banco de dados, crie um usuário do banco de dados PostgreSQL para a conta de serviço criada anteriormente.

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

5. Preparar inscrição

Prepare um aplicativo Go que responda a solicitações HTTP.

  1. No Cloud Shell, crie um novo diretório chamado helloworld e mude para ele:
    mkdir helloworld
    cd helloworld
    
  2. Execute go mod init para inicializar um novo aplicativo Go.
    go mod init github.com/GoogleCloudPlatform/golang-samples/run/helloworld
    
  3. Instale a dependência do Cloud SQL Go Connector.
    go get cloud.google.com/go/cloudsqlconn
    go get cloud.google.com/go/cloudsqlconn/postgres/pgxv4
    
  4. Crie um arquivo main.go com o código do aplicativo. Esse código é capaz de:
    • Aceitar solicitações HTTP
    • Conecte-se ao banco de dados
    • Armazenar o horário da solicitação HTTP no banco de dados
    • Retorna os tempos das últimas cinco solicitações
    . Execute este comando no 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
    

Esse código cria um servidor da Web básico que detecta na porta definida pela variável de ambiente PORT. Agora o aplicativo está pronto para ser implantado.

6. Implantar o aplicativo do Cloud Run

Execute o comando abaixo para implantar o aplicativo:

  • –region: local regional da instância (por exemplo: us-central1, asia-east1, us-east1).
  • –source: o código-fonte a ser implantado. Nesse caso, . se refere ao código-fonte na pasta atual helloworld.
  • –set-env-vars: define variáveis de ambiente usadas pelo aplicativo para direcioná-lo ao banco de dados do Cloud SQL.
  • –service-account: vincula a implantação do Cloud Run à conta de serviço com permissões para se conectar ao banco de dados do Cloud SQL criado no início deste codelab.
  • –allow-unauthenticated: permite solicitações não autenticadas para que o aplicativo fique acessível pela 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

Se solicitado, pressione y e Enter para confirmar que você quer continuar:

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

Depois de alguns minutos, o aplicativo fornecerá um URL para você acessar.

Navegue até o URL para ver seu aplicativo em ação. Sempre que você acessar o URL ou atualizar a página, as cinco visitas mais recentes serão retornadas como JSON.

7. Parabéns

Você implantou um aplicativo Go no Cloud Run capaz de se conectar a um banco de dados PostgreSQL em execução no Cloud SQL.

O que aprendemos:

  • Como criar um banco de dados do Cloud SQL para PostgreSQL
  • Como implantar um aplicativo Go no Cloud Run
  • Como conectar seu aplicativo ao Cloud SQL usando o Go Connector

Limpar

Para evitar cobranças na sua conta do Google Cloud pelos recursos usados no tutorial, exclua o projeto ou mantenha o projeto e exclua cada um dos recursos. Se quiser excluir o projeto inteiro, execute:

gcloud projects delete ${GOOGLE_CLOUD_PROJECT}