次の方法で共有


チュートリアル: 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 2022Web 開発、Azure Tools ワークロードおよび/または .NET クロスプラットフォーム開発 ワークロードがインストールされている場合。 このインストールには、.NET 8 開発ツールが含まれています。

Web アプリケーション プロジェクトを作成する

Visual Studio で、という名前の WebFrontEnd プロジェクトを作成し、Razor ページを含む Web アプリケーションを作成します。

ASP.NET Core Web App プロジェクトの作成を示すスクリーンショット。

[ コンテナーのサポートを有効にする] を選択しないでください。 Docker Compose のサポートは、プロセスの後半で追加します。

Web プロジェクトの作成時の [追加情報] 画面のスクリーンショット。Docker サポートを有効にするオプションが選択されていません。

Docker サポートを有効にするを選択しないでください。 Docker サポートは、プロセスの後半で追加します。

Web プロジェクトの作成時の [追加情報] 画面のスクリーンショット。Docker サポートを有効にするオプションが選択されていません。

Web API プロジェクトを作成する

プロジェクトを同じソリューションに追加し、MyWebAPI 呼び出します。 プロジェクトの種類として[API] を選択し、[HTTPS 用に構成する] チェック ボックスをオフにします。 この設計では、クライアントとの通信には SSL のみを使用し、同じ Web アプリケーション内のコンテナー間の通信には使用しません。 HTTPS が必要な WebFrontEnd のみであり、この例のコードでは、そのチェック ボックスをオフにしていることを前提としています。 一般に、Visual Studio で使用される .NET 開発者証明書は、コンテナー間要求ではなく、外部からコンテナーへの要求でのみサポートされます。

