NGINX Open Source 1.13.10でリリースされたgRPCトラフィックの最初のネイティブサポートについて、ここでご紹介します。
NGINX Plusリリース15には、gRPCサポートと、NGINX 1.13.9で導入されたHTTP/2サーバプッシュのサポートが含まれています。
NGINXはgRPC TCP接続をプロキシすることができます。この新しい機能を使用して、gRPCメソッドのコールを終了、検査、およびルーティングすることができます。これらの機能は、以下の目的で使用できます。
詳細については、オンデマンドのウェビナー、NGINX:HTTP / 2サーバプッシュとgRPC(英語版)もご覧ください。
gRPCとは、リモートプロシージャコール用のプロトコルであり、クライアントとサーバアプリケーション間の通信に使用されます。コンパクト(リソース効率が良い)で複数の言語に移植できるように設計されており、要求応答とストリーミング対話の両方をサポートしています。このプロトコルは、その広範な言語サポートとシンプルなユーザー向けの設計により、サービスメッシュ実装を含め、人気が高まっています。
gRPCは、クリアテキストまたはTLS暗号化のいずれかで、HTTP/2を介して転送されます。 gRPCの呼び出しは、効率的にエンコードされた本文を含むHTTP POST
リクエストとして実装されます(プロトコルバッファーは標準のエンコードです)。 gRPCの応答は、同様にエンコードされた本文を使用し、HTTPトレーラーを使用して、応答の最後にステータスコードを送信します。
設計上、gRPCプロトコルはHTTP/1.xでは転送できません。 gRPCプロトコルは、HTTP/2接続の多重化およびストリーミング機能を利用するために、HTTP/2での利用が必須です。
下記では、gRPC Hello Worldクイックスタートチュートリアルの複数例を用いて、シンプルなクライアントおよびサーバプリケーションを作成する例を示しています。NGINXにおける設定の詳細を共有します。ヒントとして参考にしていただければ幸いです。
まず、クライアントアプリケーションとサーバプリケーションの間にNGINXを配置します。NGINXは、サーバプリケーションに安定した信頼性の高いゲートウェイを提供します。
まず、gRPCを更新しNGINXをデプロイします。 ソースからNGINXをビルドする場合は、http_ssl
およびhttp_v2
モジュールを含めることを忘れないでください。
$ auto/configure --with-http_ssl_module --with-http_v2_module
NGINXは、gRPCトラフィックをHTTPサーバを使用して待ち受け、grpc_pass
ディレクティブを使用してトラフィックをプロキシします。 続くプロキシ設定をNGINXで作成し、ポート80で暗号化されていないgRPCトラフィックをリッスンし、ポート50051でサーバにリクエストを転送します。
http { log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent"'; server { listen 80 http2; access_log logs/access.log main; location / { # Replace localhost:50051 with the address and port of your gRPC server # The 'grpc://' prefix is optional; unencrypted gRPC is the default grpc_pass grpc://localhost:50051; } } }
grpc_pass
ディレクティブのアドレスが正しいことを確認してください。 クライアントを再コンパイルして、NGINXのIPアドレスと待ち受けるポートを指定します。
変更したクライアントを実行すると、以前と同じ応答が表示されますが、トランザクションはNGINXによって終了および転送されます。 設定したアクセスログで確認できます。
$ tail logs/access.log192.168.20.11 - - [01/Mar/2018:13:35:02 +0000] "POST /helloworld.Greeter/SayHello HTTP/2.0" 200 18 "-" "grpc-go/1.11.0-dev"192.168.20.11 - - [01/Mar/2018:13:35:02 +0000] "POST /helloworld.Greeter/SayHelloAgain HTTP/2.0" 200 24 "-" "grpc-go/1.11.0-dev"
注:NGINXは、クリアテキスト(非TLS)ポート上でHTTP/1.xとHTTP/2を同時にサポートしません。 使用するプロトコルのバージョンに関する事前確認が必要です。 両方のプロトコルバージョンをクリアテキストで処理する場合は、それぞれにリッスンポートを作成します。
Hello Worldクイックスタートの例では、暗号化されていないHTTP/2(クリアテキスト)を使用して通信します。テスト用のためかなりシンプルデプロイですが、実運用の環境に必要な暗号化は提供されません。NGINXを用いて、この暗号化レイヤーを追加して見ましょう。
自己署名証明書のセットを作成し、NGINXサーバの設定を次のように変更します。
server { listen 1443 ssl http2; ssl_certificate ssl/cert.pem; ssl_certificate_key ssl/key.pem; #... }
TLSを使用するためgRPCクライアントは宛先ポート1443に接続し、証明書チェックを無効にします。(この設定は自己署名証明書または信頼されていない証明書を使用する場合に必要となります)Goを使用している場合は、crypto/tls
とgoogle.golang.org/grpc/credentials
をインポートリストに追加し、grpc.Dial()
呼び出しを次のように変更する必要があります。
creds := credentials.NewTLS( &tls.Config{ InsecureSkipVerify: true } ) // remember to update address to use the new NGINX listen port conn, err := grpc.Dial( address, grpc.WithTransportCredentials( creds ) )
NGINXでgRPCトラフィックをセキュアに処理するために必要な設定はこれだけです。本番の実行環境では、自己署名証明書を信頼できる認証局(CA)が発行した証明書に置き換える必要があります。 次に、そのCAを信頼するようにクライアントを設定する必要があります。
内部にプロキシするgRPCトラフィックを暗号化する必要が出てくる場合があります。 その際には、まず非暗号化(grpc
)接続ではなくTLS暗号化(grpcs
)接続をリッスンするようにサーバアプリケーションを変更する必要があります。
cer, err := tls.LoadX509KeyPair( "cert.pem", "key.pem" ) config := &tls.Config{ Certificates: []tls.Certificate{cer} } lis, err := tls.Listen( "tcp", port, config )
そして、NGINXの設定で、gRPCトラフィックをアップストリームのサーバにプロキシするために使用するプロトコルを変更します。
# Use grpcs for TLS-encrypted gRPC traffic grpc_pass grpcs://localhost:50051;
複数のgRPCサービスがあり、それぞれが異なるサーバアプリケーションによって実装されている場合は、何をすべきでしょうか? これらすべてのサービスを単一のTLS暗号化エンドポイントを介して公開できたら素晴らしいと思いませんか?
NGINXでは、サービスとメソッドを識別し、location
ディレクティブを使用してトラフィックをルーティングすることができます。プロトコルの仕様にあるパッケージ、サービス、およびメソッド名になどを参考に、すでに各gRPCリクエストのURLを導き出すことができるかもしれません。SayHello
RPCメソッドの例を見てみましょう
package helloworld; service Greeter { rpc SayHello (HelloRequest) returns (HelloReply) {} }
SayHello
RPCメソッドを呼び出すと、次のログエントリに示すように、/helloworld.Greeter/SayHelloに対するPOST
リクエストが発行されます。
192.168.20.11 - - [01/Mar/2018:13:35:02 +0000] "POST /helloworld.Greeter/SayHello HTTP/2.0" 200 18 "-" "grpc-go/1.11.0-dev"
NGINXでのトラフィックのルーティングは非常に簡単です。
location /helloworld.Greeter { grpc_pass grpc://192.168.20.11:50051; } location /helloworld.Dispatcher { grpc_pass grpc://192.168.20.11:50052; } location / { root html; index index.html index.htm; }
こちらについて自分で試すことが可能です。 ここでは、サンプルのHello Worldパッケージ(helloworld.proto
内)を拡張してDispatcherという名前の新しいサービスを追加し、Dispatcherメソッドを実装する新しいサーバアプリケーションを作成しました。 クライアントは単一のHTTP/2接続を使用して、GreeterサービスとDispatcherサービスの両方にRPC呼び出しを発行します。 NGINXは呼び出しを分離し、それぞれを適切なgRPCサーバにルーティングします。
すべてをキャッチする「location
/
」の箇所に注意してください。 このブロックは、既知のgRPC呼び出しと一致しないリクエストを処理します。 このように、location
ブロックを使用して、同じTLSの暗号化を行うエンドポイントからWebコンテンツや、その他のgRPC以外のサービスを提供することが可能です。
キャパシティを増やして高可用性を実現するためには、gRPCサービスをどのようにスケーリングするのかを見ていく必要があります。NGINXのアップストリームグループでこの要望を実現することが可能です:
upstream grpcservers { server 192.168.20.11:50051; server 192.168.20.12:50051; } server { listen 1443 ssl http2; ssl_certificate ssl/certificate.pem; ssl_certificate_key ssl/key.pem; location /helloworld.Greeter { grpc_pass grpc://grpcservers; error_page 502 = /error502grpc; } location = /error502grpc { internal; default_type application/grpc; add_header grpc-status 14; add_header grpc-message "unavailable"; return 204; } }
もちろん、アップストリームでTLSをリッスンしている場合は、grpc_pass
grpcs://upstreams
を使用できます。
NGINXは、さまざまな負荷分散アルゴリズムを使用して、gRPCの呼び出しをアップストリームのgRPCサーバ全体に分散することができます。 NGINXのヘルスチェック機能では、応答していないサーバや、エラーがでているかどうかを検出し、その問題のあるサーバをローテーションから外します。この設定サンプルでは、使用可能なサーバがない場合、「/error502grpc
」のロケーションを用いて、gRPC準拠のエラーメッセージを返すよう動作します。
本内容に、コメントやフィードバックなどあれば、コミュニティメーリングリストを通じてぜひご意見お聞かせください。
確認されたバグのレポートは、Tracバグトラッカーに送信してください。
下記、関連ウェビナーもご参照ください。
「NGINX HTTP/2 Server Push and gRPC(英語版)」
"This blog post may reference products that are no longer available and/or no longer supported. For the most current information about available F5 NGINX products and solutions, explore our NGINX product family. NGINX is now part of F5. All previous NGINX.com links will redirect to similar NGINX content on F5.com."