双方向ストリーミングなgRPCサーバーをGKEにデプロイしてみる

2021.12.14

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

どうもMAD事業部の新井です。

本エントリは クラスメソッド Google Cloud Advent Calendar 2021 の14日目の記事です。

あまりいいネタも思いつかなかったので、前回作成したojichat-streamをGoogle Kubernetes Engine(GKE)にデプロイしてみようと思います。

正直GKEは触ったことないので、初歩的な内容になるかと思います。

概要

こちらのESPを使用したGKE用Endpointsのスタートガイドを参考に進めていきます。

GKE上のgRPCサーバーと通信するためにCloud EndpointsのESPv1を利用します。ESPv1はNginxベースのリバースプロキシとして動作し、サイドカーコンテナとしてアプリケーションと一緒にデプロイすることで、認証、モニタリング、ロギングなどのCloud Endpointsの機能が利用可能です。

ちなみにESPv2はEnvoyベースのプロキシです。 機会があればこちらも試してみたいです。

Endpoints の設定

サンプルプロジェクトのクローン

以前作った、ojichat-streamをそのまま使います。

git clone https://github.com/seiichi1101/ojichat-stream

※以降はこのリポジトリ内で作業を進めます

コードの自動生成

protoc -I proto \
  --go_out proto/gen \
  --go_opt paths=source_relative \
  --go-grpc_out proto/gen \
  --go-grpc_opt paths=source_relative \
  --descriptor_set_out=api_descriptor.pb \
  proto/ojichat.proto

Cloud EndpointのデプロイにFileDescriptorSetが必要なので、protocコマンドに--descriptor_set_outを追加しています。

APIの設定ファイル

type: google.api.Service
config_version: 3
name: ojichat-stream.endpoints.<your-accont-id>.cloud.goog
title: Ojichat Strem gRPC API
apis:
- name: ojichat.Ojichat
usage:
  rules:
  - selector: ojichat.Ojichat.Chat
    allow_unregistered_calls: true

selectorにはProtocol Bufferの「パッケージ名+サービス名」の組み合わせになっている必要があります。

Endopiontのデプロイ

gcloud endpoints services deploy api_descriptor.pb api_config.yaml

先にEndpointをデプロイします。後ほどこのEndpointをESPのサイドカーコンテナから参照させます。

サービスの有効化

GKEが利用するサービス

  • Service Management API

gcloud services enable servicemanagement.googleapis.com

  • Service Control API

gcloud services enable servicecontrol.googleapis.com

  • Google Cloud Endpoints

gcloud services enable endpoints.googleapis.com

Endpointsサービスの有効化

gcloud services enable <ENDPOINTS_SERVICE_NAME>

先ほどデプロイしたEndpointsサービスの有効化です。

Kubernetesクラスタの作成

今回は簡略化のため「GKE Standard」をデフォルト設定のまま利用します。

クラスタへkubectlコマンドを実行できるように認証しておきます。

gcloud container clusters get-credentials cluster-1 --zone asia-northeast1-a

※また、今回はデフォルトのサービスアカウントを利用します。特に指定していなければ、Compute Engineサービスアカウントがデフォルトサービスアカウントとして設定されるはずです。

コンテナのbuild&push

  • build

docker build -t gcr.io/<your-account-id>/ojichat-stream:latest .

  • push

docker push gcr.io/<your-account-id>/ojichat-stream:latest

GCR(Google Container Registry)にPushします。

アプリケーションのデプロイ

マニフェスト

apiVersion: v1
kind: Service
metadata:
  name: esp-grpc-ojichat-stream
spec:
  ports:
  - port: 80
    targetPort: 9000
    protocol: TCP
    name: http2
  selector:
    app: esp-grpc-ojichat-stream
  type: LoadBalancer
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: esp-grpc-ojichat-stream
spec:
  selector:
    matchLabels:
      app: esp-grpc-ojichat-stream
  replicas: 1
  template:
    metadata:
      labels:
        app: esp-grpc-ojichat-stream
    spec:
      containers:
      - name: esp
        image: gcr.io/endpoints-release/endpoints-runtime:1
        args: [
          "--http2_port=9000",
          "--service=ojichat-stream.endpoints.<your-accont-id>.cloud.goog",
          "--rollout_strategy=managed",
          "--backend=grpc://127.0.0.1:50051"
        ]
        ports:
          - containerPort: 9000
      - name: ojichat-stream
        image: gcr.io/<your-accont-id>/ojichat-stream:latest
        ports:
          - containerPort: 50051

L4 LoadBalancerを追加し、ESPをアプリケーションのサイドカーコンテナとして設定しています。

--serviceの部分に、先ほど作成したEndpointのサービス名を割り当てることで、ESPのサイドカーコンテナからCloud Endpointを参照することが可能です。

アプリケーションのデプロイ

kubectl create -f grpc-ojichat-stream.yaml

マニフェストファイルの設定に基づいてデプロイされます。

動作確認

エンドポイントの確認

kubectl get service

表示されるLoad BalancerのEXTERNAL-IPが外部アクセス用のエンドポイントになります。

確認用コマンド

go run ./cmd/client/main.go --name arai --addr <ip-addr>:80

まとめ

正直GKEを触るのは初めてだったため、Cloud EndpointとESPの関係性の理解に苦しんだり、サービスアカウントまわりでハマったりと、結構時間がかかりました。

次はもうちょっと実践的な環境構築ができれば思います。

明日12/15は西田さんです。よろしくお願いします!