一般的な Web アプリケーション アーキテクチャ

"優れたアーキテクチャが高価であると思うならば、不完全なアーキテクチャを試してみてください。" - Brian Foote および Joseph Yoder

従来の .NET アプリケーションのほとんどは、実行可能ファイルに対応する単一のユニットとして、または 1 つの IIS appdomain 内で実行される単一の Web アプリケーションとして展開されます。 この方法は最も簡単な展開モデルであり、多くの内部的アプリケーションおよび小さなパブリック アプリケーションに適切に対応します。 ただし、このように単位ユニットとして展開されても、重要なビジネス アプリケーションの大部分は複数のレイヤーへの論理的な分離から恩恵を受けます。

モノリシック アプリケーションとは?

モノリシック アプリケーションは、そのビヘイビアーの観点から見ると、完全な自己独立型のアプリケーションです。 このアプリケーションは、操作の実行中に他のサービスまたはデータ ストアとやり取りすることがありますが、アプリケーションのビヘイビアーの中核を成す部分は独自のプロセス内で実行され、通常はアプリケーション全体が単一ユニットとして展開されます。 このようなアプリケーションを水平方向にスケーリングする必要がある場合、通常は、アプリケーション全体を複数のサーバーまたは仮想マシンに複製します。

オールインワン アプリケーション

アプリケーション アーキテクチャ用の最小限のプロジェクト数は 1 となります。 このアーキテクチャでは、アプリケーションのロジック全体が単一のプロジェクトに含められ、単一のアセンブリにコンパイルされ、単一ユニットとして展開されます。

新しい ASP.NET Core プロジェクトは、Visual Studio またはコマンド ラインのいずれで作成されたかに関係なく、簡単な "オールインワン" モノシリックとして開始されます。 これには、プレゼンテーション、ビジネス、データ アクセス ロジックなど、アプリケーションのあらゆるビヘイビアーが含まれています。 図 5-1 に、単一プロジェクト アプリのファイル構造を示します。

単一プロジェクトの ASP.NET Core アプリ

図 5-1 単一プロジェクトの ASP.NET Core アプリ。

単一プロジェクトのシナリオでは、フォルダーを使用して懸念事項の分離が実現されます。 既定のテンプレートには、Models、Views、および Controllers の MVC パターン責任用の分離フォルダーに加えて、Data および Services 用の追加のフォルダーが含まれています。 この配置では、プレゼンテーションの詳細は可能な限り Views フォルダーに限定する必要があり、データ アクセス実装の詳細は Data フォルダー内に保持されるクラスに限定する必要があります。 ビジネス ロジックは、Models フォルダーにあるサービスとモデル内に配置する必要があります。

単一プロジェクトのモノリシック ソリューションは簡単なのですが、いくつかの欠点があります。 プロジェクトの規模と複雑さが増大するに従い、ファイルとフォルダーの数も増加し続けます。 アルファベット順にグループ化されていない複数のフォルダーには、ユーザー インターフェイス (UI) の懸念事項 (モデル、ビュー、コントローラー) が存在します。 この問題は、Filters や ModelBinders などの UI レベル構造が独自のフォルダーに追加される場合にのみ深刻になります。 ビジネス ロジックは Models フォルダーと Services フォルダーに分散され、どのフォルダーのどのクラスが他のどれに依存すべきかは明示されません。 プロジェクト レベルでのこの編成不足は、スパゲティ コードの原因となることがよくあります。

これらの問題に対処するために、アプリケーションは多くの場合、マルチ プロジェクト ソリューションに展開されます。ここで、各プロジェクトは、アプリケーションの特定の レイヤー に配置されているとみなされます。

レイヤーとは?

アプリケーションの複雑さが増すにつれて、その複雑さを管理することが必要です。その方法の 1 つが、アプリケーションをその責任や懸念事項に従って分割するというものです。 この方法は懸念事項の分離の原則に従って実施されます。また、この方法を使用すれば、特定の機能が実装されている場所を開発者が容易に見つけられるように、増大するコードベースを常に整理された状態に維持することができます。 ただし、レイヤー化されたアーキテクチャには、単なるコード編成に勝る利点が複数あります。

