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 para Go é a maneira mais fácil de conectar seu 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 por solicitações HTTP. Este codelab demonstra como conectar um aplicativo Go no Cloud Run a um banco de dados do Cloud SQL para PostgreSQL com segurança usando uma conta de serviço com a autenticação do IAM.

O que você vai aprender

Neste laboratório, você vai aprender a:

  • Criar um banco de dados do Cloud SQL para PostgreSQL
  • Implantar um aplicativo Go no Cloud Run
  • Conectar o aplicativo ao Cloud SQL usando o conector do Go

Pré-requisitos

  • Para fazer este laboratório, é preciso saber usar o console do Cloud e os ambientes do Cloud Shell.

2. Antes de começar

Configuração do projeto do Cloud

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

b35bf95b8bf3d5d8.pnga99b7ace416376c4.pngbd84a6d3004737c5.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 É possível atualizar o local 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. Em geral, não importa o que seja. Na maioria dos codelabs, é necessário fazer referência ao ID do projeto, normalmente identificado como PROJECT_ID. Se você não gostar do ID gerado, crie outro aleatório. Se preferir, teste o seu e confira se ele está disponível. Ele não pode ser mudado após essa etapa e permanece durante o projeto.
  • Para sua informação, há um terceiro valor, um Número do 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 desligar os recursos e evitar cobranças além deste tutorial, exclua os recursos criados ou 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

Clique no ícone à direita da barra de pesquisa para ativar o Cloud Shell.

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 vai gerar uma mensagem de sucesso semelhante a esta:

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

3. Configurar uma conta de serviço

Crie e configure uma conta de serviço do Google Cloud para ser usada pelo Cloud Run, de modo que ela tenha 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 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 maneira para adicionar o papel Cliente do Cloud SQL à 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 seu projeto. Você também pode fazer essa substituição manualmente se preferir.
    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 maneira 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 de banco de dados. Se não for especificado, a API padrão será usada. Consulte a documentação das versões de banco de dados do gcloud para ver as versões atuais disponíveis.
  • –cpu: o número de núcleos desejados na máquina.
  • –memory: valor inteiro que indica a quantidade de memória desejada na máquina. Uma unidade de tamanho precisa ser fornecida (por exemplo, 3.072 MB ou 9 GB). Se nenhuma unidade for especificada, GB será usado.
  • –region: local regional da instância (por exemplo, us-central1, asia-east1, us-east1).
  • –database-flags: permite definir flags. Nesse caso, estamos ativando cloudsql.iam_authentication para permitir que o Cloud Run se conecte ao Cloud SQL usando a conta de serviço criada anteriormente.
    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 em quickstart-instance.

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

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

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 conector do Cloud SQL para Go.
    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 pode:
    • Aceitar solicitações HTTP
    • Conecte-se ao banco de dados
    • Armazenar o horário da solicitação HTTP no banco de dados
    • Retornar os horários dos últimos cinco pedidos
    Execute o comando a seguir 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. O aplicativo está pronto para ser implantado.

6. Implantar 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 possa ser acessado na 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 vai fornecer um URL para você acessar.

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

7. Parabéns

Você implantou um aplicativo Go no Cloud Run que pode 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 conector Go

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 todo o projeto, execute:

gcloud projects delete ${GOOGLE_CLOUD_PROJECT}