こんにちは、たびとです。
前回、WSL2/Ubuntu で作った gRPC サーバアプリを Docker コンテナで構築しましたが、 gRPC クライアントと gRPC サーバの間に Nginx サーバをバースプロキシとして構築します。
今回の記事は「前回の続き」となっています。 前回の記事はこちらを参照してください。
この記事の対象者
- gRPC により HTTP/2 通信 (現在 HTTP/3 はプレビュー機能) アプリを作ってみたい。
- gRPC アプリを Nginx をリバースプロキシとして HTTP/2 通信で実装したい。
docker の準備
ここでは、WSL2/Ubuntu 上にインストールした docker を用いています。 詳細は、以前の記事を参考にしてください。
gRPC サーバ
前回の gRPC の資産に Nginx のサーバ分を追加します。 web ディレクトリを作成し、Nginx 用のDockerfile と default.conf を追加します。
$ cd ~/greeter $ mkdir web $ touch ./web/Dockerfile $ touch ./web/default.conf
ソースコード
docker-compose.yml に Nginx 用の定義を追加します。 http は Nginx の Welcome ページ表示用、https(ssl) は gRPC 用のリバースプロキシとして使います。
version: '3.8' services: #gRPC (ASP.NET Core) app: container_name: 'greeter' build: context: ./src dockerfile: Dockerfile ports: - "5094:80" - "7094:443" environment: - TZ=Asia/Tokyo volumes: - ./ssl_greeter.crt:/etc/ssl/certs/ssl_greeter.crt - ./ssl_greeter.key:/etc/ssl/private/ssl_greeter.key tty: true restart: always stdin_open: true # Web web: container_name: 'nginx' build: ./web ports: - "5011:80" - "7011:443" environment: - TZ=Asia/Tokyo volumes: - ./web/default.conf:/etc/nginx/conf.d/default.conf - ./ssl_greeter.crt:/etc/ssl/certs/ssl_greeter.crt - ./ssl_greeter.key:/etc/ssl/private/ssl_greeter.key tty: true restart: always depends_on: - app
web フォルダ内の Dockerfile を編集します。
今回追加する Nginx サーバは軽量な Alpine 版を使います。
ただし、現時点の Alpine は apk update
で固る障害があるため、
apk
コマンドでパッケージを追加する必要がある場合、避けた方がいいと思います。
イメージ | OS | 容量 |
---|---|---|
nginx:latest | Debian 11 | 142MB |
nginx:alpine | Alpine 3.16.2 | 23.5MB |
環境変数 TZ は、docker-compose.yml で指定しているため、コメントにしています。 どちらで指定しても構いません。
FROM nginx:alpine
# ENV TZ Asia/Tokyo
web フォルダ内の default.conf を編集します。
upstream
の項目は、 gRPC サーバを定義します。
サーバ名は docker-compose.yml に指定した container_name: 'greeter'
を使います。
docker ネットワーク内なので、80 と 443 ポートでアクセスすることができます。
ここでは、どちらのパターンも掲載しておきますが、どちから片方で大丈夫です。
次に、Nginx サーバへのアクセスを定義します。 ポート 80 (クライアントからは 5011)は、Nginx の確認用として、Welcome ページを表示させます。 ポート 443(クライアントからは 7011)は、前回作った証明書を使います。 後は、URL 指定で、gRPC サーバと通信するように設定します。
今回はあまり関係ありませんが、client_max_body_size 0;
とゼロを設定して、
クライアントのリクエストのサイズ制限を無効化しておきます。
# gRPC server upstream grpc_service_servers { server greeter:80; } # gRPC server (SSL) upstream grpcs_service_servers { server greeter:443; } # Default server configuration server { # Welcome(HTML)表示用 listen 80; listen [::]:80; # gRPC用 listen 443 ssl http2; listen [::]:443 ssl http2; server_name _; client_max_body_size 0; # 証明書 ssl_certificate /etc/ssl/certs/ssl_greeter.crt; ssl_certificate_key /etc/ssl/private/ssl_greeter.key; # デフォルト location / { root /usr/share/nginx/html; index index.html index.htm; } # gRPCサーバにhttpで接続する location /greet.Greeter { grpc_pass grpc://grpc_service_servers; error_page 502 = /error502grpc; } # gRPCサーバにhttps(SSL)で接続する location /greet.Greeter.SSL { grpc_pass grpcs://grpcs_service_servers; error_page 502 = /error502grpc; } # エラー定義 location /error502grpc { internal; default_type application/grpc; add_header grpc-status 14; add_header grpc-message "unavailable"; return 204; } }
ビルド&実行
Docker 資材をビルドします。
$ docker-compose build
ビルドの正常終了後、コンテナを起動します。
$ docker-compose up -d
コンテナが正常に起動していることを確認します。
$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES b79b5edfb252 greeter-web "/docker-entrypoint.…" 2 hours ago Up 2 hours 0.0.0.0:5011->80/tcp, :::5011->80/tcp, 0.0.0.0:7011->443/tcp, :::7011->443/tcp nginx 87c0bb4a8d40 greeter-app "dotnet GrpcGreeter.…" 2 hours ago Up 2 hours 0.0.0.0:5094->80/tcp, :::5094->80/tcp, 0.0.0.0:7094->443/tcp, :::7094->443/tcp greeter
docker-compose logs
コマンドで Nginx と gRPC のログを確認します。
Log2Console を起動している場合、前回同様に gRPC に関するログが出力されています。
$ docker-compose logs greeter | DEBUG: init main greeter | TRACE: Discovering gRPC methods for GrpcGreeter.Services.GreeterService. greeter | TRACE: Added gRPC method 'SayHello' to service 'greet.Greeter'. Method type: 'Unary', route pattern: '/greet.Greeter/SayHello'. greeter | DEBUG: Hosting starting greeter | INFO : Now listening on: http://[::]:80 greeter | INFO : Now listening on: https://[::]:443 greeter | DEBUG: Loaded hosting startup assembly GrpcGreeter greeter | INFO : Application started. Press Ctrl+C to shut down. greeter | INFO : Hosting environment: Production greeter | INFO : Content root path: /app/ greeter | DEBUG: Hosting started nginx | /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration nginx | /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/ nginx | /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh nginx | 10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf nginx | 10-listen-on-ipv6-by-default.sh: info: /etc/nginx/conf.d/default.conf differs from the packaged version nginx | /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh nginx | /docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh nginx | /docker-entrypoint.sh: Configuration complete; ready for start up nginx | 2022/09/04 14:38:53 [notice] 1#1: using the "epoll" event method nginx | 2022/09/04 14:38:53 [notice] 1#1: nginx/1.23.1 nginx | 2022/09/04 14:38:53 [notice] 1#1: built by gcc 11.2.1 20220219 (Alpine 11.2.1_git20220219) nginx | 2022/09/04 14:38:53 [notice] 1#1: OS: Linux 5.10.102.1-microsoft-standard-WSL2 nginx | 2022/09/04 14:38:53 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576 nginx | 2022/09/04 14:38:53 [notice] 1#1: start worker processes nginx | 2022/09/04 14:38:53 [notice] 1#1: start worker process 31 nginx | 2022/09/04 14:38:53 [notice] 1#1: start worker process 32
ブラウザで http://localhost:5011
に接続し、Nginx のホームページが表示されることを確認します。
Web サーバへの接続
Alpine なので、ash を指定します。
$ docker-compose exec web /bin/ash または $ docker-compose exec web ash
gRPC サーバへの接続
$ docker-compose exec app /bin/bash または $ docker-compose exec app bash
gRPC クライアント
クライアントは、URL を変更する以外、全て同じなので割愛します。
gRPC クライアントからは、今回の作り方では 4通りのアクセスができます。 大きくは Nginx サーバ経由、または gRPC サーバ経由になります。 ただし、Nginx サーバ経由の場合、Nginx までは SSL が必須ですが、 gRPC サーバへは SSL を選択する必要はありません。
サーバ | アクセス方法 | 補足 |
---|---|---|
Nginx | https://localhost:7011/greet.Greeter |
gRPC サーバへ HTTP/2 (SSLなし) |
Nginx | https://localhost:5011/greet.Greeter.SSL |
gRPC サーバへ HTTP/2 + SSL |
gRPC | https://localhost:7094 |
直接 gRPC サーバへ HTTP/2 + SSL |
gRPC | http://localhost:5094 |
直接 gRPC サーバへ HTTP/2 |
IPv4 アドレスを指定する場合、localhost の箇所を IPv4 アドレスに変更してください。 このとき、docker を起動させた WSL2/Ubuntu の IP アドレスを指定してください。
実行結果は、前回同様なので省略します。
まとめ
今回は前回の docker 版 gRPC サーバに Nginx のリバースプロキシを追加しました。 Nginx の追加に関しては、特に難しことはなかったと思います。
今後は、gRPC の通信にファイルやバイナリデータを送受信するとか、 それらを DB サーバを作って、そこに保存できるようにするアプリを掲載しようと思います。 このときは、ネットワークもフロントエンドとバックエンドに分離していきましょう。 それぐらいの規模になったら、GitHub に掲載しようと思います。
上記のように Docker で、Web-AP-DB の 3 層構造を作るぐらいになると、 やはり書籍で一通り勉強しておくと良いと思います。 私が読んだ中で、お勧めなのは以下の本です。 ただし、CentOS のため、WSL2/AlmaLinux を使うといいかもしれません。
最後に参考サイトを掲載しておきます。 では、皆さん、よい旅を。