コードをレイヤーに編成することにより、よく使われる下位機能をアプリケーション全体で再利用できるようになります。 この再利用を行うと、コードをほとんど記述する必要がなくなり、DRY (don't repeat yourself) 原則に従って単一の実装でアプリケーションを標準化できるようになるので、便利です。

レイヤー化されたアーキテクチャの場合、アプリケーションではレイヤー間のやり取りに対して制限を加えることができます。 このアーキテクチャは、カプセル化を実現するのに役立ちます。 レイヤーを変更または置換した場合、そのレイヤーと連携しているその他のレイヤーのみが影響を受けます。 レイヤー同士の依存関係を制限することにより、1 つの変更がアプリケーション全体に影響しないように変更の及ぼす影響を軽減することができます。

レイヤー (およびカプセル化) により、アプリケーション内で機能を容易に置換できるようになります。 たとえば、アプリケーションで最初は永続化のために独自の SQL Server データベースが使用されている場合でも、後でクラウド ベースの永続化の方法または Web API の背後での永続化の方法を使用するように選択することが可能です。 論理層内でアプリケーションによって永続化の実装が適切にカプセル化されている場合、その SQL Server に固有のレイヤーを、同じパブリック インターフェイスを実装する新しいレイヤーに置き換えることが可能です。

将来的な要件の変更に合わせて実装を交換できることに加えて、アプリケーション レイヤーではテスト目的で実装を容易に交換することもできます。 アプリケーションの実際のデータ レイヤーまたは UI レイヤーに対して動作するテストを記述しなくても、これらのレイヤーをテスト時に、要求に対して既知の応答を提供するフェイク実装に置き換えることができます。 この方法は、アプリケーションの実際のインフラストラクチャに対してテストを実行する場合と比較して、一般的にテストの記述が簡単であり、テストをより迅速に実行することができます。

論理的なレイヤー化は、エンタープライズ ソフトウェア アプリケーションでのコード編成を改善するための一般的な手法です。コードをレイヤーに編成する方法には複数あります。

注意

"レイヤー" とは、アプリケーション内での論理的な分離を表します。 アプリケーション ロジックを個々のサーバーまたはプロセスに物理的に分散するイベントでは、このような個々の物理的展開ターゲットを "階層" と呼んでいます。 N レイヤー アプリケーションを単一の階層に展開することは可能であり、これは非常に一般的な方法です。

従来の "N レイヤー" アーキテクチャ アプリケーション

図 5-2 に、レイヤーへのアプリケーション ロジックの最も一般的な編成を示します。

代表的なアプリケーション レイヤー

図 5-2 代表的なアプリケーション レイヤー。

これらのレイヤーは多くの場合、UI、BLL (ビジネス ロジック層)、DAL (データ アクセス層) と略称で表現されます。 このアーキテクチャを使用する場合、ユーザーは UI レイヤーを介して要求を行います。UI レイヤーは BLL とのみやり取りします。 次に BLL は、データ アクセス要求のために DAL を呼び出すことができます。 UI レイヤーは DAL に要求を直接出すことも、他の手段によって永続化と直接やり取りすることもありません。 同様に、BLL は DAL を経由して永続化とやり取りするだけです。 この方法では、各レイヤーには独自の既知の責任があります。

この従来のレイヤー化アプローチの欠点の 1 つは、コンパイル時の依存関係が上位から下位に向かって適用されるということです。 つまり、UI レイヤーは BLL に依存し、BLL は DAL に依存するということです。 このことは、アプリケーション内で、通常、最も重要なロジックを保持する BLL が、データ アクセスの実装の詳細 (およびしばしばデータベースの存在) に依存することを意味します。 このようなアーキテクチャでビジネス ロジックをテストするのは困難なことが多く、テスト データベースが必要となります。 次のセクションで示すように、依存関係逆転の原則 (Dependency Inversion principle) を使用すれば、この問題に対処できます。

図 5-3 に、責任 (またはレイヤー) ごとに 3 つのプロジェクトにアプリケーションを分割するソリューションの例を示します。

3 つのプロジェクトによる単純なモノリシック アプリケーション

図 5-3 3 つのプロジェクトによる単純なモノリシック アプリケーション。

このアプリケーションでは編成上の目的で複数のプロジェクトを使用していますが、アプリケーションは引き続き単一ユニットとして展開され、そのクライアントは単一の Web アプリとしてこのアプリケーションとやり取りします。 これにより、展開プロセスが非常に簡単になります。 図 5-4 に、そのようなアプリを Azure を使用してホストする場合の方法を示します。

Azure Web アプリの単純な展開

図 5-4 Azure Web アプリの単純な展開

アプリケーション ニーズの拡大に合わせて、より複雑で堅牢な展開ソリューションが必要な場合があります。 図 5-5 に、追加の機能をサポートするより複雑な展開計画の例を示します。

Azure App Service への Web アプリの公開

図 5-5 Azure App Service への Web アプリの公開

内部的には、このプロジェクトを責任に基づいて複数のプロジェクトに編成することにより、アプリケーションの保守容易性が向上します。

このユニットをスケール アップまたはスケール アウトすることで、クラウド ベースのオンデマンドのスケーラビリティを活用することができます。 スケール アップとは、アプリをホストしているサーバーに CPU、メモリ、ディスク領域などのリソースを追加することを意味します。 スケール アウトとは、そのようなサーバーが物理サーバーか、仮想マシンか、コンテナーかに関係なく、サーバーのインスタンスを追加することを意味します。 アプリが複数のインスタンスでホストされている場合は、ロード バランサーを使用して個々のアプリ インスタンスに要求が割り当てられます。

Azure 内で Web アプリケーションをスケーリングする最も簡単な方法は、アプリケーションの App Service プランでスケーリングを手動で構成するというものです。 図 5-6 に、アプリを提供しているインスタンスの数を構成する適切な Azure ダッシュボード画面を示します。

Azure での App Service プランによるスケーリング

図 5-6 App での App Service プランによるスケーリング。

クリーン アーキテクチャ

依存関係逆転の原則ならびにドメイン駆動設計 (DDD) の原則に従うアプリケーションは、同様のアーキテクチャに到達する傾向があります。 このアーキテクチャには長年にわたってさまざまな名称が付けられてきました。 最初の名前の 1 つがヘキサゴナル アーキテクチャ (Hexagonal Architecture) でした。その後に使用された名前がポート アンド アダプター (Ports-and-Adapters) でした。 最近では、このアーキテクチャはオニオン アーキテクチャまたはクリーン アーキテクチャとして引用されています。 後者のクリーン アーキテクチャは、この電子書籍でアーキテクチャの名前として使用されています。

eShopOnWeb 参照アプリケーションでは、そのコードをプロジェクトに整理するためにクリーン アーキテクチャ アプローチが使用されています。 独自の ASP.NET Core の出発点として使用できるソリューション テンプレートについては、ardalis/cleanarchitecture GitHub リポジトリ を参照してください。

クリーン アーキテクチャでは、ビジネス ロジックとアプリケーション モデルをアプリケーションの中心に配置します。 ビジネス ロジックはデータ アクセスまたはその他のインフラストラクチャの懸念事項に依存するのでなく、この依存関係は逆転されます。つまり、インフラストラクチャおよび実装の詳細はアプリケーション コアに依存します。 この機能を実現するには、アプリケーション コア内で抽象化またはインターフェイスを定義し、それらをインフラストラクチャ レイヤーで定義された型によって実装します。 このアーキテクチャを視覚化するための一般的な方法としては、オニオンに似た一連の同心円を使用します。 図 5-7 に、このスタイルのアーキテクチャを表現した例を示します。

クリーン アーキテクチャ。オニオン ビュー

図 5-7 クリーン アーキテクチャ。オニオン ビュー

この図では、依存関係が最も内側の円に向かっています。 アプリケーション コアという名前は、この図の中心に位置するところから取ったものです。 この図から、アプリケーション コアが他のアプリケーション レイヤーに依存していないことがわかります。 アプリケーションのエンティティとインターフェイスは真中にあります。 そのすぐ外側 (まだアプリケーション コア内) は、ドメイン サービスです。ここでは通常、内側の円で定義されたインターフェイスを実装します。 アプリケーション コアの外側には、UI レイヤーとインフラストラクチャ レイヤーがあり、これらの両方がアプリケーション コアに依存しますが、相互に依存関係があるとは限りません。

図 5-8 に、UI とその他のレイヤーの間の依存関係をより正確に反映させた、従来の水平方向レイヤー図を示します。

クリーン アーキテクチャ。水平方向のレイヤー ビュー

図 5-8 クリーン アーキテクチャ。水平方向のレイヤー ビュー

実線の矢印はコンパイル時の依存関係を表し、破線の矢印は実行時専用の依存関係を表します。 クリーン アーキテクチャを使用する場合、UI レイヤーではコンパイル時にアプリケーション コアで定義されたインターフェイスを操作します。インフラストラクチャ レイヤーで定義された実装型を把握しなくてもよいのが理想的です。 ただし、実行時にこれらの実装型は、アプリを実行するために必須となるので、存在する必要があり、また依存関係挿入を介してアプリケーション コアのインターフェイスに接続される必要があります。

図 5-9 に、これらの推奨事項に従って ASP.NET Core アプリケーションのアーキテクチャを構築した場合の詳細なビューを示します。

クリーン アーキテクチャに基づく ASP.NET Core アーキテクチャの図

図 5-9 クリーン アーキテクチャに基づく ASP.NET Core アーキテクチャの図。

アプリケーション コアはインフラストラクチャに依存していないので、このレイヤーを対象にした自動化された単体テストを記述するのは非常に簡単です。 図 5-10 と図 5-11 に、このアーキテクチャにテストがどのように適合するのかを示します。

UnitTestCore

図 5-10 分離環境でのアプリケーション コアの単体テスト。

IntegrationTests

図 5-11 外部依存関係を持つインフラストラクチャ実装の統合テスト。

UI レイヤーはインフラストラクチャ プロジェクトで定義された型に対して直接的な依存関係を持たないことから、テストの促進、またはアプリケーション要件の変更への対応を目的として実装を交換することも容易にできます。 ASP.NET Core には依存関係挿入の使用とサポートが組み込まれているので、このアーキテクチャは重要なモノリシック アプリケーションを構築する方法として最適です。

モノリシック アプリケーションの場合、アプリケーション コア、インフラストラクチャ、UI の各プロジェクトはいずれも単一のアプリケーションとして実行されます。 ランタイム アプリケーションのアーキテクチャは、図 5-12 のようなものになります。

ASP.NET Core アーキテクチャ 2

図 5-12 ASP.NET Core アプリのランタイム アーキテクチャの例。

クリーン アーキテクチャ内でのコードの整理

クリーン アーキテクチャでは、各プロジェクトが明確な責任を担っています。 そのため、各プロジェクトにはそれぞれ特定の型が属しており、該当するプロジェクトではこれらの型に対応するフォルダーを頻繁に確認できます。

アプリケーション コア

アプリケーション コアでは、エンティティ、サービス、およびインターフェイスが含まれるビジネス モデルを保持します。 これらのインターフェイスには、データ アクセス、ファイル システム アクセス、ネットワーク呼び出しなどのインフラストラクチャを使用して実行される操作のための抽象化が含まれます。このレイヤーで定義されたサービスまたはインターフェイスは場合によって、UI またはインフラストラクチャに対して依存関係を持たない非エンティティ型を操作する必要があります。 これらは単純なデータ転送オブジェクト (DTO) として定義することができます。

アプリケーション コアの種類
  • エンティティ (永続化されたビジネス モデル クラス)
  • インターフェイス
  • Services
  • DTO

インフラストラクチャ

インフラストラクチャ プロジェクトには、通常、データ アクセス実装が含まれます。 代表的な ASP.NET Core Web アプリケーションの場合、これらの実装には Entity Framework (EF) DbContext、定義済みの任意の EF Core Migration オブジェクト、およびデータ アクセス実装クラスが含まれます。 データ アクセス実装コードを抽象化するには、リポジトリ デザイン パターンを使用するのが最も一般的な方法です。

データ アクセス実装に加えて、インフラストラクチャ プロジェクトにはインフラストラクチャの懸念事項とやり取りする必要があるサービスの実装を含める必要があります。 これらのサービスではアプリケーション コアで定義されているインターフェイスを実装する必要があります。そのため、インフラストラクチャにはアプリケーション コア プロジェクトへの参照を含める必要があります。

インフラストラクチャの種類
  • EF Core 型 (DbContextMigration)
  • データ アクセス実装型 (リポジトリ)
  • インフラストラクチャに固有のサービス (FileLoggerSmtpNotifier など)

UI レイヤー

ASP.NET Core MVC アプリケーション内のユーザー インターフェイス レイヤーは、アプリケーションのエントリ ポイントです。 このプロジェクトはアプリケーション コア プロジェクトを参照する必要があり、その型はアプリケーション コアで定義されているインターフェイスを介してインフラストラクチャと厳密にやり取りする必要があります。 UI レイヤーでは、インフラストラクチャ レイヤー型の直接的なインスタンス化や静的呼び出しを許可すべきではありません。

UI レイヤーの型
  • Controllers
  • フィルター
  • Views
  • ViewModels
  • スタートアップ

スタートアップ クラスはアプリケーションの構成と、インターフェイスへの実装型の接続とを担当します。これにより、依存関係挿入は実行時に適切に機能します。

注意

UI プロジェクトの Startup.cs ファイル内の ConfigureServices で依存関係挿入を接続するために、プロジェクトはインフラストラクチャ プロジェクトを参照することが必要な場合があります。 この依存関係を排除するには、カスタム DI コンテナーを使用するのが最も簡単な方法です。 このサンプルの目的を考慮すると、UI プロジェクトでインフラストラクチャ プロジェクトを参照できるようにするのが最も簡単な方法です。

モノリシック アプリケーションとコンテナー

モノリシックに展開された単一の Web アプリケーションまたはサービスを構築し、それをコンテナーとして展開することができます。 アプリケーション内では、それはモノリシックとはならずにいくつかのライブラリ、コンポーネント、またはレイヤーに編成される場合があります。 外部的には、単一のプロセス、単一の Web アプリケーション、または単一のサービスのような単一のコンテナーです。

このモデルを管理するには、アプリケーションを表す単一のコンテナーを展開します。 ロード バランサーを前面に配置してコピーを追加するだけで、スケーリングできます。 単一のコンテナーまたは VM で単一の展開を管理することで、このように簡単になります。

図 5-13

図 5-13 に示すように、複数のコンポーネント/ライブラリ、または内部レイヤーを各コンテナーに含めることができます。 しかし、"コンテナーは 1 つのことを実行し、それを 1 つのプロセスで実行する" というコンテナーの原則に従えば、このモノリシック パターンは矛盾する可能性があります。

このアプローチの欠点は、アプリケーションが大きくなり、スケーリングする必要が出てきた場合に顕著になります。 アプリケーション全体がスケーリングすれば、実際には問題ではありません。 ただし、ほとんどの場合、スケーリングする必要があるネックはアプリケーションの一部であり、他のコンポーネントはそれほど使用されません。

一般的な E コマースを例にとると、スケーリングする必要が生じるのは多くの場合、製品情報のコンポーネントです。 製品を購入するユーザーよりも多くのユーザーが製品を参照します。 より多くの顧客が、支払いパイプラインではなくバスケットを使用します。 コメントを追加したり、購入履歴を表示したりする顧客はそれほどいません。 また、単一のリージョンで、コンテンツとマーケティング キャンペーンを管理する必要がある従業員数は多分、ほんの一握りです。 モノリシック デザインのスケーリングにより、コード全体は複数回展開されます。

"すべてをスケーリングする" 問題に加えて、単一のコンポーネントを変更するには、アプリケーション全体を完全に再テストし、すべてのインスタンスを完全に再展開する必要があります。

モノリシック アプローチは一般的であり、多くの組織が、このアーキテクチャ アプローチによって開発を行っています。 多くの組織が十分に良好な結果を収めている一方で、限界に達している組織もあります。 多くの組織は、このモデルでアプリケーションを設計していました。これは、ツールとインフラストラクチャのせいでサービス指向アーキテクチャ (SOA) の構築が非常に困難だったためと、アプリケーションが大きくなるまで SOA の必要性がわからなかったためです。 モノリシック アプローチの限界に達しているとわかった場合は、コンテナーとマイクロサービスを有効活用できるようにアプリを分割することを次の論理的な手順とすることができます。

図 5-14

Microsoft Azure のモノリシック アプリケーションは、各インスタンスに専用の VM を使用して展開できます。 Azure Virtual Machine Scale Sets を使用すると、VM のスケーリングを簡単に行うことができます。 Azure App Service では、VM の管理を必要とせずに、モノリシック アプリケーションを実行し、インスタンスを簡単にスケーリングすることができます。 Azure App Services では、Docker コンテナーの単一インスタンスも実行できるため、展開が簡単になります。 Docker を使用すれば、1 つの VM を Docker ホストとして展開し、複数のインスタンスを実行できます。 図 5-14 に示すように、Azure バランサーを使用してスケーリングを管理できます。

さまざまなホストへの展開は、従来の展開手法で管理できます。 Docker ホストは、docker run などのコマンドを使用して手動で管理するか、継続的デリバリー (CD) パイプラインなどのオートメーションによって管理できます。

コンテナーとして展開するモノリシック アプリケーション

コンテナーを使用してモノリシック アプリケーションの展開を管理することには利点があります。 コンテナーのインスタンスをスケーリングする処理は、追加の VM を展開するよりもはるかに高速で簡単です。 仮想マシン スケール セットを使用して VM をスケーリングする場合も、インスタンス化には時間がかかります。 アプリのインスタンスとして展開する場合、アプリの構成は VM の一部として管理されます。

更新プログラムを Docker イメージとして展開する方がはるかに高速で、ネットワークの効率が高くなります。 通常、Docker イメージは秒単位で起動するので、ロールアウトが高速になります。 Docker インスタンスの破棄は、docker stop コマンドの発行と同じくらい簡単で、通常は 1 秒未満で完了します。

コンテナーは本質的に設計上、変更不可であるため、VM の破損について心配する必要はありません。一方、更新スクリプトではディスク上に残された特定の構成またはファイルが考慮されない場合があります。

Docker コンテナーは、単純な Web アプリケーションのモノリシックな展開に使用できます。 この方法により継続的な統合と継続的配置のパイプラインがアプリケーション向上し、展開から実稼働を成功に導くのために役立ちます。 "自分のコンピューターでは動作するのに実稼働環境では動作しないのはなぜ" と悩むことがなくなります。

マイクロサービスベースのアーキテクチャには、多くの利点がありますが、それらの利点のために複雑さが増加します。 場合によっては、コストが利点を上回り、1 つのコンテナーまたは少数のコンテナーで実行されているモノリシック展開アプリケーションの方が有効なことがあります。

モノリシック アプリケーションを適切に区切られたマイクロサービスに簡単に分解できない場合があります。 マイクロサービスは相互に独立して起動することで、より回復力のあるアプリケーションを提供します。 アプリケーションの独立した機能のスライスを提供できない場合、分割しても複雑さが増すだけです。

場合によっては、アプリケーションを機能に依存せずに拡張できる必要があります 多くのアプリケーションでは、単一のインスタンスの範囲を超えてスケーリングする必要がある場合、そのインスタンス全体を複製する比較的シンプルなプロセスで行うことができます。 アプリケーションを個別のサービスに分割する追加の作業では、アプリケーションのすべてのインスタンスをスケーリングするのがシンプルかつコスト効率に優れている場合、最小限のメリットしか得られません。

アプリケーション開発の早い段階では、自然の機能的な境界を明確に把握できないことがあります。 最小の実行可能な製品を開発したときには、自然な境界がまだ明らかにならないことがあります。 これらの条件の一部は、一時的な可能性があります。 最初にモノリシック アプリケーションを作成し、後で一部の個別の機能を開発して、マイクロサービスとして展開する場合があります。 その他の条件はアプリケーションの問題の領域に不可欠な場合があります。つまり、このようなアプリケーションが複数のマイクロサービスに分割されることはありません。

多くの個別のプロセスにアプリケーションを分割すると、オーバーヘッドも発生します。 別のプロセスに機能を分離することで、複雑さが増します。 通信プロトコルはより複雑になります。 メソッドの呼び出しではなく、サービス間の非同期通信を使用する必要があります。 マイクロサービス アーキテクチャに移動するきには、eShopOnContainers アプリケーションのマイクロサービス バージョンに実装される多くの構築ブロックを追加する必要があります。つまり、イベント バスの処理、メッセージの回復性と再試行、最終的な整合性などです。

よりシンプルな eShopOnWeb 参照アプリケーションでは、単一コンテナーのモノリシック コンテナーの使用がサポートされます。 このアプリケーションには、従来の MVC ビュー、Web API、Razor Pages が含まれる Web アプリケーションが 1 つ含まれます。 docker-compose build コマンドと docker-compose up コマンドを使用し、ソリューション ルートからこのアプリケーションを起動できます。 このコマンドでは、Web プロジェクトのルートで検出された Dockerfile を使用し、Web インスタンスのコンテナーを構成し、コンテナーを指定のポートで実行します。 GitHub からこのアプリケーションのソースをダウンロードして、ローカルで実行できます。 このモノリシック アプリケーションは、コンテナー環境で展開すると有益です。

1 つは、コンテナー化した展開は、アプリケーションのすべてのインスタンスが同じ環境で実行されることを意味します。 この方法には、初期のテストと開発を行う開発者環境が含まれます。 開発チームは、実稼働環境に一致するコンテナー化した環境でアプリケーションを実行できます。

さらに、コンテナー化アプリケーションは低コストでスケールアウトされます。 コンテナー環境を使用することで、従来の VM 環境よりも多くのリソースを共有できます。

最後に、アプリケーションのコンテナー化は、強制的にビジネス ロジックと記憶域サーバーの間を分離します。 アプリケーションのスケール アウト時には、複数のコンテナーはすべて単一の物理記憶域メディアに移動します。 通常、この記憶域メディアが SQL Server データベースを実行している高可用性サーバーになります。

Docker のサポート

eShopOnWeb プロジェクトは、.NET で実行されます。 そのため、Windows ベースまたは Linux ベースのコンテナーで実行できます。 Docker の展開の場合、SQL Server に同じホストの種類を使用する必要があります。 Linux ベースのコンテナーは、小さなフット プリントが可能なので優先されます。

Visual Studio 2017 以降を使用すれば、Docker サポートを既存のアプリケーションに追加することができます。その場合、ソリューション エクスプローラー でプロジェクトを右クリックし、 [追加] > [Docker サポート] の順に選択します。 この手順により、必要なファイルが追加され、そのファイルを使用するようにプロジェクトが変更されます。 現在の eShopOnWeb サンプルには既にこれらのファイルが用意されています。

ソリューション レベルの docker-compose.yml ファイルには、どのようなイメージをビルドしてどのようなコンテナーを起動するかに関する情報が含まれています。 このファイルでは、docker-compose コマンドを使用し、複数のアプリケーションを同時に起動できます。 この場合、Web プロジェクトのみが起動されます。 別のデータベース コンテナーなど、依存関係を構成する場合にも使用できます。

version: '3'

services:
  eshopwebmvc:
    image: eshopwebmvc
    build:
      context: .
      dockerfile: src/Web/Dockerfile
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
    ports:
      - "5106:5106"

networks:
  default:
    external:
      name: nat

docker-compose.yml ファイルは Web プロジェクトで Dockerfile を参照します。 Dockerfile は、使用される基本コンテナーと、その基本コンテナーでのアプリケーションの構成方法を指定する場合に使います。 WebDockerfile は次のとおりです。

FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
WORKDIR /app

COPY *.sln .
COPY . .
WORKDIR /app/src/Web
RUN dotnet restore

RUN dotnet publish -c Release -o out

FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS runtime
WORKDIR /app
COPY --from=build /app/src/Web/out ./

ENTRYPOINT ["dotnet", "Web.dll"]

Docker に関する問題のトラブルシューティング

コンテナー化アプリケーションを実行すると、それを停止するまで実行し続けます。 docker ps コマンドで実行されているコンテナーを表示することができます。 docker stop コマンドを使用して、コンテナー ID を指定すれば、実行中のコンテナーを停止することができます。

実行中の Docker コンテナーは、開発環境では別の目的で使用を試みる可能性のあるポートにバインドされる場合があることに注意してください。 実行中の Docker コンテナーと同じポートを使用して、アプリケーションの実行やデバッグを試みると、サーバーがそのポートにバインドできないことを示すエラーが表示されます。 繰り返しになりますが、コンテナーを停止すると、問題は解決します。

Visual Studio を使用して、ご利用のアプリケーションに Docker サポートを追加する場合は、その際に Docker Desktop が実行されていることを確認してください。 ウィザードを起動するときに、Docker Desktop が実行されていない場合、ウィザードは正しく実行されません。 さらに、ウィザードでは、正しい Docker のサポートを追加するためにコンテナーの現在の選択について説明します。 Windows コンテナーのサポートを追加する場合は、Windows コンテナーが構成された状態で Docker Desktop が実行されているときに、ウィザードを実行する必要があります。 Linux コンテナーのサポートを追加する場合は、Linux コンテナーが構成された状態で Docker が実行されているときに、ウィザードを実行する必要があります。

参照 – 一般的な Web アーキテクチャ