Cloud Run functions から Redis インスタンスに接続する

ダイレクト VPC 下り(外向き)を使用すると、Cloud Run functions から Redis インスタンスに接続できます。

設定

Google Cloud CLI をインストール済みで Redis インスタンスを作成済みの場合は、次の手順をスキップできます。

  1. gcloud CLI をインストールして初期化します。

    gcloud init
    
  2. クイックスタート ガイドの手順に沿って Redis インスタンスを作成します。Redis インスタンスのゾーン、IP アドレス、ポート番号をメモしておきます。

構成用に VPC ネットワークの下り(外向き)を準備する

Redis インスタンスに接続するには、Cloud Run functions が Redis インスタンスの承認済み VPC ネットワークにアクセスできる必要があります。

このネットワークの名前を確認するには、次のコマンドを実行します。

  gcloud redis instances describe INSTANCE_ID --region REGION --format "value(authorizedNetwork)"

ネットワーク名をメモしておきます。

サンプル関数

Cloud Run functions から Redis インスタンスへの接続を確立するサンプル関数です。

使用するプログラミング言語のリポジトリのクローンを作成し、サンプルコードを含むフォルダに移動します。

Go

git clone https://github.com/GoogleCloudPlatform/golang-samples
cd golang-samples/functions/memorystore/redis

Node.js

git clone https://github.com/GoogleCloudPlatform/nodejs-docs-samples
cd nodejs-docs-samples/functions/memorystore/redis

Python

git clone https://github.com/GoogleCloudPlatform/python-docs-samples
cd python-docs-samples/functions/memorystore/redis

サンプルコードは、関数がトリガーされるたびに Redis カウンタをインクリメントします。

Go

この関数は github.com/gomodule/redigo/redis クライアントを使用します。


// Package visitcount provides a Cloud Function that connects
// to a managed Redis instance.
package visitcount

import (
	"errors"
	"fmt"
	"log"
	"net/http"
	"os"

	"github.com/GoogleCloudPlatform/functions-framework-go/functions"
	"github.com/gomodule/redigo/redis"
)

var redisPool *redis.Pool

func init() {
	// Register the HTTP handler with the Functions Framework
	functions.HTTP("VisitCount", visitCount)
}

// initializeRedis initializes and returns a connection pool
func initializeRedis() (*redis.Pool, error) {
	redisHost := os.Getenv("REDISHOST")
	if redisHost == "" {
		return nil, errors.New("REDISHOST must be set")
	}
	redisPort := os.Getenv("REDISPORT")
	if redisPort == "" {
		return nil, errors.New("REDISPORT must be set")
	}
	redisAddr := fmt.Sprintf("%s:%s", redisHost, redisPort)

	const maxConnections = 10
	return &redis.Pool{
		MaxIdle: maxConnections,
		Dial: func() (redis.Conn, error) {
			c, err := redis.Dial("tcp", redisAddr)
			if err != nil {
				return nil, fmt.Errorf("redis.Dial: %w", err)
			}
			return c, err
		},
	}, nil
}

// visitCount increments the visit count on the Redis instance
// and prints the current count in the HTTP response.
func visitCount(w http.ResponseWriter, r *http.Request) {
	// Initialize connection pool on first invocation
	if redisPool == nil {
		// Pre-declare err to avoid shadowing redisPool
		var err error
		redisPool, err = initializeRedis()
		if err != nil {
			log.Printf("initializeRedis: %v", err)
			http.Error(w, "Error initializing connection pool", http.StatusInternalServerError)
			return
		}
	}

	conn := redisPool.Get()
	defer conn.Close()

	counter, err := redis.Int(conn.Do("INCR", "visits"))
	if err != nil {
		log.Printf("redis.Int: %v", err)
		http.Error(w, "Error incrementing visit count", http.StatusInternalServerError)
		return
	}
	fmt.Fprintf(w, "Visit count: %d", counter)
}

Node.js

この関数は redis モジュールを使用します。


const functions = require('@google-cloud/functions-framework');
const redis = require('redis');

const REDISHOST = process.env.REDISHOST || 'localhost';
const REDISPORT = process.env.REDISPORT || 6379;

const redisClient = redis.createClient({
  socket: {
    host: REDISHOST,
    port: REDISPORT,
  },
});
redisClient.on('error', err => console.error('ERR:REDIS:', err));
redisClient.connect();

functions.http('visitCount', async (req, res) => {
  try {
    const response = await redisClient.incr('visits');
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.end(`Visit count: ${response}`);
  } catch (err) {
    console.log(err);
    res.status(500).send(err.message);
  }
});

Python

この関数は redis-py パッケージを使用します。


import os

import functions_framework
import redis

redis_host = os.environ.get("REDISHOST", "localhost")
redis_port = int(os.environ.get("REDISPORT", 6379))
redis_client = redis.StrictRedis(host=redis_host, port=redis_port)


@functions_framework.http
def visit_count(request):
    value = redis_client.incr("visits", 1)
    return f"Visit count: {value}"

サンプルを Cloud Run functions にデプロイする

関数をデプロイするには:

  1. Dockerfile をソース ディレクトリにコピーします。

    cp cloud_run_deployment/Dockerfile .
    
  2. 次のコマンドを実行して、Cloud Build を使用してコンテナ イメージをビルドします。

    gcloud builds submit --tag gcr.io/PROJECT_ID/visit-count
    
  3. 次のコマンドを実行して、コンテナを Cloud Run にデプロイします。

        gcloud run deploy \
        --image gcr.io/PROJECT_ID/visit-count \
        --allow-unauthenticated \
        --region REGION \
        --network NETWORK \
        --subnet SUBNET \
        --set-env-vars REDISHOST=REDIS_IP,REDISPORT=REDIS_PORT
    

    ここで

    • PROJECT_ID は、 Google Cloud プロジェクトの ID です。
    • REGION は Redis インスタンスが配置されているリージョンです。
    • NETWORK は、Redis インスタンスがアタッチされている承認済み VPC ネットワークの名前です。
    • SUBNET は、サブネットの名前です。 サブネットは /26 以上である必要があります。VPC 下り(外向き)は、RFC 1918RFC 6598、クラス E の IPv4 範囲をサポートします。
    • REDIS_IPREDIS_PORT は、Redis インスタンスの IP アドレスとポート番号です。

関数のデプロイが完了したら、関数の URL を取得します。

gcloud run services describe visit-count \
--region=REGION

GET リクエストを URL に送信することで、関数をトリガーするたびにカウンタが増加します。