このチュートリアルでは、Visual Studio でコンテナー ツールを使用するときに、複数のコンテナーを管理し、それらの間で通信する方法について説明します。 複数のコンテナーを管理するには 、コンテナー オーケストレーション が必要であり、Docker Compose などのオーケストレーターが必要です。 これらの手順では、Docker Compose を使用します。 Docker Compose は、開発サイクル中のローカル デバッグとテストに最適です。
このチュートリアルで作成した完成したサンプルは、GitHub の docker/ComposeSample https://github.com/MicrosoftDocs/vs-tutorial-samples にあります。
前提 条件
- Docker Desktop
- ASP.NET および Web 開発、Azure 開発ワークロード、.NET クロスプラットフォーム開発ワークロードがインストールされている Visual Studio。 このインストールには、.NET SDK が含まれています。
- Docker Desktop
- ASP.NET および Web 開発、Azure 開発ワークロード、.NET クロスプラットフォーム開発ワークロードがインストールされている Visual Studio。 このインストールには、.NET SDK が含まれています。
Web アプリケーション プロジェクトを作成する
Visual Studio で、という名前の WebFrontEnd プロジェクトを作成し、Razor ページを含む Web アプリケーションを作成します。
[ コンテナーのサポートを有効にする] を選択しないでください。 コンテナーのサポートは、プロセスの後半で追加します。
Web API プロジェクトを作成する
プロジェクトを同じソリューションに追加し、MyWebAPI 呼び出します。 プロジェクトの種類として[API] を選択し、[HTTPS 用に構成する] チェック ボックスをオフにします。
手記
この設計では、クライアントとの通信には HTTPS のみを使用し、同じ Web アプリケーション内のコンテナー間の通信には使用しません。 HTTPS が必要な
WebFrontEndのみであり、この例のコードでは、そのチェック ボックスをオフにしていることを前提としています。 一般に、Visual Studio で使用される .NET 開発者証明書は、コンテナー間要求ではなく、外部からコンテナーへの要求でのみサポートされます。
Azure Cache for Redis のサポートを追加します。 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; } } }このサービスは、ページにアクセスするたびにカウンターをインクリメントし、カウンターをキャッシュに格納します。
Web API を呼び出すコードを追加する
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 ノードに
.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-composeYML ファイルにいくつかの変更を加えます。 これで、両方のサービスが含まれるようになりました。services: webfrontend: image: ${DOCKER_REGISTRY-}webfrontend build: context: . dockerfile: WebFrontEnd/Dockerfile mywebapi: image: ${DOCKER_REGISTRY-}mywebapi build: context: . dockerfile: MyWebAPI/Dockerfiledocker-compose.ymlファイルにキャッシュを追加します。redis: image: redisインデントが他の 2 つのサービスと同じレベルであることを確認します。
(Visual Studio 17.13 以降)依存サービスは、一般的な問題を示しています。 フロントエンドのメイン ページの HTTP 要求は、
mywebapiサービスが Web 要求を受信する準備が整う前に、アプリケーションの起動時に直ちに実行される可能性があります。 Visual Studio 17.13 以降を使用している場合は、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/Counter || 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にデプロイするためのオプションを確認します。 Azure Container Apps にデプロイする準備ができたら、「Azure Container Apps への マルチコンテナー アプリのデプロイ」を参照してください。