Criar uma função do Cloud Run que retorna resultados do Spanner

Neste tutorial, mostramos como gravar uma função HTTP do Cloud Run que retorna resultados do Spanner.

Objetivos

Grave, implante e acione uma função HTTP que acesse o Spanner.

Custos

Este documento usa o Spanner e o Cloud Run, que são componentes faturáveis do Google Cloud.

  • Para mais informações sobre o custo do uso do Spanner, consulte os preços do Spanner.

  • Para informações sobre o custo do uso do Cloud Run, incluindo invocações sem custo financeiro, consulte Preços do Cloud Run.

Antes de começar

  1. Neste tópico, pressupomos que você tem uma instância do Spanner chamada test-instance e um banco de dados chamado example-db que usa o esquema do aplicativo de música. Para instruções sobre como criar uma instância e um banco de dados com o esquema do aplicativo de música, consulte o Guia de início rápido do uso do console ou os tutoriais de primeiros passos em Node.js ou Python.

  2. Ative as APIs Cloud Run e Cloud Build.

    Ativar as APIs

  3. Instale e inicialize a gcloud CLI.

    Se a gcloud CLI já estiver instalada, atualize-a executando o seguinte comando:

    gcloud components update
    
  4. Prepare seu ambiente de desenvolvimento:

Funções exigidas

Para receber as permissões necessárias para implantar os serviços do Cloud Run a partir da origem, peça ao administrador para conceder a você os seguintes papéis do IAM:

Para uma lista de papéis e permissões do IAM associados ao Cloud Run, consulte Papéis do IAM do Cloud Run e Permissões do IAM do Cloud Run. Se o serviço do Cloud Run interage com APIsGoogle Cloud , como as bibliotecas de cliente do Cloud, consulte o guia de configuração de identidade de serviço. Para mais informações sobre como conceder papéis, consulte permissões de implantação e gerenciar acesso.

Papéis da conta de serviço do Cloud Build

Você ou seu administrador precisa conceder à conta de serviço do Cloud Build o seguinte papel do IAM.

Clique para conferir os papéis necessários para a conta de serviço do Cloud Build

O Cloud Build usa automaticamente a conta de serviço padrão do Compute Engine como a conta de serviço padrão do Cloud Build para criar seu código-fonte e o recurso do Cloud Run, a menos que você substitua esse comportamento. Para que o Cloud Build crie suas origens, peça ao administrador para conceder o papel Criador do Cloud Run (roles/run.builder) à conta de serviço padrão do Compute Engine no seu projeto:

  gcloud projects add-iam-policy-binding PROJECT_ID \
      --member=serviceAccount:PROJECT_NUMBER-compute@developer.gserviceaccount.com \
      --role=roles/run.builder
  

Substitua PROJECT_NUMBER pelo número do projeto do Google Cloud e PROJECT_ID pelo ID do projeto do Google Cloud. Para instruções detalhadas sobre como encontrar o ID e o número do projeto, consulte Criar e gerenciar projetos.

A concessão do papel de builder do Cloud Run à conta de serviço padrão do Compute Engine leva alguns minutos para se propagar.

Papéis para a identidade de serviço

Você precisa conceder à identidade de serviço usada para o serviço do Cloud Run o seguinte papel do IAM.

  • Leitor de banco de dados do Spanner (roles/spanner.databaseReader)

Para mais informações sobre a concessão de papéis, consulte Gerenciar o acesso a projetos, pastas e organizações.

