チュートリアル: Docker Compose を使用して複数コンテナーのアプリを作成する

このチュートリアルでは、Visual Studio でコンテナー ツールを使用しているときに、複数のコンテナーを管理し、それらの間で通信を行う方法について説明します。 複数のコンテナーを管理するには、"コンテナー オーケストレーション" が必要であり、Docker Compose、Service Fabric などのオーケストレーターが必要です。 これらの手順では、Docker Compose を使います。 Docker Compose は、開発サイクル中での、ローカルのデバッグとテストに適しています。

このチュートリアルで作成する完成したサンプルは、GitHub の https://github.com/MicrosoftDocs/vs-tutorial-samplesdocker/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 アプリケーションを作成します。

Screenshot showing Create ASP.NET Core Web App project.

[Enable Docker Support](Docker サポートを有効にする) は選択しないでください。 Docker のサポートは、プロセスで後ほど追加します。

Screenshot of the Additional information screen when creating a web project. The option to Enable Docker Support is not selected.

Note

Visual Studio 2022 17.2 以降では、代わりにこのプロジェクトに Azure Functions を使用できます。

Screenshot showing Create ASP.NET Core Web App project.

[Enable Docker Support](Docker サポートを有効にする) は選択しないでください。 Docker のサポートは、プロセスで後ほど追加します。

Screenshot of the Additional information screen when creating a web project. The option to Enable Docker Support is not selected.

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

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

Screenshot of creating the Web API project.

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

    Screenshot of creating the Web API project.

  2. 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";
       });
    
  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;
            }
        }
    }
    

    このサービスは、ページにアクセスがあるたびにカウンターを増分し、そのカウンターを Redis キャッシュに格納します。

コードを追加して 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();
        }
     }
    

    Note

    実際のコードでは、各要求の後で 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 + ")";
    }
    

    Note

    .NET Core 3.1 以降では、この追加コードではなく、提供されている WeatherForecast API を使用できます。 ただし、コードでは HTTPS ではなく HTTP を使って呼び出しを行うため、Web API プロジェクトで UseHttpsRedirection の呼び出しをコメントにする必要があります。

          //app.UseHttpsRedirection();
    

Docker Compose のサポートを追加する

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

  2. [Docker Compose] を選択します。

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

    Screenshot of choosing the Target OS.

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

    Screenshot of Solution Explorer with docker-compose project added.

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

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

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

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

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

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

    Screenshot of docker-compose project properties.

    起動時に表示されるものを次に示します (.NET Core 2.x バージョン)。

    Screenshot of running web app.

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

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

    Screenshot of Debug Manage Compose Settings menu item.

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

    Screenshot of Manage Docker Compose Launch Settings dialog box.

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

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

  7. F5 キーを押して、想定どおりに動作することを確認します。

お疲れさまでした。これで、カスタム Docker Compose プロファイルを使用して Docker Compose アプリケーションを実行できました。

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

  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. Linux などのターゲット OS を選択します。

    Screenshot of choosing the Target OS.

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

    Screenshot of Solution Explorer with docker-compose project added.

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

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

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

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

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

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

    redis:
       image: redis
    

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

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

    Screenshot of docker-compose project properties.

  7. F5キーを押します。 起動すると、このように表示されます。

    Screenshot of running web app.

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

  9. [ソリューション コンテナー] ノードを展開し、Docker Compose プロジェクトのノードを選んで、このウィンドウの [ログ] タブにまとめられたログを表示します。

    Screenshot showing viewing the Logs tab in the Containers window.

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

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

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

    Screenshot of Debug Manage Compose Settings menu item.

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

    Screenshot of Manage Docker Compose Launch Settings dialog box.

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

    Screenshot showing creating the Redis profile that starts the Redis service only.

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

    Screenshot showing creating the Services profile that starts the other services.

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

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

お疲れさまでした。これで、カスタム Docker Compose プロファイルを使用して Docker Compose アプリケーションを実行できました。

次のステップ

Azure にコンテナーをデプロイするためのオプションを確認します。

関連項目

Docker Compose
コンテナー ツール