旅の途中、興味深いオアシスを見つけた。忘れないうちに、この羊皮紙に記しておくとしよう。
前回の旅で、我々はDocker(コンテナ仮想化技術)という名の器に、gRPCサーバ(高性能RPC通信サーバ)というゴーレムの魂を封じ込めた。しかし、そのゴーレムはまだ、無防備なまま砂漠に佇んでいる。真に頼れる相棒とするには、その前に立ち、あらゆる来訪者を選別する、Nginx(高性能Webサーバ・リバースプロキシ)という名の「鉄壁の門番」が必要だ。
今回は、前回召喚したgRPC(高性能RPC通信)のゴーレムの前に、Nginxをリバースプロキシ(通信中継サーバ)として配置する。これにより、我々のゴーレムは、HTTP/2(高速通信プロトコル)という光の道を安全に行き来できるようになるのだ。これは、ただのゴーレムを、堅牢な城塞に守られた真の守護神へと進化させる、高度な錬金術の記録である。
この羊皮紙のあらまし
- この羊皮紙のあらまし
- この羊皮紙が導く者
- 砂漠の道標
- 儀式の準備:門番の設計図を追加する
- 第一の儀式:世界の契約書を書き換える(docker-compose.yml)
- 第二の儀式:門番の魂を定義する
- 最終儀式:城塞の起動と確認
- 羊皮紙を巻く前に
- 砂漠で見つけた魔法のランプ
- ラクダの独り言
この羊皮紙が導く者
- gRPCという名のゴーレムを、より堅牢な城塞で護りたいと願う者
- Nginxをリバースプロキシとして配置し、HTTP/2通信を安全に中継する術を知りたい探求者
- Docker ComposeでマイクロサービスアーキテクチャーLを構築したい実務家
- gRPCとNginxの連携方法を学びたい開発者
砂漠の道標
- gRPC - Google開発の高性能RPC(Remote Procedure Call)フレームワーク。HTTP/2ベース。
- Nginx - 高性能なWebサーバ・リバースプロキシソフトウェア。エンジンエックスと読む。
- リバースプロキシ - クライアントとサーバの間に立ち、通信を中継・制御するサーバ。
- HTTP/2 - HTTPプロトコルの第2版。多重化により高速通信が可能。
- Docker - コンテナ仮想化技術。アプリケーションを隔離された環境で実行できる。
- docker-compose - 複数のDockerコンテナを一括管理するツール。YAML形式で定義。
- upstream - Nginx用語。プロキシ先のサーバグループを定義するディレクティブ。
- SSL/TLS - 通信を暗号化するプロトコル。HTTPSで使用される。
儀式の準備:門番の設計図を追加する
前回のgRPC(高性能RPC通信)の資産に、門番(Nginx)のための設計図を追加する。
webという名の新たな区画を設け、そこに門番の魂の設計図であるDockerfile(コンテナイメージ定義ファイル)と、その行動規範を記したdefault.conf(Nginx設定ファイル)を配置する。
第一の儀式:世界の契約書を書き換える(docker-compose.yml)
docker-compose.ymlという名の世界の契約書に、門番(Nginx)の存在を追記する。
ゴーレム(app)と門番(web)が、互いに依存し、連携して動くよう、ここに力強く宣言するのだ。
version: '3.8' services: # gRPC (ASP.NET Core) - バックエンドサーバ app: container_name: 'greeter' build: context: ./src dockerfile: Dockerfile ports: - "5094:80" # HTTP通信ポート - "7094:443" # HTTPS通信ポート environment: - TZ=Asia/Tokyo volumes: - ./ssl_greeter.crt:/etc/ssl/certs/ssl_greeter.crt # SSL証明書 - ./ssl_greeter.key:/etc/ssl/private/ssl_greeter.key # SSL秘密鍵 tty: true restart: always stdin_open: true # Web (Nginx) - リバースプロキシサーバ web: container_name: 'nginx' build: ./web ports: - "5011:80" # HTTP通信ポート(外部公開) - "7011:443" # HTTPS通信ポート(外部公開) environment: - TZ=Asia/Tokyo volumes: - ./web/default.conf:/etc/nginx/conf.d/default.conf # Nginx設定 - ./ssl_greeter.crt:/etc/ssl/certs/ssl_greeter.crt # SSL証明書 - ./ssl_greeter.key:/etc/ssl/private/ssl_greeter.key # SSL秘密鍵 tty: true restart: always depends_on: - app # appコンテナ起動後にwebコンテナを起動
第二の儀式:門番の魂を定義する
Dockerfile(コンテナイメージ定義)
門番の魂には、軽量にして高速なAlpine版Nginx(Alpine Linuxベースの軽量Nginxイメージ)を選ぶ。
FROM nginx:alpine # ENV TZ Asia/Tokyo
default.conf:門番の行動規範
これが、門番の行動原理を記した、最も重要な古文書だ。
upstream(プロキシ先サーバグループ定義)で、背後に控えるゴーレムの居場所を教え、location(ルーティングルール)で、どんな来訪者をゴーレムへ通すかを厳密に定義する。
# gRPCゴーレムの居場所(HTTP通信用) upstream grpc_service_servers { server greeter:80; # コンテナ名:ポート番号 } # SSLで武装したgRPCゴーレムの居場所(HTTPS通信用) upstream grpcs_service_servers { server greeter:443; } server { # 通常の来訪者には、歓迎の門(Welcomeページ)を見せる listen 80; # gRPCの呪文を唱える者だけを、魔法の門へ通す listen 443 ssl http2; # HTTP/2プロトコル有効化 # ...(SSL証明書の設定など)... # 「/greet.Greeter」という合言葉を唱えた者を、ゴーレムの元へ導く location /greet.Greeter { grpc_pass grpc://grpc_service_servers; # HTTP経由でgRPCプロキシ } # 「/greet.Greeter.SSL」という、より厳格な合言葉を唱えた者を、 # SSLで武装したゴーレムの元へ導く location /greet.Greeter.SSL { grpc_pass grpcs://grpcs_service_servers; # HTTPS経由でgRPCプロキシ } }
最終儀式:城塞の起動と確認
全ての設計図が揃ったら、docker-compose build(イメージビルド)で魂を錬成し、docker-compose up -d(コンテナ起動)で城塞を起動する。
docker ps(コンテナ一覧表示)で、ゴーレムと門番が、共に力強く稼働していることを確認する。
$ docker ps CONTAINER ID IMAGE COMMAND ... NAMES b79b5edfb252 greeter-web "/docker-entrypoint.…" ... nginx 87c0bb4a8d40 greeter-app "dotnet GrpcGreeter.…" ... greeter
二つの魂が、それぞれの役割を果たしている。これこそが、城塞が正常に稼働している何よりの証拠だ。
ブラウザでhttp://localhost:5011(NginxのHTTPポート)を訪れ、門番が掲げる歓迎のページが表示されれば、儀式は成功だ。
gRPCクライアント(gRPC通信を行うアプリケーション)からは、門番の魔法の門(https://localhost:7011:NginxのHTTPSポート)を通して、安全にゴーレムと対話することができる。
羊皮紙を巻く前に
前回の旅で召喚したgRPC(高性能RPC通信)のゴーレムに、Nginx(高性能Webサーバ・リバースプロキシ)という鉄壁の門番を追加する儀式は、想像以上にスムーズなものだった。docker-compose.yml(コンテナ構成定義ファイル)にわずか数行を追加し、門番の設計図を用意するだけで、堅牢な城塞が完成したのだ。
Nginxリバースプロキシの優れた点
- セキュリティの砦 - Nginxが外部からの直接アクセスを遮断し、gRPCサーバを保護する。location(ルーティングルール)により、許可された通信のみを通過させる
- 負荷分散の魔法 - upstream(プロキシ先サーバグループ定義)で複数のバックエンドサーバへの振り分けが可能となり、高負荷時の安定性が向上する
- SSL/TLS処理の集約 - NginxでSSL終端を行うことで、バックエンドサーバの処理負荷を軽減し、証明書管理も一元化できる
- 柔軟なルーティング制御 - locationディレクティブにより、URLパスに応じた細かいルーティング制御が可能となる
注意すべき点
- HTTP/2の明示的指定 - Nginxでは
listen 443 ssl http2;のように、http2を明示的に指定する必要がある。これを忘れるとHTTP/1.1で通信され、gRPCの性能が発揮されない - コンテナ名での名前解決 - docker-compose環境では、upstream設定でIPアドレスではなくコンテナ名(greeter)を使用する。これによりDockerの内部DNSが自動的に名前解決を行う
まとめ
これで、我々のゴーレムは、ただのむき出しの魂ではなく、堅牢な城塞に守られた、真の守護神へと進化した。外部からの脅威は門番が選別し、ゴーレムは自らの本来の役割である通信処理に専念できる。
次の旅では、この城塞にDBサーバ(データベースサーバ)という名の「宝物庫」を加え、フロントエンドとバックエンドを分離した、より本格的なマイクロサービスアーキテクチャ(サービス分散型設計)を構築していこうと思う。
この羊皮紙が、同じように自らのゴーレムを、より強固な存在へと進化させたいと願う、未来の冒険者の助けとなることを願う。
おっと、どうやら相棒が腹を空かせたようだ。今日はこのへんで筆を置くとしよう。
砂漠で見つけた魔法のランプ
- 第三章:異次元の箱庭に、魂を宿せ ~Dockerで創る、gRPCのゴーレム~ | 前回の冒険の記録。gRPCサーバのDocker化の基礎
- 蜃気楼との決別 ~Docker Desktopを捨て、WSL2に拠点を築く~ | WSL2環境でのDocker構築方法を記した古文書
- Nginx - Docker Hub | Nginx公式イメージの詳細。nginx:alpineの使用方法
- NGINX 1.13.10でのgRPCのネイティブサポート | NginxにおけるgRPC対応の公式解説
- プログラマのためのDocker教科書 第2版 - Amazon | Web-AP-DB 3層構造の実践的な魔導書
ラクダの独り言
ご主人が創り出したゴーレムの前に、今度は「もんぱん」とかいう、やたらガタイのいい別のゴーレムを立たせている。なんでも、悪い奴らから守るためらしいが、俺に言わせりゃ、最初からそんなに心配なら、大事なもんは砂の中にでも埋めときゃいいんだ。まったく、人間ってのは、物事を複雑にするのが好きだな。守護者に守護者をつけて、次は何だ?守護者の守護者でも雇うのか?やれやれだぜ。