Cloud Bigtable と Cloud Functions の併用

目標

Cloud Bigtable にアクセスする HTTP Cloud Function の関数を作成、デプロイ、トリガーします。

費用

このトピックでは、Google Cloud の課金対象コンポーネントである Cloud Bigtable と Cloud Functions を使用します。

始める前に

  1. このトピックでは、test-instance という名前の Cloud Bigtable インスタンスと test-table という名前のテーブルがあることを前提としています。これらのリソースは、テストテーブルの作成の手順で作成できます。不要なコストの発生を避けるため、作業の終了後すぐにリソースを削除してください。

  2. Cloud Functions API を有効にします。

    API の有効化

  3. Cloud SDK をインストールし、初期化します

    Cloud SDK がすでにインストールされている場合は、次のコマンドを実行して更新します。

    gcloud components update
    
  4. 開発環境を準備します。

アプリケーションを準備する

  1. ローカルマシンにサンプルアプリのリポジトリのクローンを作成します。

    Node.js

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

    または、zip 形式のサンプルをダウンロードし、ファイルを抽出してもかまいません。

    Python

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

    または、zip 形式のサンプルをダウンロードし、ファイルを抽出してもかまいません。

    Go

    git clone https://github.com/GoogleCloudPlatform/golang-samples.git

    または、zip 形式のサンプルをダウンロードし、ファイルを抽出してもかまいません。

  2. Cloud Bigtable にアクセスするための Cloud Functions サンプルコードがあるディレクトリに移動します。

    Node.js

    cd nodejs-docs-samples/functions/bigtable/

    Python

    cd python-docs-samples/functions/bigtable/

    Go

    cd golang-samples/functions/bigtable/
  3. サンプルコードを見てみましょう。

    Node.js

    // Imports the Google Cloud client library
    const {Bigtable} = require('@google-cloud/bigtable');
    
    // Instantiates a client
    const bigtable = new Bigtable();
    
    exports.readRows = async (req, res) => {
      // Gets a reference to a Cloud Bigtable instance and database
      const instance = bigtable.instance(req.body.instanceId);
      const table = instance.table(req.body.tableId);
    
      // Execute the query
      try {
        const prefix = 'phone#';
        const rows = [];
        await table
          .createReadStream({
            prefix,
          })
          .on('error', err => {
            res.send(`Error querying Bigtable: ${err}`);
            res.status(500).end();
          })
          .on('data', row => {
            rows.push(
              `rowkey: ${row.id}, ` +
                `os_build: ${row.data['stats_summary']['os_build'][0].value}\n`
            );
          })
          .on('end', () => {
            rows.forEach(r => res.write(r));
            res.status(200).end();
          });
      } catch (err) {
        res.send(`Error querying Bigtable: ${err}`);
        res.status(500).end();
      }
    };
    

    Python

    from google.cloud import bigtable
    from google.cloud.bigtable.row_set import RowSet
    
    client = bigtable.Client()
    
    def bigtable_read_data(request):
        instance = client.instance(request.headers.get("instance_id"))
        table = instance.table(request.headers.get("table_id"))
    
        prefix = 'phone#'
        end_key = prefix[:-1] + chr(ord(prefix[-1]) + 1)
    
        outputs = []
        row_set = RowSet()
        row_set.add_row_range_from_keys(prefix.encode("utf-8"),
                                        end_key.encode("utf-8"))
    
        rows = table.read_rows(row_set=row_set)
        for row in rows:
            output = 'Rowkey: {}, os_build: {}'.format(
                row.row_key.decode('utf-8'),
                row.cells["stats_summary"]["os_build".encode('utf-8')][0]
                .value.decode('utf-8'))
            outputs.append(output)
    
        return '\n'.join(outputs)
    

    Go

    
    // Package bigtable contains an example of using Bigtable from a Cloud Function.
    package bigtable
    
    import (
    	"context"
    	"fmt"
    	"log"
    	"net/http"
    	"sync"
    
    	"cloud.google.com/go/bigtable"
    )
    
    // client is a global Bigtable client, to avoid initializing a new client for
    // every request.
    var client *bigtable.Client
    var clientOnce sync.Once
    
    // BigtableRead is an example of reading Bigtable from a Cloud Function.
    func BigtableRead(w http.ResponseWriter, r *http.Request) {
    	clientOnce.Do(func() {
    		// Declare a separate err variable to avoid shadowing client.
    		var err error
    		client, err = bigtable.NewClient(context.Background(), r.Header.Get("projectID"), r.Header.Get("instanceId"))
    		if err != nil {
    			http.Error(w, "Error initializing client", http.StatusInternalServerError)
    			log.Printf("bigtable.NewClient: %v", err)
    			return
    		}
    	})
    
    	tbl := client.Open(r.Header.Get("tableID"))
    	err := tbl.ReadRows(r.Context(), bigtable.PrefixRange("phone#"),
    		func(row bigtable.Row) bool {
    			osBuild := ""
    			for _, col := range row["stats_summary"] {
    				if col.Column == "stats_summary:os_build" {
    					osBuild = string(col.Value)
    				}
    			}
    
    			fmt.Fprintf(w, "Rowkey: %s, os_build:  %s\n", row.Key(), osBuild)
    			return true
    		})
    
    	if err != nil {
    		http.Error(w, "Error reading rows", http.StatusInternalServerError)
    		log.Printf("tbl.ReadRows(): %v", err)
    	}
    }
    

    この関数はテーブルに対して読み取りリクエストを送信して、行キー接頭辞が phone であるすべての stats_summary データをフェッチします。この関数は、関数のエンドポイントに HTTP リクエストを行うと実行されます。

