-
Notifications
You must be signed in to change notification settings - Fork 0
MS_DotNetCoreDockerization
- 戻る(.NET Core)
- .NET CoreのDockerfile(
MS_DotNetCoreDockerfile.md) - .NET CoreのDockerコンテナ化
- .NET CoreのDockerfile(
.NET Core の Docker コンテナ化に必要な検討事項。
補足(このページの位置づけ): 「Dockerfile をどう書くか」ではなく、
**「コンテナに載せるためにアプリ側を何を直すか」**を扱うページである。
コンテナ化の作業は、実際には① アプリの前提を変える(本ページ) ・設定の外出し、パス、URL、セッション、証明書 ② Dockerfile を書く(.NET CoreのDockerfile) ③ Compose / K8s で束ねる(コンテナのチェーン)という 3 層に分かれ、① を飛ばすと動かない。
Program.cs、Startup.cs などの初期化処理を変更する。
-
UseUrls を設定する。
-
Session ストアを Redis に変更するなど。
-
カレント・ディレクトリを変更する(
OTR_DotNetCoreInitialization.md)。
補足(なぜセッションと「データ保護」が要点なのか): コンテナは
使い捨てで、複数インスタンスに増えることが前提になる。
このため、プロセス内に状態を持つ実装が破綻する。
項目 何が起きるか 対処 セッション インスタンスごとに別のセッション Redis 等の分散キャッシュへ外出し データ保護キー Cookie の暗号化鍵がインスタンスごとに違う → 認証が壊れる 鍵を共有ストレージに永続化 ローカル ファイル 再起動で消える ボリューム or オブジェクト ストレージ 特に データ保護(Data Protection) の見落としは典型的な事故で、
「ログインできるが、リロードすると落ちる」
「インスタンスを増やした途端に認証が不安定になる」という形で現れる。
ASP.NET Core は認証 Cookie や CSRF トークンをこの鍵で保護しているため、
鍵の共有はコンテナ化の必須作業である。
- 使用するファイルは以下の 2 つの方法で、コンテナに含める。
- 何れの方法も、プロジェクト・ファイルの変更が必要になる。
プロジェクト出力に含めると、
Dockerfile の以下コマンドでコンテナに出力される。
RUN dotnet publish -c release -o /app
...
COPY --from=build /app ./埋め込まれたリソースとして埋め込む。
コチラ(.NET CoreのDockerfile(MS_DotNetCoreDockerfile.md))でも言及した通り、別物なので。
- https://github.com/NetDevInfraWGinOSSConsortium/OAuth2OidcArchitOnDocker/blob/develop/programs/MultiPurposeAuthSiteCore/MultiPurposeAuthSiteCore/Dockerfile
- https://github.com/NetDevInfraWGinOSSConsortium/OAuth2OidcArchitOnDocker/blob/develop/DockerHub/Push/MultiPurposeAuthSiteCore/Dockerfile
補足(開発用と本番用が別物である理由): Visual Studio が生成する
Dockerfile はデバッガをアタッチするための構成を含んでおり、
そのまま本番に使うものではない。【本番用】マルチステージ ビルド FROM sdk AS build … ビルドだけに使う(重い) FROM aspnet AS final … 実行時はランタイムのみ(軽い)**SDK イメージ(約 700MB〜)と ASP.NET ランタイム イメージ(約 200MB)**では
サイズが大きく違うため、マルチステージにするだけで効果がある。
さらに小さくしたい場合は、Alpine 版や
chiseled(distroless 相当)イメージを選ぶ。
- プロジェクト出力に含める方式も併用する。
- 以下は HTTPS 化するための証明書
COPY ["MultiPurposeAuthSiteCore/aspnetapp.pfx", "./"] # Added補足(証明書をイメージに焼き込まないこと): 上記は検証用の手法である。
.pfxをイメージに含めると、イメージを取得できる者が
秘密鍵を取り出せる。本番では、
- ボリューム / Secret でマウントする(K8s の Secret、Docker Secret)、
- Key Vault から起動時に取得する、
- そもそもTLS 終端を手前に置く(Application Gateway、
Ingress、リバース プロキシ)、のいずれかにする。3 つ目が最も素直で、
AppService閉域構成テクニカルリファレンス や
AKS の構成でも標準的な形になる。
外部通信か、内部通信かを検討する。
-
外部通信
- Docker Compose の ports でコンテナ・ポートをホスト・ポートにマッピングする。
- Cookie を伴う外部通信は HTTPS 化が必要になる事が多い。
-
内部通信
- Docker Compose の networks で同一のネットワークに含めて通信可能にする。
- 内部通信は HTTP のままにする必要がある。
- SameSite 属性の件で HTTPS 化が必要になる。
- また、内部通信は HTTP での通信にする。
- 自己署名証明書の検証ができない。
- HTTPS リダイレクトを無効化する。
//app.UseHttpsRedirection();- 参考
- HTTPS 経由 ASP.NET Docker を使用したコア イメージのホスト
https://learn.microsoft.com/ja-jp/aspnet/core/security/docker-https
- HTTPS 経由 ASP.NET Docker を使用したコア イメージのホスト
補足(外は HTTPS・中は HTTP という構成): これは
TLS 終端を境界に置くという一般的な構成である。ブラウザ ──HTTPS──▶ [ 境界(ports 公開 / Ingress )] ──HTTP──▶ コンテナ間 ↑ ここで TLS を終端 ↑ 同一ネットワーク内内部を HTTP にする理由は、原文が挙げる
**「自己署名証明書の検証ができない」**が実務上は最大である
(コンテナごとに正規の証明書を用意するのは非現実的)。ただし、ゼロトラストの観点では内部も暗号化すべきという要求もあり、
その場合はサービス メッシュ(Istio 等)の
mTLS で、アプリを変えずに暗号化する方法が採られる。
UseHttpsRedirection()を無効化する点も重要で、
これを残すと内部通信が HTTPS へリダイレクトされて無限ループする。
コンテナの場合はルートディレクトリは仮想ディレクトリでない。
補足: IIS では
https://host/AppName/のように
仮想ディレクトリ配下に配置するのが普通だが、
コンテナでは 1 コンテナ 1 アプリなのでルートに置く。
パスをハードコードしていると壊れるため、
Url.Content("~/...")や<base href>を使うよう直す必要がある。
- Windows パスだと Linux 上で認識しない。
- 標準で Linux パスにしてしまっても良い。
Linux パスは Windows 上で認識するため。
補足: 原文の「Linux パスは Windows 上で認識する」は、
Windows API が/を\と同様に扱うためである。
ただし最も安全なのはPath.Combine/Path.DirectorySeparatorCharを使い、
パスを文字列連結で組み立てないこと。
併せて、ファイル名の大文字小文字も Linux では区別される点に注意
(.NET Coreの開発 参照)。
- 環境変数は、Docker Compose で設定すると楽。
- 内部通信のホスト名は、サービス名に変更する。
- 以下の例では ConnectionString_XXX 変数を上書きしている。
environment:
- UseUrl=http://0.0.0.0:5000/;https://0.0.0.0:5001/
- RedisConfig=redis
- RedisInstanceName=redis
- ASPNETCORE_Kestrel__Certificates__Default__Password=seigi@123
- ASPNETCORE_Kestrel__Certificates__Default__Path=/app/aspnetapp.pfx
- ConnectionString_SQL=Data Source=sqlserver;Initial Catalog=Northwind;User ID=sa;Password=seigi@123;
- ConnectionString_MCN=Server=mysql;Database=test;User Id=root;Password=seigi@123;
- ConnectionString_NPS=HOST=postgres;DATABASE=postgres;USER ID=postgres;PASSWORD=seigi@123;補足(この設定の読み方): 2 つの重要な仕組みが使われている。
① 二重アンダースコアによる階層指定
ASPNETCORE_Kestrel__Certificates__Default__Pathは、
appsettings.json の次の階層に対応する。{ "Kestrel": { "Certificates": { "Default": { "Path": "..." } } } }.NET Core config の構成プロバイダーの仕組みで、
環境変数が JSON の設定を上書きする(後勝ち)。
:は Linux の環境変数名に使えないため__を使う。② サービス名による名前解決
Server=sqlserverRedisConfig=redisのように、
Compose のサービス名がそのままホスト名になる
(Docker の内蔵 DNS が解決する)。
IP を書かずに済むため、コンテナの再作成に強い。注意: この例は検証用なのでパスワードが平文である。
本番では Docker Secret / K8s Secret、
あるいは Key Vault + マネージド ID を使い、
接続文字列に秘密を書かない構成にすること。
以下を比較すると良い。
Docker対応(OTR_DockerSupport.md)
- ASP.NET Coreをコンテナ化する際の設定ポリシー(
DNET_ASPNETCoreContainerPolicy.md) - ASP.NET Coreをスクラッチでコンテナ化する際の手順(
DNET_ASPNETCoreContainerSteps.md)
Tags: 移行, .NET開発, .NET Core, 仮想化
このWikiは「Open棟梁Project」,「OSSコンソーシアム 開発基盤部会」によって運営されています。