たびとの旅路 ~電脳砂漠の冒険譚~

フロッピー頼りに歩き、クラウドの地平を見つめる今日まで。見つけたオアシス、迷い込んだ砂の迷宮、全てこの羊皮紙に。

第四章:鉄壁の門番を配置せよ ~Nginxリバースプロキシで護る、gRPCのゴーレム~

旅の途中、興味深いオアシスを見つけた。忘れないうちに、この羊皮紙に記しておくとしよう。

前回の旅で、我々はDocker(コンテナ仮想化技術)という名の器に、gRPCサーバ(高性能RPC通信サーバ)というゴーレムの魂を封じ込めた。しかし、そのゴーレムはまだ、無防備なまま砂漠に佇んでいる。真に頼れる相棒とするには、その前に立ち、あらゆる来訪者を選別する、Nginx(高性能Webサーバ・リバースプロキシ)という名の「鉄壁の門番」が必要だ。

今回は、前回召喚したgRPC(高性能RPC通信)のゴーレムの前に、Nginxをリバースプロキシ(通信中継サーバ)として配置する。これにより、我々のゴーレムは、HTTP/2(高速通信プロトコル)という光の道を安全に行き来できるようになるのだ。これは、ただのゴーレムを、堅牢な城塞に守られた真の守護神へと進化させる、高度な錬金術の記録である。

この羊皮紙のあらまし

この羊皮紙が導く者

  • 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 に web ディレクトリを追加する

ゴーレムの隣に、門番のための区画を設ける

第一の儀式:世界の契約書を書き換える(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ポート)を訪れ、門番が掲げる歓迎のページが表示されれば、儀式は成功だ。

Nginx のホームページ

鉄壁の門番が、我々を歓迎している

gRPCクライアント(gRPC通信を行うアプリケーション)からは、門番の魔法の門(https://localhost:7011:NginxのHTTPSポート)を通して、安全にゴーレムと対話することができる。

羊皮紙を巻く前に

前回の旅で召喚したgRPC(高性能RPC通信)のゴーレムに、Nginx(高性能Webサーバ・リバースプロキシ)という鉄壁の門番を追加する儀式は、想像以上にスムーズなものだった。docker-compose.yml(コンテナ構成定義ファイル)にわずか数行を追加し、門番の設計図を用意するだけで、堅牢な城塞が完成したのだ。

Nginxリバースプロキシの優れた点

  1. セキュリティの砦 - Nginxが外部からの直接アクセスを遮断し、gRPCサーバを保護する。location(ルーティングルール)により、許可された通信のみを通過させる
  2. 負荷分散の魔法 - upstream(プロキシ先サーバグループ定義)で複数のバックエンドサーバへの振り分けが可能となり、高負荷時の安定性が向上する
  3. SSL/TLS処理の集約 - NginxでSSL終端を行うことで、バックエンドサーバの処理負荷を軽減し、証明書管理も一元化できる
  4. 柔軟なルーティング制御 - locationディレクティブにより、URLパスに応じた細かいルーティング制御が可能となる

注意すべき点

  1. HTTP/2の明示的指定 - Nginxではlisten 443 ssl http2;のように、http2を明示的に指定する必要がある。これを忘れるとHTTP/1.1で通信され、gRPCの性能が発揮されない
  2. コンテナ名での名前解決 - docker-compose環境では、upstream設定でIPアドレスではなくコンテナ名(greeter)を使用する。これによりDockerの内部DNSが自動的に名前解決を行う

まとめ

これで、我々のゴーレムは、ただのむき出しの魂ではなく、堅牢な城塞に守られた、真の守護神へと進化した。外部からの脅威は門番が選別し、ゴーレムは自らの本来の役割である通信処理に専念できる。

次の旅では、この城塞にDBサーバ(データベースサーバ)という名の「宝物庫」を加え、フロントエンドとバックエンドを分離した、より本格的なマイクロサービスアーキテクチャ(サービス分散型設計)を構築していこうと思う。

この羊皮紙が、同じように自らのゴーレムを、より強固な存在へと進化させたいと願う、未来の冒険者の助けとなることを願う。

おっと、どうやら相棒が腹を空かせたようだ。今日はこのへんで筆を置くとしよう。

砂漠で見つけた魔法のランプ

ラクダの独り言

ご主人が創り出したゴーレムの前に、今度は「もんぱん」とかいう、やたらガタイのいい別のゴーレムを立たせている。なんでも、悪い奴らから守るためらしいが、俺に言わせりゃ、最初からそんなに心配なら、大事なもんは砂の中にでも埋めときゃいいんだ。まったく、人間ってのは、物事を複雑にするのが好きだな。守護者に守護者をつけて、次は何だ?守護者の守護者でも雇うのか?やれやれだぜ。