Preparar o aplicativo

  1. Clone o repositório do app de amostra na máquina local:

    Node.js

    git clone https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git

    Também é possível fazer o download do exemplo como um arquivo zip e extraí-lo.

    Python

    git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git

    Também é possível fazer o download do exemplo como um arquivo zip e extraí-lo.

  2. Mude para o diretório que contém o código de amostra das funções do Cloud Run para acessar o Spanner:

    Node.js

    cd nodejs-docs-samples/functions/spanner

    Python

    cd python-docs-samples/functions/spanner
  3. Confira o código de amostra:

    Node.js

    // Imports the Google Cloud client library
    const {Spanner} = require('@google-cloud/spanner');
    
    // Imports the functions framework to register your HTTP function
    const functions = require('@google-cloud/functions-framework');
    
    // Instantiates a client
    const spanner = new Spanner();
    
    // Your Cloud Spanner instance ID
    const instanceId = 'test-instance';
    
    // Your Cloud Spanner database ID
    const databaseId = 'example-db';
    
    /**
     * HTTP Cloud Function.
     *
     * @param {Object} req Cloud Function request context.
     * @param {Object} res Cloud Function response context.
     */
    functions.http('spannerQuickstart', async (req, res) => {
      // Gets a reference to a Cloud Spanner instance and database
      const instance = spanner.instance(instanceId);
      const database = instance.database(databaseId);
    
      // The query to execute
      const query = {
        sql: 'SELECT * FROM Albums',
      };
    
      // Execute the query
      try {
        const results = await database.run(query);
        const rows = results[0].map(row => row.toJSON());
        rows.forEach(row => {
          res.write(
            `SingerId: ${row.SingerId}, ` +
              `AlbumId: ${row.AlbumId}, ` +
              `AlbumTitle: ${row.AlbumTitle}\n`
          );
        });
        res.status(200).end();
      } catch (err) {
        res.status(500).send(`Error querying Spanner: ${err}`);
      }
    });

    Python

    import functions_framework
    from google.cloud import spanner
    
    instance_id = "test-instance"
    database_id = "example-db"
    
    client = spanner.Client()
    instance = client.instance(instance_id)
    database = instance.database(database_id)
    
    
    @functions_framework.http
    def spanner_read_data(request):
        query = "SELECT * FROM Albums"
    
        outputs = []
        with database.snapshot() as snapshot:
            results = snapshot.execute_sql(query)
    
            for row in results:
                output = "SingerId: {}, AlbumId: {}, AlbumTitle: {}".format(*row)
                outputs.append(output)
    
        return "\n".join(outputs)
    
    

    A função envia uma consulta SQL para buscar todos os dados de Albums do banco de dados. A função é executada quando você faz uma solicitação HTTP ao endpoint da função.

Implante a função

Para implantar a função com um gatilho HTTP, execute o seguinte comando no diretório spanner:

Node.js

gcloud run deploy nodejs-spanner-function \
    --source . \
    --region REGION \
    --function spannerQuickstart \
    --base-image RUNTIME_ID \
    --log-http

Python

gcloud run deploy python-spanner-function \
    --source . \
    --region REGION \
    --function spanner_read_data \
    --base-image RUNTIME_ID \
    --log-http

Substitua:

A implantação da função pode levar até dois minutos.

Observe o valor de url retornado quando a implantação da função for concluída. Você o usará ao acionar a função.

É possível ver as funções implantadas na página do Cloud Run no Google Cloud console. Nessa página, também é possível criar e editar funções, assim como obter detalhes e diagnósticos das suas funções.

Acionar a função

Faça uma solicitação HTTP à função:

curl URL

Substitua URL pelo valor do URL retornado quando a implantação da função for concluída.

Será exibida a saída que mostra os resultados da consulta SQL, supondo que você seguiu um tutorial de primeiros passos e preencheu o banco de dados:

SingerId: 2, AlbumId: 2, AlbumTitle: Forever Hold Your Peace
SingerId: 1, AlbumId: 2, AlbumTitle: Go, Go, Go
SingerId: 2, AlbumId: 1, AlbumTitle: Green
SingerId: 2, AlbumId: 3, AlbumTitle: Terrified
SingerId: 1, AlbumId: 1, AlbumTitle: Total Junk

Você também pode visitar o URL da função no seu navegador para ver o resultado da sua consulta SQL.

Limpar

Para evitar cobranças extras na sua conta do Google Cloud pelos recursos do Spanner e do Cloud Run functions usados neste documento:

  1. Exclua a instância:

    gcloud CLI instances delete test-instance
    
  2. Exclua o serviço do Cloud Run que você implantou neste tutorial:

    Node.js

    gcloud run services delete nodejs-spanner-function

    Python

    gcloud run services delete python-spanner-function

A seguir