Announcing gRPC Support in NGINX ということで、nginx 1.13.9 で gRPC サポートが入り、HTTP と同じように gRPC ストリームを扱えるようになるようです。めでたい!
grpc_pass ディレクティブが新規に実装され、grpc:// と grpcs:// なバックエンドに対してリバースプロキシを行えるようになるようです。これを使って、
- TLS 終端を nginx にやってもらったり
- 複数のバックエンドを置いて柔軟にロードバランスしてもらったり
- 同一のエンドポイントに複数 gRPC service を設定して、nginx にルーティングしてもらったり
などの設定をすることが可能になるようです。
まだ正式にリリースされているわけではないので、今回は HEAD を持ってきて、リリースに載っている例を試してみます。
下準備
今回は適当に EC2 で Ubuntu 16.04 インスタンスを立ち上げました。必要なパッケージをインストールし、https://hg.nginx.org/ から HEAD の tar.gz を持ってきて、ビルドします。
特に configure にオプションを渡さなければ、すべてのファイルが /usr/local/nginx 以下に配置されます。
$ sudo apt install build-essential libssl-dev libpcre3-dev
$ curl -O https://hg.nginx.org/nginx/archive/tip.tar.gz
$ tar xvf tip.tar.gz
$ cd nginx-c2a0a838c40f
$ ./auto/configure --with-http_ssl_module --with-http_v2_module
$ make
$ sudo make install
# nginx を foreground で起動
sudo ./nginx -g 'daemon off;'
また、実験用の gRPC サーバー・クライアントを準備します。今回は grpc/grpc の examples にある、Python 版を使います。いつもの greeter のやつですね。
$ sudo apt install python-pip3
$ sudo pip3 install grpcio-tools
$ git clone https://github.com/grpc/grpc.git
# 試しに動かしてみる
$ cd ~/grpc/examples/python/helloworld
$ python3 greeter_server.py
$ python3 greeter_client.py
2018/03/18 14:46:12 Greeting: Hello world
普通にリバースプロキシ
http {
server {
listen 80 http2; // http2 必須
location / {
grpc_pass grpc://localhost:50051;
}
}
}
greeter_client.py を書き換えて、 localhost:80
を向くようにし、実行。
$ python3 greeter_client.py
Greeter client received: Hello, you!
$ tail /usr/local/nginx/logs/access.log
127.0.0.1 - - [18/Mar/2018:16:46:09 +0000] "POST /helloworld.Greeter/SayHello HTTP/2.0" 200 18 "-" "grpc-python/1.10.0 grpc-c/6.0.0 (manylinux; chttp2; glamorous)"
あっさりリバースプロキシできましたね。
普通に TLS 終端してもらう
server {
listen 443 ssl http2;
ssl_certificate ssl/cert.pem;
ssl_certificate_key ssl/key.pem;
}
今回は証明書を用意するのが面倒だったので試さなかったが、これだけで普通に grpcs:// を受けられるようになる、とのこと。外部のクライアントとの間は grpcs で通信したいが、内部の Microservice 同士は平文でいい…… といったケースで便利?
複数 gRPC Service へのルーティング + ロードバランス + REST API との共存例
別の Service ("DaininkiService") を提供する gRPC サーバーを立ててみて、ロードバランスさせてみます。
upstream daininki_service_servers {
# helloworld.Daininki を提供するサーバーたち
server localhost:50052;
server localhost:50053;
}
server {
listen 80 http2;
location /helloworld.Greeter {
grpc_pass grpc://localhost:50051;
}
location /helloworld.Daininki {
# HTTP と同じようにロードバランス
grpc_pass grpc://daininki_service_servers;
error_page 502 = /error502grpc;
}
# バックエンドが unavailable だった場合は gRPC 形式でエラーを返す
location = /error502grpc {
internal;
default_type application/grpc;
add_header grpc-status 14;
add_header grpc-message "unavailable";
return 204;
}
location / {
proxy_pass http://rest_api_server;
}
}
大人気である DaininkiService は大人気なので、2つのサーバーを構えて nginx にロードバランスしてもらっていることが分かると思います。また、バックエンドのいずれもが応答できなかったときは、nginx 自身に application/grpc 形式の応答を返してもらうことも出来るようです。
アナウンスのページには REST API のような non-gRPC サービスも同じ endpoint に混ぜることができる、と書いてありますが、この例のように location /
を記述しても上手く動作しませんでした……。上手く使えた場合、REST API を提供していたアプリケーションを拡張して gRPC も話せるようにするようなケースでは便利ではないでしょうか。
今後
gRPC 関連機能の実装はメーリングリストでのフィードバックを受け、今後の nginx のリリースに含まれるようです。期待ですね!