CloudRunでRedis(Memorystore)を利用する


この記事は、Google Cloud Platform(GCP)のサービスであるCloudRunでRedisを利用するための方法をまとめたものです。

CloudRundもサーバレスVPCアクセスが利用可能になったので、CloudRunからMemorystore(Redis)を利用することが可能になっています。
CluodRunでできることがどんどん増えていくのは嬉しいですね。

ポイント

  • フルマネージドなインメモリサービスであるMemorystore(Redis,Memcached)を利用する
  • Memorystoreを利用するにはプライベートアドレスでの接続が必要
  • GAEやCloudRunから接続する場合はサーバーレスVPCアクセスを利用する
    ※GAEやCloudRunはマネージドサービスなのでプライベートアドレスが付与されない

手順

  1. サーバーレスVPCを作成
  2. MemoryStoreを作成
  3. CloudRunを作成

1. サーバーレスVPCを作成

CloudRunからアクセスするためのネットワークを作成します。

GCPコンソールから
VPCネットワーク > サーバーレスVPCアクセス
に移動し、コネクタを作成
(初回はAPIを有効化する必要あり)

例えば下記のように設定します。

2. Memorystore(Redis)を作成

次に、Memorystore(Redis)を下記の点に注意して作成します。

  • ロケーションを 1.で作成したコネクタと同じリージョンにする
    (今回はasia-northeast1)

  • ネットワークを1.で作成したコネクタと同じネットワークにする
    (今回はdefault)

これらを設定することで 1.のコネクタを通したVPCアクセスが可能になります。

3. CloudRunを作成

最後に、CloudRunにソースコードをデプロイします。

変数設定にRedisのIPアドレス、ポート番号を指定する

2.で作成したMemorystoreのIPアドレス、ポート番号を環境変数に下記のように設定します。

接続設定に作成したサーバーレスVPCコネクタを指定する

CloudRunが接続するコネクタを下記の画像のように設定します。

サンプルコード

サイト訪問によるカウントアップ

main.go
// 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)
    }
}

Dockerfileはかなり適当...

FROM golang:1.13
RUN mkdir -p /app
WORKDIR /app
COPY . /app
RUN go build /app/main.go
ENTRYPOINT ["/app/main"]

ここまでの設定ができていれば、リロードするごとに数値がカウントアップされるサイトがデプロイされていると思います。

参考サイト

GAEからサーバレスVPCへの接続
https://cloud.google.com/appengine/docs/standard/python/connecting-vpc?hl=ja#creating_a_connector

GAE/GoでRedisへ接続する
https://cloud.google.com/appengine/docs/standard/go/using-memorystore?hl=ja