Docker で PHP 用の gRPC スタブを生成する
gRPC のスタブコードを生成するには protoc
と protoc プラグインの grpc_php_plugin
が必要です。
protoc
は mac でも容易に導入できるのですが、 grpc_php_plugin
は自前でビルドする必要がある(=ビルド環境を整える必要がある)ため、ローカル環境を汚さないよう Docker を用いてビルドおよびスタブの生成を行いました。
この記事はその備忘録です。
生成するスタブの例として、Open Match の gRPC クライアントを生成します。
Docker で protoc および grpc_php_plugin を準備する
今回は alpine をベースにします。 結論から言うと、以下の Dockerfile で作れます。
FROM alpine:3.12 RUN apk add --no-cache --allow-untrusted \ libtool \ libstdc++ \ linux-headers \ zlib-dev \ protoc \ && apk add --virtual=.build-deps --no-cache --allow-untrusted \ gcc \ g++ \ git \ make \ automake \ autoconf \ && git clone --recursive -b v1.34.1 https://github.com/grpc/grpc \ && cd grpc \ && make grpc_php_plugin \ && mv bins/opt/grpc_php_plugin /usr/local/bin \ && apk del .build-deps \ && apk del *-dev \ && cd .. \ && rm -rf grpc \ && mkdir -p /project WORKDIR /project
実行するときに便利なので docker-compose.yml も用意しておきます。
version: "3" services: protoc: build: context: . volumes: - .:/project
ちなみに
grpc_php_plugin は v1.35 以降でビルドの方法が変わっているようです。 可能であればビルドの方法を調べて書き換えるほうがいいかも。
.proto の依存を解決する
スタブを生成する環境は整ったので、実際に .proto
ファイルからスタブを生成しましょう。
そのためにはまず、 .proto
ファイルを取得する必要があります。
Open Match の API を定義する .proto
ファイルは GitHub から入手することができます。
また、Open Match の frontend サービスの API を定義する frontend.proto
と API のリクエスト・レスポンスを表現する message.proto
はサードパーティの .proto
に依存しています。
スタブを生成するためにはこれらを取得・管理する必要がありますが、バージョンなどの違いを考慮するとなかなか面倒な作業です。
.proto
の管理は protodep というツールを導入するといい感じにできるので、今回はこれを導入します。
protodep は Go で書かれたツールなので、 go install
でインストールできます。
$ go install github.com/stormcat24/protodep@0.1.3
インストールできたら、プロジェクトルートに protodep.toml
を用意しましょう。
proto_outdir = "./third_party" [[dependencies]] target = "github.com/googleapis/googleapis/google/api" revision = "aba342359b6743353195ca53f944fe71e6fb6cd4" path = "google/api" [[dependencies]] target = "github.com/googleapis/googleapis/google/rpc" revision = "aba342359b6743353195ca53f944fe71e6fb6cd4" path = "google/rpc" [[dependencies]] target = "github.com/protocolbuffers/protobuf/src/google/protobuf" revision = "v3.13.0" path = "google/protobuf" [[dependencies]] target = "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger/options" revision = "v1.14.3" path = "protoc-gen-swagger/options" [[dependencies]] target = "github.com/googleforgames/open-match/api" revision = "v1.0.0" path = "open-match/api"
protodep を用いて依存を解決します。
$ mkdir third_party $ protodep up --use-https
これで third_party
ディレクトリに依存をダウンロードすることができました。
補足
mac に protoc をインストールした場合、 protodep.toml
に定義した依存のうち、3つめの github.com/protocolbuffers/protobuf
配下の .proto
ファイルは /usr/local/include
に入ってきていたのですが、 alpine では入ってきませんでした。
そのため、今回はこれも protodep で管理しています。
スタブコードを生成する
用意したビルド環境と定義ファイルを用いて、スタブを生成しましょう。
以下のコマンドで src/Openmatch
ディレクトリにスタブを生成できます。
$ docker-compose run -w /project/third_party/open-match protoc protoc \ -I .:.. \ --plugin=protoc-gen-grpc=/usr/local/bin/grpc_php_plugin \ --php_out=../../src/Openmatch \ --grpc_out=../../src/Openmatch \ api/messages.proto api/frontend.proto
このとき、生成されたコードの namespace は .proto
ファイルのパッケージ名から生成されます。
生成されたコードを autoload するためには PSR-4 の設定か namespace の変更のいずれかが必要です。
PSR-4 の設定は composer.json に記述できます。 composer.json の autoload -> psr-4 に namespace とディレクトリの対応を記述してください。
{ ... "autoload": { "psr-4": { "Project\\Namespace" : "src", "GPBMetadata\\Api\\": "src/ThirdParty/GPBMetadata/Api", "GPBMetadata\\ProtocGenSwagger\\": "src/ThirdParty/GPBMetadata/ProtocGenSwagger", "Openmatch\\": "src/ThirdParty/Openmatch" } } }
namespace を変更する場合は、生成対象の .proto
ファイル(今回では messages.proto
と frontend.proto
)に option
を追加しましょう。
追加する位置はもともと存在した option
の直下あたりでいいのではないかと思います。
// 先頭のコメントは省略 syntax = "proto3"; package openmatch; option go_package = "open-match.dev/open-match/pkg/pb"; option csharp_namespace = "OpenMatch"; option php_namespace = "Path\\To\\Openmatch\\Extension"; // ←ココ option php_metadata_namespace = "Path\\To\\Openmatch\\GPBMetadata"; // ←ココも // 後略