Cloud Run(フルマネージド)サービスから Redis インスタンスへの接続

サーバーレス VPC アクセスを使用すると、Cloud Run(フルマネージド)から Redis インスタンスに接続できます。Cloud Run サービスは、Redis インスタンスと同じリージョンに配置する必要があります。

設定

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

  1. 次のように入力し、Cloud SDK をインストールして初期化します。

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

サーバーレス VPC アクセスの構成

Redis インスタンスに接続するには、Cloud Run(フルマネージド)サービスが Redis インスタンスの承認済み VPC ネットワークにアクセスできる必要があります。このアクセスを有効にするには、サーバーレス VPC アクセス コネクタが必要です。

  1. 次のコマンドを使用して、Redis インスタンスの承認済みネットワークの名前を確認します。

    gcloud redis instances describe INSTANCE_ID --region REGION --format "value(authorizedNetwork)"
    
  2. コネクタの作成の手順に従って、サーバーレス VPC アクセス コネクタを作成します。コネクタは Redis インスタンスと同じリージョンに作成し、Redis インスタンスの承認済み VPC ネットワークにコネクタが接続されていることを確認します。コネクタの名前を記憶しておいてください。

サンプル アプリケーション

このサンプル HTTP サーバー アプリケーションは、Cloud Run(フルマネージド)サービスから Redis インスタンスへの接続を確立します。

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

Go

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

Node.js

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

Python

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

このサンプル アプリケーションは、/ エンドポイントがアクセスされるたびに Redis カウンタをインクリメントします。

Go

このアプリケーションは、github.com/gomodule/redigo/redis クライアントを使用します。次のコマンドを実行してインストールします。

go get github.com/gomodule/redigo/redis

// Command redis is a basic app that connects to a managed Redis instance.
package main

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

	"github.com/gomodule/redigo/redis"
)

var redisPool *redis.Pool

func incrementHandler(w http.ResponseWriter, r *http.Request) {
	conn := redisPool.Get()
	defer conn.Close()

	counter, err := redis.Int(conn.Do("INCR", "visits"))
	if err != nil {
		http.Error(w, "Error incrementing visitor counter", http.StatusInternalServerError)
		return
	}
	fmt.Fprintf(w, "Visitor number: %d", counter)
}

func main() {
	redisHost := os.Getenv("REDISHOST")
	redisPort := os.Getenv("REDISPORT")
	redisAddr := fmt.Sprintf("%s:%s", redisHost, redisPort)

	const maxConnections = 10
	redisPool = redis.NewPool(func() (redis.Conn, error) {
		return redis.Dial("tcp", redisAddr)
	}, maxConnections)

	http.HandleFunc("/", incrementHandler)

	port := os.Getenv("PORT")
	if port == "" {
		port = "8080"
	}
	log.Printf("Listening on port %s", port)
	if err := http.ListenAndServe(":"+port, nil); err != nil {
		log.Fatal(err)
	}
}

Node.js

このアプリケーションでは、redis モジュールを使用します。

{
  "name": "memorystore-redis",
  "description": "An example of using Memorystore(Redis) with Node.js",
  "version": "0.0.1",
  "private": true,
  "license": "Apache Version 2.0",
  "author": "Google Inc.",
  "engines": {
    "node": ">=8.0.0"
  },
  "dependencies": {
    "redis": "^3.0.0"
  }
}

'use strict';
const http = require('http');
const redis = require('redis');

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

const client = redis.createClient(REDISPORT, REDISHOST);
client.on('error', (err) => console.error('ERR:REDIS:', err));

// create a server
http
  .createServer((req, res) => {
    // increment the visit counter
    client.incr('visits', (err, reply) => {
      if (err) {
        console.log(err);
        res.status(500).send(err.message);
        return;
      }
      res.writeHead(200, {'Content-Type': 'text/plain'});
      res.end(`Visitor number: ${reply}\n`);
    });
  })
  .listen(8080);

Python

このアプリケーションでは、ウェブサービスに Flask を使用し、redis-py パッケージを使用して Redis インスタンスと通信します。

Flask==1.1.2
gunicorn==20.0.4
redis==3.5.3
import logging
import os

from flask import Flask
import redis

app = Flask(__name__)

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)

@app.route('/')
def index():
    value = redis_client.incr('counter', 1)
    return 'Visitor number: {}'.format(value)

@app.errorhandler(500)
def server_error(e):
    logging.exception('An error occurred during a request.')
    return """
    An internal error occurred: <pre>{}</pre>
    See logs for full stacktrace.
    """.format(e), 500

if __name__ == '__main__':
    # This is used when running locally. Gunicorn is used to run the
    # application on Google App Engine and Cloud Run.
    # See entrypoint in app.yaml or Dockerfile.
    app.run(host='127.0.0.1', port=8080, debug=True)

Cloud Run(フルマネージド)へのアプリケーションのデプロイ

アプリケーションをデプロイするには:

  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 \
    --platform managed \
    --allow-unauthenticated \
    --region REGION \
    --vpc-connector CONNECTOR_NAME \
    --set-env-vars REDISHOST=REDIS_IP,REDISPORT=REDIS_PORT
    

    ここで

    • PROJECT_ID は、Google Cloud プロジェクトの ID です。
    • REGION は、サーバーレス VPC アクセス コネクタと Redis インスタンスが配置されているリージョンです。
    • CONNECTOR_NAME は、コネクタの名前です。
    • REDIS_IPREDIS_PORT は、Redis インスタンスの IP アドレスとポート番号です。

デプロイが正常に完了すると、コマンドラインに Cloud Run サービスの URL が表示されます。ウェブブラウザで(または curl などのツールを使用して)この URL にアクセスし、サービスがアクセスされるたびに Redis インスタンスのカウントが増加することを確認します。