旅の途中、興味深いオアシスを見つけた。忘れないうちに、この羊皮紙に記しておくとしよう。
Windows、そしてLinux。二つの広大な大地を旅した後、私はついに、gRPC(高性能RPC通信)のゴーレムを召喚する、究極の祭壇に辿り着いた。その名は「Docker」(コンテナ仮想化技術)。あらゆる環境の差異を吸収し、どこにでも持ち運べる、異次元の箱庭だ。
今回は、これまでの旅で得た知見を元に、このDocker(コンテナ仮想化技術)という箱庭の中で、gRPCサーバというゴーレムを錬成する。自己署名証明書(開発用SSL証明書)という結界を自ら創り出し、コンテナ(隔離実行環境)の中で魂を安全に稼働させる、その儀式の全てを、未来の錬金術師たちのために記そう。
この羊皮紙のあらまし
- この羊皮紙のあらまし
- この羊皮紙が導く者
- 砂漠の道標
- 第一の儀式:結界の創造(自己署名証明書)
- 第二の儀式:魂の設計図(ソースコード)
- 最終儀式:魂の召喚と対話
- 羊皮紙を巻く前に
- 砂漠で見つけた魔法のランプ
- ラクダの独り言
この羊皮紙が導く者
- gRPCという名のゴーレムを、Dockerというポータブルな器に封じ込めたいと願う者
- HTTP/2という光の道を、コンテナを越えて繋げたい探求者
- マイクロサービスアーキテクチャに興味がある実務家
- 開発環境をコンテナ化したい開発者
砂漠の道標
- gRPC - Google開発の高性能RPC(Remote Procedure Call)フレームワーク。HTTP/2ベース。
- Docker - コンテナ仮想化技術。アプリケーションを隔離された環境で実行できる。
- docker-compose - 複数のDockerコンテナを一括管理するツール。YAML形式で定義。
- 自己署名証明書 - 認証局を介さず自身で発行したSSL/TLS証明書。開発・テスト環境で使用。
- Dockerfile - Dockerイメージをビルドするための設定ファイル。
- ASP.NET Core - Microsoftのオープンソースなクロスプラットフォームフレームワーク。
- Kestrel - ASP.NET Core標準のWebサーバ。高性能で軽量。
- マルチステージビルド - Dockerfileで複数の段階を経てイメージを作成する手法。最終イメージを軽量化できる。
第一の儀式:結界の創造(自己署名証明書)
HTTPS(暗号化HTTP通信)という聖なる光でゴーレムを護るには、まず「証明書」(SSL/TLS証明書)という名の結界が必要だ。openssl(SSL/TLS暗号化ツール)の古の呪文を三度唱え、我々は自らの手で、この儀式に不可欠な結界を創り出す。
# 秘密鍵という、結界の核を創る(2048ビットRSA鍵) $ openssl genrsa 2048 > ssl_greeter.key # 証明書発行要求(CSR)という、神々への願いを記す $ openssl req -new -key ssl_greeter.key -out ssl_greeter.csr # 自らの力で、願いを成就させ、証明書を創り出す(10年間有効) $ openssl x509 -days 3650 -in ssl_greeter.csr -req -signkey ssl_greeter.key -out ssl_greeter.crt
第二の儀式:魂の設計図(ソースコード)
次に、ゴーレムの魂の設計図を、現代の言葉で記していく。
世界の契約書:docker-compose.yml(Docker Compose設定ファイル)
この箱庭の世界全体の理を定義する。ゴーレムにgreeterという名を与え、外界との魂の通り道(ポート番号)を定め、先ほど創り出した結界(証明書)を、コンテナ(隔離実行環境)内の聖域へと共有する。
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
魂の錬成工程:Dockerfile(イメージビルド定義)
ゴーレムの魂を、どのように錬成するかを記した、最も重要な羊皮紙だ。sdk(.NET SDK:開発キット)という名の広大な工房で魂を鍛え上げ、完成した魂を、aspnet(ASP.NET Coreランタイム)という名の、より軽量で戦闘に特化した器へと移し替える。
# 本番用の器(.NET6 runtime:実行環境のみ) FROM mcr.microsoft.com/dotnet/aspnet:6.0-focal AS runtime ENV ASPNETCORE_URLS=http://+:80;https://+:443 # 待ち受けURLを環境変数で設定 EXPOSE 80 # HTTPポート公開 EXPOSE 443 # HTTPSポート公開 # 魂を鍛える工房(sdk:開発キット) FROM mcr.microsoft.com/dotnet/sdk:6.0-focal AS build ARG DOTNET_SYSTEM_NET_HTTP_USESOCKETSHTTPHANDLER=0 WORKDIR /src COPY ["./GrpcGreeter/GrpcGreeter.csproj", "GrpcGreeter/"] RUN dotnet restore "./GrpcGreeter/GrpcGreeter.csproj" # 依存関係の復元 COPY . . WORKDIR "/src/GrpcGreeter" RUN dotnet build "GrpcGreeter.csproj" -c Release -o /app/build # Releaseビルド # 鍛え上げた魂を工房から取り出す FROM build AS publish RUN dotnet publish "GrpcGreeter.csproj" -c Release -o /app/publish # 発行 # 魂を、本番用の器へと移し替える(マルチステージビルドで軽量化) FROM runtime AS final WORKDIR /app COPY --from=publish /app/publish . # publishステージから成果物をコピー ENTRYPOINT ["dotnet", "GrpcGreeter.dll"] # 起動コマンド
(注:上記Dockerfileは、./src/GrpcGreeter/配下にcsprojファイルがある前提の記述です)
魂の契約:appsettings.json(ASP.NET Core設定ファイル)
ゴーレムに、自らが護られるべき結界(証明書)の場所を教える。
{ "Kestrel": { // ASP.NET Core標準Webサーバの設定 "Certificates": { "Default": { "Path": "/etc/ssl/certs/ssl_greeter.crt", // 証明書のパス "KeyPath": "/etc/ssl/private/ssl_greeter.key" // 秘密鍵のパス } } } }
最終儀式:魂の召喚と対話
全ての設計図が揃ったら、docker-compose build(イメージビルド)で魂を錬成し、docker-compose up -d(コンテナ起動)で箱庭に魂を召喚する。
docker-compose logs(ログ表示)コマンドで、ゴーレムが正常に起動し、力強く鼓動しているのがわかるだろう。
$ docker-compose logs grpc | INFO : Now listening on: http://[::]:80 grpc | INFO : Now listening on: https://[::]:443 grpc | INFO : Application started. Press Ctrl+C to shut down. ...
二つの光の道(ポート80と443)で、来訪者を待ち構えている。これこそが、魂が正常に宿った証だ。
Windowsの世界から、gRPCクライアント(gRPC通信を行うアプリケーション)という名の魔法で、箱庭の中のゴーレムと対話する。
172.18.126.178:7094という、異次元への座標(WSL2のIPアドレス:ポート番号)を指定し、HttpClientHandler(HTTP通信制御クラス)で結界への信頼を宣言すれば、二つの世界は光の道で結ばれる。
// 異次元の座標(WSL2のIPアドレスとHTTPSポート) var server = "https://172.18.126.178:7094"; var option = new GrpcChannelOptions() { HttpClient = new HttpClient(new HttpClientHandler { // 自己署名証明書という結界を、信頼する(開発環境専用) ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator, }) }; var channel = GrpcChannel.ForAddress(server, option); // ...
羊皮紙を巻く前に
Windows、Linux、そしてDocker。三つの大地を旅し、我々はついに、どこにでも持ち運べる、堅牢なgRPC(高性能RPC通信)ゴーレムを錬成する術を手に入れた。自己署名証明書(開発用SSL証明書)という結界を自ら創り出し、docker-compose(Docker統合管理ツール)とDockerfile(イメージビルド定義)という二つの設計図で、異次元の箱庭に魂を宿す儀式は、想像以上に明快なものだった。
Docker版gRPCの優れた点
- 環境の完全な一貫性 - 開発・検証・本番環境で同一の動作を保証。「俺の環境では動くのに」という呪いからの解放
- 真のポータビリティ - コンテナイメージをどこでも実行可能。クラウドでもオンプレミスでも同じ動作を実現
- マルチステージビルドによる軽量化 - sdk(開発キット)で魂を鍛え、aspnet(実行環境)という軽量な器に移し替えることで、最終イメージを最小化
- 環境変数による普遍的制御 -
ASPNETCORE_URLS環境変数でポート設定を制御。launchSettings.json(Visual Studio専用設定)というローカルな呪文に依存しない
この儀式で学んだこと
Docker版では、環境変数ASPNETCORE_URLS=http://+:80;https://+:443という普遍的な方法で、Kestrel(ASP.NET Coreの標準Webサーバ)の待ち受けポートを制御できる。これは、launchSettings.jsonというVisual Studio専用の設定ファイルに依存せず、あらゆる環境で一貫して動作する、真に移植可能な設定方法だ。
まとめ
この後、我々の旅は、この城塞の前にNginx(高性能Webサーバ・リバースプロキシ)という鉄壁の門番を配置する、さらなる冒険へと続いていく。Dockerという異次元の箱庭は、単なる実行環境ではなく、マイクロサービスアーキテクチャ(サービス分散型設計)という、より壮大な世界を構築するための、確かな礎となるのだ。
この羊皮紙が、同じように異次元の箱庭で魂を錬成しようと挑む、未来の冒険者の助けとなることを願う。
おっと、相棒が「もう日が暮れる」と急かしている。今宵はここまでとしよう。
砂漠で見つけた魔法のランプ
- 第一章:古の魔法は死んだ。王の帰還だ。 ~WCFからgRPCへ、魂の継承儀式~ | Windows環境でのgRPC実装を記した前回の冒険記録
- 第二章:異世界に、魂を宿せ ~Linuxと.NETで創る、gRPCのゴーレム~ | Linux環境での実装を記した前回の冒険記録
- 蜃気楼との決別 ~Docker Desktopを捨て、WSL2に拠点を築く~ | WSL2環境でのDocker構築方法を記した古文書
- ASP.NET Core gRPC チュートリアル - Microsoft Docs | Microsoft公式のgRPC実装ガイド
- Kestrel エンドポイントの構成 - Microsoft Docs | Kestrelのポート設定と証明書設定に関する賢者の言葉
- NLog with ASP.NET Core 6 - GitHub | ログ管理に関する実践的な古文書
ラクダの独り言
ご主人が「どっかー」とかいう、透明な箱の中にゴーレムを創り出して、悦に入っている。なんでも、この箱ごとどこへでも持っていけるらしい。俺に言わせりゃ、そんな面倒なことしなくても、俺の背中に乗せりゃどこへでも運んでやるのによ。それに、箱の中に箱を入れて、その中にまた何か入れて…って、まるで入れ子細工だ。まったく、人間ってのは、シンプルなものを複雑にするのが大好きだな。やれやれだぜ。