概要
ストリーミング対応版の記事を公開しました。最新情報はそちらをご覧ください。
https://qiita.com/K-Kachi/items/8aa6c81990b7e8c6a628
Cloud Run とはグーグルが提供する サーバレスコンピューティングサービス の1つで、ステートレスなコンテナを実行可能なサービスである。
ウェブリクエストに応答する任意のコンテナを実行可能なため自由度が高い。
最近(といっても数か月前だが)、新機能としてUnary gRPC プロトコル(非ストリーミングの gRPC)のサポートが発表された。
そこで、Go言語でのチュートリアルを参考にしつつ、試しにRustでgRPCサーバを構築してみた。
RustでgRPC
tonic はgRPCサーバ・クライアントをRustで実装したライブラリである。
このライブラリのリポジトリにあるExamplesをもとに Cloud Run で実行可能なgRPCサーバを構築する。
まずはソースコードをとってくる。
git clone https://github.com/hyperium/tonic.git
cp -r tonic/examples tonic-examples
cd tonic-examples
続いてCargo.toml
をいじる。
106c106
< tonic = { path = "../tonic", features = ["tls", "data-prost"] }
---
> tonic = { version = "0.1", features = ["tls", "tls-roots"] }
131c131
< tonic-build = { path = "../tonic-build", features = ["prost"] }
---
> tonic-build = "0.1"
Cloud Run では https での呼び出しが必須のためtls
関連が必要になってくる。
tonicが外部クレートとして利用されることによる変更も適宜行う。
sed -i 's/::prost//g' build.rs
この段階でサンプルコードが動作することを確かめておく。
cargo run --bin helloworld-server
# 別のターミナルで実行
cargo run --bin helloworld-client
Cloud Run で呼び出すための変更
IPアドレスとポート番号を変更する。
ポート番号は環境変数から与える。
30c30,31
< let addr = "[::1]:50051".parse().unwrap();
---
> let port = std::env::var("PORT").unwrap_or("8080".into());
> let addr = format!("0.0.0.0:{}", port).parse().unwrap();
Dockerfileも用意する。証明書関連のパッケージもインストールしていることに注意。
テストが目的なのでコンパイルの最適化を行っていないが、本番環境で利用する場合は--release
フラグを付けるのを忘れずに。その際、バイナリの出力される場所が./target/debug
ではなく./target/release
になることに注意。
FROM rust:1.41.0 as build-env
WORKDIR /app
ADD . .
RUN rustup update && rustup component add rustfmt && cargo build --bin helloworld-server
FROM debian:stretch-slim
WORKDIR /app
RUN apt-get update && apt-get install -y libgcc1 libgomp1 libstdc++6 ca-certificates && update-ca-certificates && rm -rf /var/lib/apt/lists/*
COPY --from=build-env /app/target/debug/helloworld-server /app
ENTRYPOINT ["./helloworld-server"]
ビルド
Dockerfileはローカルでビルドしてもよいが、Cloud Buildを使ったほうが個人的には早くて便利。
.gcloudignore
でバイナリフォルダを除いておく。
target/
gcloud builds submit --machine-type=n1-highcpu-32 --tag gcr.io/$PROJECT_ID/helloworld-grpc-rust
デプロイ
gcloud
コマンドが使用できることを前提とする。
まずリージョンを設定しておく。以下のコマンドでは東京リージョンを選択している。
gcloud config set run/region asia-northeast1
コンテナイメージを指定してデプロイ。
gcloud run deploy helloworld-grpc-rust --image gcr.io/$PROJECT_ID/helloworld-grpc-rust
途中で質問されるので Cloud Run (fully managed) と Allow unauthenticated invocations [Yes] と答える。
無事デプロイされるとデプロイ先のURLが出力されるはずである。
gRPC クライアント
出力されたURLをクライアントのコードに貼り付ける。そのままではHTTPSに対応していないので修正する。
0a1,2
> use tonic::transport::{Channel, ClientTlsConfig};
>
10c12,19
< let mut client = GreeterClient::connect("http://[::1]:50051").await?;
---
>
> let tls = ClientTlsConfig::new()
> .domain_name("デプロイ先");
>
> let channel = Channel::from_static("https://デプロイ先")
> .tls_config(tls)
> .connect()
> .await?;
15a25
> let mut client = GreeterClient::new(channel);
まとめ
Rustは神。Cloud Run は最強。