チュートリアル: Docker Compose を使用して複数コンテナーのアプリを作成する
このチュートリアルでは、Visual Studio でコンテナー ツールを使用しているときに、複数のコンテナーを管理し、それらの間で通信を行う方法について説明します。 複数のコンテナーを管理するには、"コンテナー オーケストレーション" が必要であり、Docker Compose、Service Fabric などのオーケストレーターが必要です。 これらの手順では、Docker Compose を使います。 Docker Compose は、開発サイクル中での、ローカルのデバッグとテストに適しています。
このチュートリアルで作成する完成したサンプルは、GitHub の https://github.com/MicrosoftDocs/vs-tutorial-samples の docker/ComposeSample フォルダーにあります。
前提条件
- Docker Desktop
- Web 開発、Azure Tools ワークロード、 .NET クロスプラットフォーム開発ワークロードのいずれか、またはすべてがインストールされた Visual Studio 2019
- Docker Desktop
- Web 開発、Azure Tools ワークロード、 .NET クロスプラットフォーム開発ワークロードのいずれか、またはすべてがインストールされた Visual Studio 2022。 このインストールには、.NET 8 開発ツールが含まれています。
Web アプリケーション プロジェクトを作成する
Visual Studio で、WebFrontEnd
という名前の [ASP.NET Core Web アプリ] プロジェクトを作成し、Razor Pages を使用した Web アプリケーションを作成します。
[Enable Docker Support](Docker サポートを有効にする) は選択しないでください。 Docker のサポートは、プロセスで後ほど追加します。
Note
Visual Studio 2022 17.2 以降では、代わりにこのプロジェクトに Azure Functions を使用できます。
[Enable Docker Support](Docker サポートを有効にする) は選択しないでください。 Docker のサポートは、プロセスで後ほど追加します。
Web API プロジェクトを作成する
同じソリューションにプロジェクトを追加し、MyWebAPI という名前を付けます。 プロジェクト タイプとして API を選択し、 [HTTPS 用の構成] チェックボックスをオフにします。 この設計では、同じ Web アプリケーション内のコンテナー間の通信ではなく、クライアントとの通信にのみ SSL を使用します。 WebFrontEnd
のみが HTTPS を必要とし、例のコードでは、そのチェックボックスをオフにしていることを前提としています。 一般に、Visual Studio によって使用される .NET 開発者証明書は外部からコンテナーへの要求に対してのみサポートされ、コンテナーからコンテナーへの要求に対してはサポートされません。
同じソリューションにプロジェクトを追加し、WebAPI という名前を付けます。 プロジェクト タイプとして API を選択し、 [HTTPS 用の構成] チェックボックスをオフにします。 この設計では、同じ Web アプリケーション内のコンテナー間の通信ではなく、クライアントとの通信にのみ SSL を使用します。
WebFrontEnd
のみが HTTPS を必要とし、例のコードでは、そのチェックボックスをオフにしていることを前提としています。 一般に、Visual Studio によって使用される .NET 開発者証明書は外部からコンテナーへの要求に対してのみサポートされ、コンテナーからコンテナーへの要求に対してはサポートされません。Redis Cache のサポートを追加します。 NuGet パッケージ
Microsoft.Extensions.Caching.StackExchangeRedis
を取得する (StackExchange.Redis
ではありません)。 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"; });
Program.cs で
Microsoft.Extensions.Caching.Distributed
とMicrosoft.Extensions.Caching.StackExchangeRedis
に 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; } } }
このサービスは、ページにアクセスがあるたびにカウンターを増分し、そのカウンターを Redis キャッシュに格納します。
コードを追加して 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(); } }
Note
実際のコードでは、各要求の後で
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 + ")"; }
Note
.NET Core 3.1 以降では、この追加コードではなく、提供されている WeatherForecast API を使用できます。 ただし、コードでは HTTPS ではなく HTTP を使って呼び出しを行うため、Web API プロジェクトで UseHttpsRedirection の呼び出しをコメントにする必要があります。
//app.UseHttpsRedirection();
Docker Compose のサポートを追加する
WebFrontEnd
プロジェクトで、[追加] > [コンテナー オーケストレーター サポート] の順に選択します。 [Docker サポート オプション] ダイアログが表示されます。[Docker Compose] を選択します。
Linux などのターゲット OS を選択します。
Visual Studio では、docker-compose.yml ファイルと .dockerignore ファイルが、ソリューション内の docker-compose ノードで作成されます。そのプロジェクトは、スタートアップ プロジェクトであることを示す太字のフォントで表示されます。
docker-compose.yml は、次のように表示されます。
version: '3.4' services: webfrontend: image: ${DOCKER_REGISTRY-}webfrontend build: context: . dockerfile: WebFrontEnd/Dockerfile
最初の行で指定されている
version
は、Docker Compose ファイルのバージョンです。 ファイルの解釈方法を理解するためにツールによって使われるため、通常はそれを変更しないでください。.dockerignore ファイルには、Docker によってコンテナーに含める必要のないファイルの種類と拡張機能が含まれます。 これらのファイルは、開発中のアプリまたはサービスの一部ではなく、一般的に、開発環境やソース管理に関連付けられるものです。
実行中のコマンドの詳細については、[出力] ウィンドウの [コンテナー ツール] セクションを参照してください。 コマンドライン ツールの docker-compose が、ランタイム コンテナーの構成や作成に使用されているのが確認できます。
Web API プロジェクトで、プロジェクト ノードを再度右クリックして、 [追加]>[コンテナー オーケストレーター サポート] の順に選択します。 [Docker Compose] を選択し、同じターゲット OS を選択します。
Note
この手順では、Visual Studio によって Dockerfile が作成されます。 既に Docker サポートがあるプロジェクトでこれを行う場合は、既存の Dockerfile を上書きするかどうかを確認するメッセージが表示されます。 保持する Dockerfile に変更を加えた場合は、[いいえ] を選択します。
Visual Studio によって、docker compose YML ファイルにいくつかの変更が加えられます。 これで、両方のサービスが含まれることになります。
version: '3.4' 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() { using (var client = new System.Net.Http.HttpClient()) { // Call *mywebapi*, and display its response in the page var request = new System.Net.Http.HttpRequestMessage(); // webapi is the container name request.RequestUri = new Uri("http://webapi/Counter"); var response = await client.SendAsync(request); string counter = await response.Content.ReadAsStringAsync(); ViewData["Message"] = $"Counter value from cache :{counter}"; } }
Note
実際のコードでは、各要求の後で
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>
このコードを実行すると、Web API プロジェクトから返されたカウンターの値が表示されます。
Docker Compose のサポートを追加する
WebFrontEnd
プロジェクトで、[追加] > [コンテナー オーケストレーター サポート] の順に選択します。 [Docker サポート オプション] ダイアログが表示されます。[Docker Compose] を選択します。
Linux などのターゲット OS を選択します。
Visual Studio では、docker-compose.yml ファイルと .dockerignore ファイルが、ソリューション内の docker-compose ノードで作成されます。そのプロジェクトは、スタートアップ プロジェクトであることを示す太字のフォントで表示されます。
docker-compose.yml は、次のように表示されます。
version: '3.4' services: webfrontend: image: ${DOCKER_REGISTRY-}webfrontend build: context: . dockerfile: WebFrontEnd/Dockerfile
最初の行で指定されている
version
は、Docker Compose ファイルのバージョンです。 ファイルの解釈方法を理解するためにツールによって使われるため、通常はそれを変更しないでください。.dockerignore ファイルには、Docker によってコンテナーに含める必要のないファイルの種類と拡張機能が含まれます。 これらのファイルは、開発中のアプリまたはサービスの一部ではなく、一般的に、開発環境やソース管理に関連付けられるものです。
実行中のコマンドの詳細については、[出力] ウィンドウの [コンテナー ツール] セクションを参照してください。 コマンドライン ツールの docker-compose が、ランタイム コンテナーの構成や作成に使用されているのが確認できます。
Web API プロジェクトで、プロジェクト ノードを再度右クリックして、 [追加]>[コンテナー オーケストレーター サポート] の順に選択します。 [Docker Compose] を選択し、同じターゲット OS を選択します。
Note
この手順では、Visual Studio によって Dockerfile が作成されます。 既に Docker サポートがあるプロジェクトでこれを行う場合は、既存の Dockerfile を上書きするかどうかを確認するメッセージが表示されます。 保持する Dockerfile に変更を加えた場合は、[いいえ] を選択します。
Visual Studio によって、docker compose YML ファイルにいくつかの変更が加えられます。 これで、両方のサービスが含まれることになります。
version: '3.4' services: webfrontend: image: ${DOCKER_REGISTRY-}webfrontend build: context: . dockerfile: WebFrontEnd/Dockerfile mywebapi: image: ${DOCKER_REGISTRY-}mywebapi build: context: . dockerfile: MyWebAPI/Dockerfile
Redis キャッシュを
docker.compose.yml
ファイルに追加します。redis: image: redis
インデントが他の 2 つのサービスと同じレベルであることを確認します。
コンテナー オーケストレーションを追加する最初のプロジェクトは、実行またはデバッグの際に起動されるように設定されます。 docker-compose プロジェクトの [プロジェクトのプロパティ] で、起動アクションを構成できます。 docker-compose プロジェクト ノードで、右クリックしてコンテキスト メニューを開き、 [プロパティ] を選択するか、Alt+Enter キーを押します。 たとえば、[サービス URL] プロパティをカスタマイズすることで読み込まれるページを変更できます。
F5キーを押します。 起動すると、このように表示されます。
[コンテナー] ウィンドウを使ってコンテナーを監視できます。 ウィンドウが表示されない場合は、検索ボックスを使うか、Ctrl+K キー、Ctrl+O キーを押すか、Ctrl+Q キーを押します。 [機能の検索] で
containers
を検索し、一覧から [表示]>[その他のウィンドウ]>[コンテナー] を選びます。[ソリューション コンテナー] ノードを展開し、Docker Compose プロジェクトのノードを選んで、このウィンドウの [ログ] タブにまとめられたログを表示します。
個々のコンテナーのノードを選んで、ログ、環境変数、ファイルシステム、その他の詳細を表示することもできます。
起動プロファイルを設定する
このソリューションには Redis Cache がありますが、デバッグ セッションを開始するたびに Redis キャッシュ コンテナーを再構築するのは効率的ではありません。 それを避けるには、2 つの起動プロファイルを設定できます。 Redis キャッシュを開始するためのプロファイルを 1 つ作成します。 他のサービスを開始するために 2 つ目のプロファイルを作成します。 2 番目のプロファイルでは、既に実行されている Redis Cache コンテナーを使用できます。 メニュー バーから、スタート ボタンの横にあるドロップダウンを使って、デバッグ オプションを含むメニューを開くことができます。 [Docker Compose の起動設定を管理] を選びます。
[Docker Compose 起動設定の管理] ダイアログが表示されます。 このダイアログでは、デバッグ セッションの間に起動されるサービスのサブセット、その起動時にデバッガーをアタッチするかしないか、起動サービスと URL を制御できます。 Compose サービスのサブセットの開始に関するページを参照してください。
[新規] を選んで新しいプロファイルを作成し、「
Start Redis
」という名前を指定します。 次に、Redis コンテナーを [デバッグなしで開始] に設定し、もう一方のコンテナーを [起動しない] のままにして、[保存] を選択します。次に、Redis を開始せず、他の 2 つのサービスを開始する別のプロファイル
Start My Services
を作成します。(省略可能) すべてを開始する 3 つ目のプロファイル
Start All
を作成します。 Redis の [デバッグなしで開始] を選択できます。メイン Visual Studio ツール バーのドロップダウン リストから [Redis を開始する] を選択し、F5 キーを押します。 Redis コンテナーがビルドされ、開始されます。 [コンテナー] ウィンドウを使用して、実行中であることを確認できます。 次に、ドロップダウン リストから [マイ サービスの開始] を選択し、F5 キーを押して起動します。 これで、後続の多くのデバッグ セッションを通じて Redis キャッシュ コンテナーを実行したままにできます。 [Start My Services] (マイ サービスの開始) を使うたびに、それらのサービスで同じ Redis キャッシュ コンテナーが使われます。
お疲れさまでした。これで、カスタム Docker Compose プロファイルを使用して Docker Compose アプリケーションを実行できました。
次のステップ
Azure にコンテナーをデプロイするためのオプションを確認します。