Web API プロジェクトの作成のスクリーンショット。

  1. プロジェクトを同じソリューションに追加し、MyWebAPI 呼び出します。 プロジェクトの種類として[API] を選択し、[HTTPS 用に構成する] チェック ボックスをオフにします。

    手記

    この設計では、クライアントとの通信には HTTPS のみを使用し、同じ Web アプリケーション内のコンテナー間の通信には使用しません。 HTTPS が必要な WebFrontEnd のみであり、この例のコードでは、そのチェック ボックスをオフにしていることを前提としています。 一般に、Visual Studio で使用される .NET 開発者証明書は、コンテナー間要求ではなく、外部からコンテナーへの要求でのみサポートされます。

    Web API プロジェクトの作成のスクリーンショット。

  2. 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";
       });
    
  3. Program.csMicrosoft.Extensions.Caching.DistributedMicrosoft.Extensions.Caching.StackExchangeRedis に using ディレクティブを追加します。

    using Microsoft.Extensions.Caching.Distributed;
    using Microsoft.Extensions.Caching.StackExchangeRedis;
    
  4. Web API プロジェクトで、既存の WeatherForecast.csControllers/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 を呼び出すコードを追加する

  1. 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 要求を実装する」を参照してください。

  2. 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>
    
  3. (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 のサポートを追加する

  1. WebFrontEnd プロジェクトで、[追加] > [コンテナー オーケストレーター サポート] の順に選択します。 Docker サポート オプション ダイアログが表示されます。

  2. Docker Compose を選びます。

  3. ターゲット OS (Linux など) を選択します。

    ターゲット OS の選択のスクリーンショット。

    Visual Studio では、ソリューションの docker-compose ノードに .dockerignore ファイルと ファイルが作成され、そのプロジェクトは太字のフォントで表示され、スタートアップ プロジェクトであることを示します。

    Docker Compose プロジェクトが追加されたソリューション エクスプローラーのスクリーンショット。

    docker-compose.yml は次のように表示されます。

     services:
       webfrontend:
         image: ${DOCKER_REGISTRY-}webfrontend
         build:
           context: .
           dockerfile: WebFrontEnd/Dockerfile
    

    最初の行で指定する version は、Docker Compose ファイル バージョンです。 ファイルの解釈方法を理解するためにツールによって使用されるため、通常は変更しないでください。

    .dockerignore ファイルには、Docker をコンテナーに含めないようにするファイルの種類と拡張子が含まれています。 これらのファイルは、通常、開発中のアプリやサービスの一部ではなく、開発環境とソース管理に関連付けられます。

    実行されているコマンドの詳細については、出力ウィンドウの Container Tools セクションを参照してください。 ランタイム コンテナーの構成と作成に使用 docker-compose コマンドライン ツールを確認できます。

  4. 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
    
  5. コンテナー オーケストレーションを追加する最初のプロジェクトは、実行時またはデバッグ時に起動するように設定されます。 起動アクションは、Docker Compose プロジェクトの プロジェクト プロパティ で構成できます。 Docker Compose プロジェクト ノードで右クリックしてコンテキスト メニューを開き、[プロパティ] 選択するか、Alt キーを押しながら Enter キーを押します。 次のスクリーンショットは、ここで使用するソリューションに必要なプロパティを示しています。 たとえば、サービス URL プロパティをカスタマイズすることで、読み込まれるページを変更できます。

    Docker Compose プロジェクトのプロパティのスクリーンショット。

    起動時に表示される内容は次のとおりです (.NET Core 2.x バージョン)。

    実行中の Web アプリのスクリーンショット。

    .NET 3.1 用 Web アプリでは、JSON 形式で気象データが表示されます。

  6. ここで、デバッガーを Web API プロジェクトではなく WebFrontEnd にアタッチすることだけに関心があるとします。 メニュー バーから、スタート ボタンの横にあるドロップダウン リストを使用して、デバッグ オプションのメニューを表示できます。[Docker Compose 起動設定 管理]を選択します。

    デバッグから Compose 設定の管理のメニュー項目のスクリーンショット。

    Docker Compose 起動設定の管理 ダイアログが表示されます。 このダイアログでは、デバッグ セッション中に起動するサービスのサブセットを制御できます。デバッガーがアタッチされている場合とアタッチされていない場合に起動されるサービスと URL を制御できます。 「Compose サービスのサブセットを開始する」を参照してください。

    Docker Compose 起動設定の管理ダイアログ ボックスのスクリーンショット。

    を選択し、 新規作成を選び、新しいプロファイルを作成して、Debug WebFrontEnd onlyと名前を付けます。 次に、[デバッグなしで開始] するように Web API プロジェクトを設定し、WebFrontEnd プロジェクトはデバッグありで開始するように設定されたままにして、[保存] を選びます。

    新しい構成は、次の F5の既定値として選択されます。

  7. F5 押して、期待どおりに動作することを確認します。

おめでとうございます。カスタム Docker Compose プロファイルを使用して、Docker Compose アプリケーションを実行しています。

  1. 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 を公開します。

  2. 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 のサポートを追加する

  1. WebFrontEnd プロジェクトで、[追加] > [コンテナー オーケストレーター サポート] の順に選択します。 Docker サポート オプション ダイアログが表示されます。

  2. Docker Compose を選びます。

  3. Visual Studio 17.12 以降 WebFrontEnd プロジェクトのスキャフォールディング オプションを選択します。

    WebFrontEnd プロジェクトの [コンテナー スキャフォールディング オプション] ダイアログを示すスクリーンショット。

    Visual Studio 17.11 以前 ターゲット OS (Linux など) を選択します。

    ターゲット OS の選択のスクリーンショット。

    Visual Studio では、ソリューションの docker-compose ノードに .dockerignore ファイルと ファイルが作成され、そのプロジェクトは太字のフォントで表示され、スタートアップ プロジェクトであることを示します。

    Docker Compose プロジェクトが追加されたソリューション エクスプローラーのスクリーンショット。

    docker-compose.yml は次のように表示されます。

     services:
       webfrontend:
         image: ${DOCKER_REGISTRY-}webfrontend
         build:
           context: .
           dockerfile: WebFrontEnd/Dockerfile
    

    .dockerignore ファイルには、Docker をコンテナーに含めないようにするファイルの種類と拡張子が含まれています。 これらのファイルは、通常、開発中のアプリやサービスの一部ではなく、開発環境とソース管理に関連付けられます。

    実行されているコマンドの詳細については、出力ウィンドウの Container Tools セクションを参照してください。 ランタイム コンテナーの構成と作成に使用 docker-compose コマンドライン ツールを確認できます。

  4. 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
    
  5. docker-compose.yml ファイルにキャッシュを追加します。

    redis:
       image: redis
    

    インデントが他の 2 つのサービスと同じレベルであることを確認します。

  6. (Visual Studio 17.13 以降)依存サービスは、一般的な問題を示しています。 フロントエンドのメイン ページの HTTP 要求は、mywebapi サービスが Web 要求を受信する準備が整う前に、アプリケーションの起動時に直ちに実行される可能性があります。 Visual Studio 17.13 以降を使用している場合は、depends_onhealthcheck および 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 要求が正常に処理されるまで開始されません。

  7. コンテナー オーケストレーションを追加する最初のプロジェクトは、実行時またはデバッグ時に起動するように設定されます。 起動アクションは、Docker Compose プロジェクトの プロジェクト プロパティ で構成できます。 Docker Compose プロジェクト ノードで右クリックしてコンテキスト メニューを開き、[プロパティ]を選択するか、Alt+Enterキーを使用します。 たとえば、サービス URL プロパティをカスタマイズすることで、読み込まれるページを変更できます。

    Docker Compose プロジェクトのプロパティのスクリーンショット。

  8. F5 押します。 起動時に表示される内容を次に示します。

    実行中の Web アプリのスクリーンショット。

  9. コンテナー ウィンドウを使用して、コンテナーを監視できます。 ウィンドウが表示されない場合は、検索ボックスを使用するか、Ctrl キー +Kキーを押してください。または、Ctrl キー +Oキー、もしくはCtrl キー +Qキーを押してください。 [機能の検索]containers を検索し、一覧から [表示]>[その他のウィンドウ]>[コンテナー] を選びます。

  10. ソリューション コンテナー ノードを展開し、Docker Compose プロジェクトのノードを選択して、このウィンドウの [ログ] タブに結合されたログを表示します。

    [コンテナー] ウィンドウに [ログ] タブが表示されているスクリーンショット。

    個々のコンテナーのノードを選択して、ログ、環境変数、ファイルシステム、その他の詳細を表示することもできます。

起動プロファイルを設定する

  1. このソリューションには Azure Cache for Redis がありますが、デバッグ セッションを開始するたびにキャッシュ コンテナーを再構築するのは効率的ではありません。 この状況を回避するために、いくつかの起動プロファイルを設定できます。 Azure Cache for Redis を開始するプロファイルを 1 つ作成します。 他のサービスを開始する 2 つ目のプロファイルを作成します。 2 番目のプロファイルでは、既に実行されているキャッシュ コンテナーを使用できます。 メニュー バーから、スタート ボタンの横にあるドロップダウン リストを使用して、デバッグ オプションを含むメニューを開くことができます。 [Docker Compose の起動設定を管理]を選択します。

    デバッグから Compose 設定の管理のメニュー項目のスクリーンショット。

    Docker Compose 起動設定の管理 ダイアログが表示されます。 このダイアログでは、デバッグ セッション中に起動するサービスのサブセットを制御できます。デバッガーがアタッチされている場合とアタッチされていない場合に起動されるサービスと URL を制御できます。 「Compose サービスのサブセットを開始する」を参照してください。

    Docker Compose 起動設定の管理ダイアログ ボックスのスクリーンショット。

    を選択し、 新規作成を選び、新しいプロファイルを作成して、Start Redisと名前を付けます。 次に、Redis コンテナーを [デバッグ せずに開始に設定し、もう一方の設定を 起動しない] のままにして、[保存]選択します。

    Redis サービスのみを開始する Redis プロファイルの作成を示すスクリーンショット。

    次に、Redis を起動せず、他の 2 つのサービスを開始する別のプロファイル Start My Services を作成します。

    他のサービスを開始するサービス プロファイルの作成を示すスクリーンショット。

    (省略可能)すべてを開始する 3 つ目のプロファイル Start All を作成します。 for Redis をデバッグせずに[ 開始]を選択できます。

  2. Visual Studio のメイン ツール バー ドロップダウン リストから [Redis の開始] を選択します。 Redis コンテナーはビルドされ、デバッグなしで開始されます。 コンテナー ウィンドウを使用して、実行中であることを確認できます。 次に、ドロップダウン リストから [Start My Services] を選択し、F5 キー 押して起動します。 これで、後続の多くのデバッグ セッションでキャッシュ コンテナーを実行し続けることができます。 [マイ サービスの開始] 使用するたびに、これらのサービスは同じキャッシュ コンテナーを使用します。

おめでとうございます。カスタム Docker Compose プロファイルを使用して、Docker Compose アプリケーションを実行しています。

次の手順

コンテナーを Azureにデプロイするためのオプションを確認します。 Azure Container Apps にデプロイする準備ができたら、「Azure Container Apps への マルチコンテナー アプリのデプロイ」を参照してください。

関連項目

Docker Compose

コンテナー ツール