関数をデプロイする

HTTP トリガーを使用して関数をデプロイするには、bigtable ディレクトリで次のコマンドを実行します。

Node.js

gcloud functions deploy get \
--runtime nodejs10 --trigger-http
優先する Node.js のバージョンを指定するには、--runtime フラグに次の値を使用します。
  • nodejs10
  • nodejs12
  • nodejs14(公開プレビュー)

Python

gcloud functions deploy bigtable_read_data \
--runtime python38 --trigger-http
優先する Python バージョンを指定するには、--runtime フラグに次の値を使用します。
  • python37
  • python38
  • python39(公開プレビュー)

Go

gcloud functions deploy HelloBigtable \
--runtime go113 --trigger-http
優先する Go バージョンを指定するには、--runtime フラグに次の値を使用します。
  • go111
  • go113

関数のデプロイには最大 2 分かかります。

関数のデプロイが完了すると、url の値が返されます。この値は、関数をトリガーするときに使用します。

Google Cloud Console の Cloud Functions ページで、デプロイされた関数を確認できます。このページでは関数の作成と編集、関数の詳細と診断を得ることもできます。

関数をトリガーする

関数に HTTP リクエストを出します。

Node.js

curl "https://REGION-PROJECT_ID.cloudfunctions.net/get" --trigger-http

Python

curl "https://REGION-PROJECT_ID.cloudfunctions.net/bigtable_read_data" --trigger-http

Go

curl "https://REGION-PROJECT_ID.cloudfunctions.net/HelloBigtable" --trigger-http

ここで REGIONPROJECT_ID は、関数のデプロイが完了したときにターミナルに表示される値と一致します。読み取りリクエストの結果を示す出力が表示されます。

ブラウザで関数の URL にアクセスして、読み取りリクエストの結果を表示することもできます。

クリーンアップ

このトピックで使用した Cloud Bigtable と Cloud Functions のリソースについて、Google Cloud アカウントに課金されないようにするには、次の手順を行います。

  1. インスタンスを削除します。

    gcloud bigtable instances delete test-instance
    
  2. デプロイした関数を削除します。

    Node.js

    gcloud functions delete get --trigger-http

    Python

    gcloud functions delete bigtable_read_data --trigger-http

    Go

    gcloud functions delete HelloBigtable --trigger-http

次のステップ