共用方式為


教學課程:使用 Docker Compose 建立多容器應用程式

在本教學課程中,您會瞭解如何管理多個容器,並在Visual Studio中使用容器工具時進行通訊。 管理多個容器需要 容器協調流程,而且需要 Docker Compose 或 Service Fabric 等協調器。 針對這些流程,您使用 Docker Compose。 Docker Compose 非常適合在開發周期進行本機偵錯和測試。

您可以在 gitHub 上找到您在本教學課程中建立的完整範例,位於 https://github.com/MicrosoftDocs/vs-tutorial-samples資料夾中的

先決條件

建立 Web 應用程式專案

在 Visual Studio 中,建立名為 WebFrontEnd 專案,以使用 Razor 頁面建立 Web 應用程式。

螢幕快照,其中顯示 [建立 ASP.NET Core Web App 專案]。

請勿選取 [啟用 Docker 支援] 這個選項 。 您稍後會在程式中新增 Docker 支援。

建立 Web 專案時 [其他資訊] 畫面的螢幕快照。未選取 [啟用 Docker 支援] 選項。

請勿選取 [啟用 Docker 支援] 這個選項 。 您稍後會在程式中新增 Docker 支援。

建立 Web 專案時 [其他資訊] 畫面的螢幕快照。未選取 [啟用 Docker 支援] 選項。

建立 Web API 專案

將一個專案新增到相同的方案中,並將其命名為 MyWebAPI。 選取 [API] 作為專案類型,然後清除 [設定 HTTPS的複選框。 在此設計中,我們只使用 SSL 與客戶端通訊,而不是用於從相同 Web 應用程式中容器之間的通訊。 只有 WebFrontEnd 需要 HTTPS,而範例中的程式代碼會假設您已清除該複選框。 一般而言,Visual Studio 所使用的 .NET 開發人員憑證僅支援外部對容器要求,而不支援容器對容器要求。

建立 Web API 項目的螢幕快照。

  1. 將一個專案新增到相同的方案中,並將其命名為 MyWebAPI。 選取 [API] 作為專案類型,然後清除 [設定 HTTPS的複選框。

    注意

    在此設計中,我們只使用 HTTPS 與用戶端通訊,而不是用於從相同 Web 應用程式中容器之間的通訊。 只有 WebFrontEnd 需要 HTTPS,而範例中的程式代碼會假設您已清除該複選框。 一般而言,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.cs 中為 Microsoft.Extensions.Caching.DistributedMicrosoft.Extensions.Caching.StackExchangeRedis新增 using 指示詞。

    using Microsoft.Extensions.Caching.Distributed;
    using Microsoft.Extensions.Caching.StackExchangeRedis;
    
  4. 在 Web API 專案中,刪除現有的 WeatherForecast.csControllers/WeatherForecastController.cs,並在 [控制器] 底下新增檔案,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,而不是這個額外的程序代碼。 不過,由於程式碼使用 HTTP 而非 HTTPS 進行呼叫,您必須在 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
    

    第一行指定的 versionDocker 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. 現在假設您只想要將調試程式附加至 WebFrontEnd,而不是 Web API 專案。 從功能表列,您可以使用 [開始] 按鈕旁的下拉清單以顯示偵錯選項清單。然後選擇 [管理 Docker Compose 啟動設定]

    [偵錯管理撰寫設定] 功能表項的螢幕快照。

    [管理 Docker Compose 啟動設定] 對話框隨即出現。 透過此對話框,您可以控制在偵錯會話期間啟動的服務子集、以及以附加或不附加偵錯工具的方式啟動的服務子集,並管理啟動服務和 URL。 請參閱 啟動 Compose 服務的子集

    [管理 Docker Compose 啟動設定] 對話框的螢幕快照。

    選擇 新增 來建立新的設定檔,並將它命名為 Debug WebFrontEnd only。 然後,將 Web API 專案設定為 Start 但不偵錯,讓 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 中設定用戶帳戶,並公開埠 8080,因為 HTTP 預設埠 80 在未提高許可權的情況下無法存取。

  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
    

    請確定縮排與其他兩個服務位於相同的層級。

  6. (Visual Studio 17.13 或更新版本)相依服務顯示出一個普遍存在的問題。 在 mywebapi 服務準備好接收 Web 要求之前,前端主頁面中的 HTTP 要求可以在應用程式啟動時立即執行。 如果您使用 Visual Studio 17.13 或更新版本,則可以在 depends_on 中使用 Docker Compose 功能 healthcheck,讓專案以正確的順序啟動,並讓這些專案準備好在需要時提供要求。 請參閱 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
    

    注意

    如果您使用Linux發行版,例如Alpine,不支援 apt-get,請嘗試 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 Ctrl+KCtrl+O,或按 ctrl Ctrl+Q。 在 [功能搜尋]底下,搜尋 containers,然後從清單中選擇 [檢視>其他 Windows>容器]

  10. 展開 [方案容器] 節點,然後選擇您的 Docker Compose 專案的節點,以在此視窗的 [日誌] 標籤中檢視合併的日誌。

    顯示檢視 [容器] 視窗中 [記錄] 索引卷標的螢幕快照。

    您也可以選取個別容器的節點,以檢視記錄、環境變數、文件系統和其他詳細數據。

設置啟動配置檔

  1. 此解決方案具有 Azure Cache for Redis,但每次開始偵錯會話時重建快取容器並不有效。 若要避免這種情況,您可以設定幾個啟動設定檔。 建立一個配置檔以啟動 Azure Cache for Redis。 建立第二個使用者帳戶以啟動其他服務。 第二個配置檔可以使用已經執行的快取容器。 從功能表列,您可以使用 [開始] 按鈕旁的下拉式清單來開啟具有偵錯選項的功能表。 選取 [管理 Docker Compose 啟動設定]

    [偵錯管理撰寫設定] 功能表項的螢幕快照。

    [管理 Docker Compose 啟動設定] 對話框隨即出現。 透過此對話框,您可以控制在偵錯會話期間啟動的服務子集、以及以附加或不附加偵錯工具的方式啟動的服務子集,並管理啟動服務和 URL。 請參閱 啟動 Compose 服務的子集

    [管理 Docker Compose 啟動設定] 對話框的螢幕快照。

    選擇 新增 來建立新的設定檔,並將它命名為 Start Redis。 然後,將 Redis 容器設定為 Start 但不偵錯,將另一個設定為 [不要啟動],然後選擇 [儲存]。

    顯示建立僅啟動 Redis 服務的 Redis 配置檔的螢幕快照。

    然後建立另一個配置檔 Start My Services,不會啟動 Redis,而是啟動其他兩個服務。

    顯示建立服務配置檔以啟動其他服務的螢幕快照。

    (選擇性)建立第三個配置檔 Start All 以啟動所有專案。 您可以選擇 開始 Redis 而不進行偵錯

  2. 從主要 Visual Studio 工具列的下拉式清單中,選擇 啟動 Redis。 Redis 容器建置完成後會啟動,且不啟用偵錯模式。 您可以使用 [容器] 視窗來查看其正在執行中。 接下來,從下拉式清單中選擇 [[啟動我的服務],然後按 F5 啟動它們。 現在,您可以讓快取容器在後續的多次除錯會議中持續運行。 每次您使用 啟動我的服務時,這些服務都會使用相同的快取容器。

恭喜您,您正在執行具有自定義 Docker Compose 設定檔的 Docker Compose 應用程式。

後續步驟

查看將 容器部署至 Azure的選項。

另請參閱

Docker Compose

容器工具