チュートリアル: Docker Compose を使用してマルチコンテナー アプリを作成する
このチュートリアルでは、Visual Studio でコンテナー ツールを使用するときに、複数のコンテナーを管理し、それらの間で通信する方法について説明します。 複数のコンテナーを管理するには、コンテナー オーケストレーション が必要であり、Docker Compose や Service Fabric などのオーケストレーターが必要です。 これらの手順では、Docker Compose を使用します。 Docker Compose は、開発サイクル中のローカル デバッグとテストに最適です。
このチュートリアルで作成した完成したサンプルは、GitHub の docker/ComposeSample フォルダーhttps://github.com/MicrosoftDocs/vs-tutorial-samples
にあります。
前提 条件
- Docker Desktop
- Web 開発、Azure Tools ワークロード、.NET クロスプラットフォーム開発ワークロードのいずれか、またはすべてがインストールされた Visual Studio 2019
- Docker Desktop
- Visual Studio 2022、Web 開発、、Azure Tools ワークロードおよび/または .NET クロスプラットフォーム開発 ワークロードがインストールされている場合。 このインストールには、.NET 8 開発ツールが含まれています。
Web アプリケーション プロジェクトを作成する
Visual Studio で、WebFrontEnd
という名前の ASP.NET Core Web App プロジェクトを作成し、Razor ページを含む Web アプリケーションを作成します。
Docker サポートを有効にするを選択しないでください。 Docker サポートは、プロセスの後半で追加します。
Dockerサポートを有効にするを選択しないでください。 Docker サポートは、プロセスの後半で追加します。
Web API プロジェクトを作成する
プロジェクトを同じソリューションに追加し、MyWebAPI 呼び出します。 プロジェクトの種類として[API] を選択し、[HTTPS 用に構成する] チェック ボックスをオフにします。 この設計では、クライアントとの通信には SSL のみを使用し、同じ Web アプリケーション内のコンテナー間の通信には使用しません。 HTTPS が必要な WebFrontEnd
のみであり、この例のコードでは、そのチェック ボックスをオフにしていることを前提としています。 一般に、Visual Studio で使用される .NET 開発者証明書は、コンテナー間要求ではなく、外部からコンテナーへの要求でのみサポートされます。
プロジェクトを同じソリューションに追加し、MyWebAPI 呼び出します。 プロジェクトの種類として「API 」を選択し、「HTTPS 用に構成する」のチェックボックスをオフにします。
手記
この設計では、クライアントとの通信には HTTPS のみを使用し、同じ Web アプリケーション内のコンテナー間の通信には使用しません。 HTTPS が必要な
WebFrontEnd
のみであり、この例のコードでは、そのチェック ボックスをオフにしていることを前提としています。 一般に、Visual Studio で使用される .NET 開発者証明書は、コンテナー間要求ではなく、外部からコンテナーへの要求でのみサポートされます。Azure Cache for Redis のサポートを追加します。 NuGet パッケージを (
StackExchange.Redis
ではなく)Microsoft.Extensions.Caching.StackExchangeRedis
追加します。 Program.csで、var app = builder.Build()
の直前に次の行を追加します。builder.Services.AddStackExchangeRedisCache(options => { options.Configuration = "redis:6379"; // redis is the container name of the redis service. 6379 is the default port options.InstanceName = "SampleInstance"; });
Microsoft.Extensions.Caching.Distributed
とMicrosoft.Extensions.Caching.StackExchangeRedis
のProgram.cs
に using ディレクティブを追加します。using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Caching.StackExchangeRedis;
Web API プロジェクトで、既存の
WeatherForecast.cs
と Controllers/WeatherForecastController.csを削除し、次の内容を含むファイルを Controllers (CounterController.cs) に追加します。using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Caching.Distributed; using StackExchange.Redis; namespace WebApi.Controllers { [ApiController] [Route("[controller]")] public class CounterController : ControllerBase { private readonly ILogger<CounterController> _logger; private readonly IDistributedCache _cache; public CounterController(ILogger<CounterController> logger, IDistributedCache cache) { _logger = logger; _cache = cache; } [HttpGet(Name = "GetCounter")] public string Get() { string key = "Counter"; string? result = null; try { var counterStr = _cache.GetString(key); if (int.TryParse(counterStr, out int counter)) { counter++; } else { counter = 0; } result = counter.ToString(); _cache.SetString(key, result); } catch(RedisConnectionException) { result = "Redis cache is not found."; } return result; } } }
このサービスは、ページにアクセスするたびにカウンターをインクリメントし、カウンターをキャッシュに格納します。
Web API を呼び出すコードを追加する
WebFrontEnd
プロジェクトで、Index.cshtml.cs ファイルを開き、OnGet
メソッドを次のコードに置き換えます。public async Task OnGet() { ViewData["Message"] = "Hello from webfrontend"; using (var client = new System.Net.Http.HttpClient()) { // Call *mywebapi*, and display its response in the page var request = new System.Net.Http.HttpRequestMessage(); request.RequestUri = new Uri("http://mywebapi/WeatherForecast"); // request.RequestUri = new Uri("http://mywebapi/api/values/1"); // For ASP.NET 2.x, comment out previous line and uncomment this line. var response = await client.SendAsync(request); ViewData["Message"] += " and " + await response.Content.ReadAsStringAsync(); } }
手記
実際のコードでは、すべての要求の後に
HttpClient
を破棄しないでください。 ベスト プラクティスについては、「HttpClientFactory を使用して回復性の高い HTTP 要求を実装する」を参照してください。Index.cshtml
ファイルで、ファイルが次のコードのように表示されるように、ViewData["Message"]
を表示する行を追加します。@page @model IndexModel @{ ViewData["Title"] = "Home page"; } <div class="text-center"> <h1 class="display-4">Welcome</h1> <p>Learn about <a href="/aspnet/core">building Web apps with ASP.NET Core</a>.</p> <p>@ViewData["Message"]</p> </div>
(ASP.NET 2.x のみ) 現在、Web API プロジェクトで、Values コントローラーにコードを追加して、webfrontendから追加した呼び出しに対して API が返すメッセージをカスタマイズします。
// GET api/values/5 [HttpGet("{id}")] public ActionResult<string> Get(int id) { return "webapi (with value " + id + ")"; }
手記
.NET Core 3.1 以降では、この追加コードではなく、提供されている WeatherForecast API を使用できます。 ただし、コードでは HTTPS ではなく HTTP を使用して呼び出しを行うため、Web API プロジェクトで UseHttpsRedirection する呼び出しをコメント アウトする必要があります。
//app.UseHttpsRedirection();
Docker Compose のサポートを追加する
WebFrontEnd
プロジェクトで、[追加] > [コンテナー オーケストレーター サポート] の順に選択します。 Docker サポート オプション ダイアログが表示されます。Docker Compose を選びます。
ターゲット OS (Linux など) を選択します。
Visual Studio では、ソリューションの docker-compose ノードに docker-compose.yml ファイルと
.dockerignore
ファイルが作成され、そのプロジェクトは太字のフォントで表示され、スタートアップ プロジェクトであることを示します。docker-compose.yml は次のように表示されます。
services: webfrontend: image: ${DOCKER_REGISTRY-}webfrontend build: context: . dockerfile: WebFrontEnd/Dockerfile
最初の行で指定する
version
は、Docker Compose ファイル バージョンです。 ファイルの解釈方法を理解するためにツールによって使用されるため、通常は変更しないでください。.dockerignore
ファイルには、Docker をコンテナーに含めないようにするファイルの種類と拡張子が含まれています。 これらのファイルは、通常、開発中のアプリやサービスの一部ではなく、開発環境とソース管理に関連付けられます。実行されているコマンドの詳細については、出力ウィンドウの Container Tools セクションを参照してください。 ランタイム コンテナーの構成と作成に使用
docker-compose
コマンドライン ツールを確認できます。Web API プロジェクトで、プロジェクト ノードを再度右クリックして、[追加]>[コンテナー オーケストレーター サポート] の順に選択します。 Docker Composeを選択し、同じターゲット OS を選択します。
手記
この手順では、Visual Studio によって Dockerfile の作成が提供されます。 Docker が既にサポートされているプロジェクトでこれを行う場合は、既存の Dockerfile を上書きするかどうかを確認するメッセージが表示されます。 保持する Dockerfile に変更を加えた場合は、[いいえ] を選択します。
Visual Studio によって、Docker Compose YML ファイルにいくつかの変更が加わります。 これで、両方のサービスが含まれるようになりました。
services: webfrontend: image: ${DOCKER_REGISTRY-}webfrontend build: context: . dockerfile: WebFrontEnd/Dockerfile mywebapi: image: ${DOCKER_REGISTRY-}mywebapi build: context: . dockerfile: MyWebAPI/Dockerfile
コンテナー オーケストレーションを追加する最初のプロジェクトは、実行時またはデバッグ時に起動するように設定されます。 起動アクションは、Docker Compose プロジェクトの プロジェクト プロパティ で構成できます。 Docker Compose プロジェクト ノードで右クリックしてコンテキスト メニューを開き、[プロパティ] 選択するか、Alt キーを押しながら Enter キーを押します。 次のスクリーンショットは、ここで使用するソリューションに必要なプロパティを示しています。 たとえば、サービス URL プロパティをカスタマイズすることで、読み込まれるページを変更できます。
起動時に表示される内容は次のとおりです (.NET Core 2.x バージョン)。
.NET 3.1 用 Web アプリでは、JSON 形式で気象データが表示されます。
ここで、デバッガーを Web API プロジェクトではなく WebFrontEnd にアタッチすることだけに関心があるとします。 メニュー バーから、スタート ボタンの横にあるドロップダウン リストを使用して、デバッグ オプションのメニューを表示できます。[Docker Compose 起動設定 管理]を選択します。
Docker Compose 起動設定の管理 ダイアログが表示されます。 このダイアログでは、デバッグ セッション中に起動するサービスのサブセットを制御できます。デバッガーがアタッチされている場合とアタッチされていない場合に起動されるサービスと URL を制御できます。 「Compose サービスのサブセットを開始する」を参照してください。
を選択し、 新規作成を選び、新しいプロファイルを作成して、
Debug WebFrontEnd only
と名前を付けます。 次に、[デバッグなしで開始] するように Web API プロジェクトを設定し、WebFrontEnd プロジェクトはデバッグありで開始するように設定されたままにして、[保存] を選びます。新しい構成は、次の F5の既定値として選択されます。
F5 押して、期待どおりに動作することを確認します。
おめでとうございます。カスタム Docker Compose プロファイルを使用して、Docker Compose アプリケーションを実行しています。
WebFrontEnd
プロジェクトで、Index.cshtml.cs ファイルを開き、OnGet
メソッドを次のコードに置き換えます。public async Task OnGet() { // Call *mywebapi*, and display its response in the page using (var client = new System.Net.Http.HttpClient()) { var request = new System.Net.Http.HttpRequestMessage(); // A delay is a quick and dirty way to work around the fact that // the mywebapi service might not be immediately ready on startup. // See the text for some ideas on how you can improve this. // Uncomment if not using healthcheck (Visual Studio 17.13 or later) // await System.Threading.Tasks.Task.Delay(10000); // mywebapi is the service name, as listed in docker-compose.yml. // Docker Compose creates a default network with the services // listed in docker-compose.yml exposed as host names. // The port 8080 is exposed in the WebAPI Dockerfile. // If your WebAPI is exposed on port 80 (the default for HTTP, used // with earlier versions of the generated Dockerfile), change // or delete the port number here. request.RequestUri = new Uri("http://mywebapi:8080/Counter"); var response = await client.SendAsync(request); string counter = await response.Content.ReadAsStringAsync(); ViewData["Message"] = $"Counter value from cache :{counter}"; } }
手記
実際のコードでは、すべての要求の後に
HttpClient
を破棄しないでください。 ベスト プラクティスについては、「HttpClientFactory を使用して回復性の高い HTTP 要求を実装する」を参照してください。指定された URI は、docker-compose.yml ファイルで定義されているサービス名を参照します。 Docker Compose は、一覧表示されているサービス名をホストとして使用して、コンテナー間の通信用の既定のネットワークを設定します。
ここで示すコードは、.NET 8 以降で動作します。これは、管理者特権なしで Dockerfile にユーザー アカウントを設定し、HTTP の既定のポート 80 に昇格された特権なしでアクセスできないため、ポート 8080 を公開します。
Index.cshtml
ファイルで、ファイルが次のコードのように表示されるように、ViewData["Message"]
を表示する行を追加します。@page @model IndexModel @{ ViewData["Title"] = "Home page"; } <div class="text-center"> <h1 class="display-4">Welcome</h1> <p>Learn about <a href="/aspnet/core">building Web apps with ASP.NET Core</a>.</p> <p>@ViewData["Message"]</p> </div>
このコードは、Web API プロジェクトから返されたカウンターの値を表示します。 ユーザーがページにアクセスまたは更新するたびにインクリメントされます。
Docker Compose のサポートを追加する
WebFrontEnd
プロジェクトで、[追加] > [コンテナー オーケストレーター サポート] の順に選択します。 Docker サポート オプション ダイアログが表示されます。[Docker Compose] を選択します。
Visual Studio 17.12 以降 WebFrontEnd プロジェクトのスキャフォールディング オプションを選択します。
Visual Studio 17.11 以前 ターゲット OS (Linux など) を選択します。
Visual Studio では、ソリューションの docker-compose ノードに docker-compose.yml ファイルと
.dockerignore
ファイルが作成され、そのプロジェクトは太字のフォントで表示され、スタートアップ プロジェクトであることを示します。docker-compose.yml は次のように表示されます。
services: webfrontend: image: ${DOCKER_REGISTRY-}webfrontend build: context: . dockerfile: WebFrontEnd/Dockerfile
.dockerignore
ファイルには、Docker をコンテナーに含めないようにするファイルの種類と拡張子が含まれています。 これらのファイルは、通常、開発中のアプリやサービスの一部ではなく、開発環境とソース管理に関連付けられます。実行されているコマンドの詳細については、出力ウィンドウの Container Tools セクションを参照してください。 ランタイム コンテナーの構成と作成に使用
docker-compose
コマンドライン ツールを確認できます。Web API プロジェクトで、プロジェクト ノードを再度右クリックして、[追加]>[コンテナー オーケストレーター サポート] の順に選択します。 Docker Composeを選択し、同じターゲットOSを選択します。
手記
この手順では、Visual Studio によって Dockerfile の作成が提供されます。 Docker が既にサポートされているプロジェクトでこれを行う場合は、既存の Dockerfile を上書きするかどうかを確認するメッセージが表示されます。 保持する Dockerfile に変更を加えた場合は、[いいえ] を選択します。
Visual Studio は、
docker-compose
YML ファイルにいくつかの変更を加えます。 これで、両方のサービスが含まれるようになりました。services: webfrontend: image: ${DOCKER_REGISTRY-}webfrontend build: context: . dockerfile: WebFrontEnd/Dockerfile mywebapi: image: ${DOCKER_REGISTRY-}mywebapi build: context: . dockerfile: MyWebAPI/Dockerfile
docker-compose.yml
ファイルにキャッシュを追加します。redis: image: redis
インデントが他の 2 つのサービスと同じレベルであることを確認します。
(Visual Studio 17.13 以降)依存サービスは、一般的な問題を示しています。 フロントエンドのメイン ページの HTTP 要求は、
mywebapi
サービスが Web 要求を受信する準備が整う前に、アプリケーションの起動時に直ちに実行される可能性があります。 Visual Studio 17.13 以降を使用している場合は、docker-compose.yml でdepends_on
およびhealthcheck
Docker Compose 機能を使用して、プロジェクトを適切な順序で開始し、必要に応じて要求を処理する準備を整えることができます。 Docker Compose - スタートアップ順序を参照。services: webfrontend: image: ${DOCKER_REGISTRY-}webfrontend depends_on: mywebapi: condition: service_healthy build: context: . dockerfile: WebFrontEnd/Dockerfile mywebapi: image: ${DOCKER_REGISTRY-}mywebapi depends_on: redis: condition: service_started healthcheck: test: curl --fail http://mywebapi:8080/ || exit 1 interval: 20s timeout: 20s retries: 5 build: context: . dockerfile: MyWebAPI/Dockerfile redis: image: redis
この例では、正常性チェックでは
curl
を使用して、サービスが要求を処理する準備ができていることを確認します。 使用しているイメージにcurl
がインストールされていない場合は、MyWebAPI Dockerfile のbase
ステージに行を追加してインストールします。 この手順には昇格された特権が必要ですが、インストール後に通常のユーザー特権を復元できます (この例で使用されている Debian イメージの場合)。USER root RUN apt-get update && apt-get install -y curl USER $APP_UID
手記
Alpine のように、
apt-get
をサポートしていない Linux ディストリビューションを使用している場合は、代わりにRUN apk --no-cache add curl
してみてください。これらの Docker Compose 機能には、Docker Compose プロジェクト ファイル (
.dcproj
) のプロパティ設定が必要です。 プロパティDependencyAwareStart
を true に設定します。<PropertyGroup> <!-- existing properties --> <DependencyAwareStart>true</DependencyAwareStart> </PropertyGroup>
このプロパティは、サービス依存関係機能をサポートするデバッグ用にコンテナーを開始する別の方法をアクティブにします。
これらの変更により、
webfrontend
サービスは、mywebapi
が開始され、Web 要求が正常に処理されるまで開始されません。コンテナー オーケストレーションを追加する最初のプロジェクトは、実行時またはデバッグ時に起動するように設定されます。 起動アクションは、Docker Compose プロジェクトの プロジェクト プロパティ で構成できます。 Docker Compose プロジェクト ノードで右クリックしてコンテキスト メニューを開き、[プロパティ]を選択するか、Alt+Enterキーを使用します。 たとえば、サービス URL プロパティをカスタマイズすることで、読み込まれるページを変更できます。
F5 押します。 起動時に表示される内容を次に示します。
コンテナー ウィンドウを使用して、コンテナーを監視できます。 ウィンドウが表示されない場合は、検索ボックスを使用するか、Ctrl キー +Kキーを押してください。または、Ctrl キー +Oキー、もしくはCtrl キー +Qキーを押してください。 [機能の検索] で
containers
を検索し、一覧から [表示]>[その他のウィンドウ]>[コンテナー] を選びます。ソリューション コンテナー ノードを展開し、Docker Compose プロジェクトのノードを選択して、このウィンドウの [ログ] タブに結合されたログを表示します。
個々のコンテナーのノードを選択して、ログ、環境変数、ファイルシステム、その他の詳細を表示することもできます。
起動プロファイルを設定する
このソリューションには Azure Cache for Redis がありますが、デバッグ セッションを開始するたびにキャッシュ コンテナーを再構築するのは効率的ではありません。 この状況を回避するために、いくつかの起動プロファイルを設定できます。 Azure Cache for Redis を開始するプロファイルを 1 つ作成します。 他のサービスを開始する 2 つ目のプロファイルを作成します。 2 番目のプロファイルでは、既に実行されているキャッシュ コンテナーを使用できます。 メニュー バーから、スタート ボタンの横にあるドロップダウン リストを使用して、デバッグ オプションを含むメニューを開くことができます。 [Docker Compose の起動設定を管理]を選択します。
Docker Compose 起動設定の管理 ダイアログが表示されます。 このダイアログでは、デバッグ セッション中に起動するサービスのサブセットを制御できます。デバッガーがアタッチされている場合とアタッチされていない場合に起動されるサービスと URL を制御できます。 「Compose サービスのサブセットを開始する」を参照してください。
新しい を選択して新しいプロファイルを作成し、
Start Redis
と名付けます。 次に、Redis コンテナーを [デバッグ せずに開始に設定し、もう一方の設定を 起動しない] のままにして、[保存]選択します。次に、Redis を起動せず、他の 2 つのサービスを開始する別のプロファイル
Start My Services
を作成します。(省略可能)すべてを開始する 3 つ目のプロファイル
Start All
を作成します。 for Redis をデバッグせずに[ 開始]を選択できます。Visual Studio のメイン ツール バー ドロップダウン リストから [Redis の開始] を選択します。 Redis コンテナーはビルドされ、デバッグなしで開始されます。 コンテナー ウィンドウを使用して、実行中であることを確認できます。 次に、ドロップダウン リストから [Start My Services] を選択し、F5 キー 押して起動します。 これで、後続の多くのデバッグ セッションでキャッシュ コンテナーを実行し続けることができます。 [マイ サービスの開始] 使用するたびに、これらのサービスは同じキャッシュ コンテナーを使用します。
おめでとうございます!カスタム Docker Compose プロファイルで Docker Compose アプリケーションを実行しています。
次の手順
コンテナーを Azureにデプロイするためのオプションを確認します。