教學課程:使用 Docker Compose 建立多容器應用程式
在本教學課程中,您將會了解如何在 Visual Studio 中使用容器工具管理多個容器並在容器之間通訊。 管理多個容器需要容器協調流程,而且需要 Docker Compose 或 Service Fabric 之類的協調器。 針對這些程序,您可以使用 Docker Compose。 Docker Compose 很適合用來在開發週期期間進行本機偵錯和測試。
您將在本教學課程中建立的完整範例可在 GitHub 上找到,其位於 https://github.com/MicrosoftDocs/vs-tutorial-samples 的 docker/ComposeSample 資料夾。
必要條件
- Docker Desktop
- 已安裝網頁程式開發、Azure Tools 工作負載和/或 .NET 跨平台開發工作負載的 Visual Studio 2019
- Docker Desktop
- 已安裝網頁程式開發、Azure Tools 工作負載和/或 .NET 跨平台開發工作負載的 Visual Studio 2022。 此安裝包含 .NET 8 開發工具。
建立 Web 應用程式專案
在 Visual Studio Code 中建立名為 WebFrontEnd
的 ASP.NET Core Web 應用程式專案,以建立具有 Razor 頁面的 Web 應用程式。
請勿選取 [啟用 Docker 支援]。 您稍後會在程序中新增 Docker 支援。
注意
在 Visual Studio 2022 17.2 與更新版本中,您可以改為針對此專案使用 Azure Functions。
請勿選取 [啟用 Docker 支援]。 您稍後會在程序中新增 Docker 支援。
建立 Web API 專案
將專案新增至相同的解決方案,並將其命名為 MyWebAPI。 選取 [API] 作為專案類型,並清除 [針對 HTTPS 進行設定] 的核取方塊。 在此設計中,我們僅將 SSL 用於與用戶端之間的通訊,而不是用於相同 Web 應用程式中的容器之間的通訊。 只有 WebFrontEnd
需要 HTTPS,而範例中的程式碼會假設您已清除該核取方塊。 一般而言,Visual Studio 所使用的 .NET 開發人員憑證僅支援外部對容器要求,而不支援容器對容器要求。
將專案新增至相同的解決方案,並將其命名為 WebAPI。 選取 [API] 作為專案類型,並清除 [針對 HTTPS 進行設定] 的核取方塊。 在此設計中,我們僅將 SSL 用於與用戶端之間的通訊,而不是用於相同 Web 應用程式中的容器之間的通訊。 只有
WebFrontEnd
需要 HTTPS,而範例中的程式碼會假設您已清除該核取方塊。 一般而言,Visual Studio 所使用的 .NET 開發人員憑證僅支援外部對容器要求,而不支援容器對容器要求。新增對 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; } } }
服務會在每次存取頁面時遞增計數器,並將計數器儲存在 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(); } }
注意
在真實世界的程式碼中,您不應該在每個要求之後都處置
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 + ")"; }
注意
在 .NET Core 3.1 和更新版本中,您可以使用提供的 WeatherForecast API,而不是這個額外的程式碼。 不過,您必須將 Web API 專案中針對 UseHttpsRedirection 的呼叫註解化,因為此程式碼會使用 HTTP (而不是 HTTPS) 來進行呼叫。
//app.UseHttpsRedirection();
新增 Docker Compose 支援
在
WebFrontEnd
專案中,選擇 [新增] > [容器協調器支援]。 [Docker 支援選項] 對話方塊隨即出現。選擇 [Docker Compose]。
選擇您的目標 OS,例如 Linux。
Visual Studio 會在解決方案的 docker-compose 節點中建立 docker-compose.yml 檔案與 .dockerignore 檔案,且該專案會以粗體字型顯示,表示其為起始專案。
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。
注意
在此步驟中,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 格式顯示天氣資料。
現在假設您只想要將偵錯工具附加至 WebFrontEnd,而不是 Web API 專案。 從功能表列,您可以使用 [開始] 按鈕旁的下拉式清單來顯示偵錯選項功能表;選擇 [管理 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}"; } }
注意
在真實世界的程式碼中,您不應該在每個要求之後都處置
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]。
選擇您的目標 OS,例如 Linux。
Visual Studio 會在解決方案的 docker-compose 節點中建立 docker-compose.yml 檔案與 .dockerignore 檔案,且該專案會以粗體字型顯示,表示其為起始專案。
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。
注意
在此步驟中,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
請確定縮排與其他兩個服務位於相同的層級。
您新增容器協調流程的第一個專案會設定為在執行或偵錯時啟動。 您可以在 docker-compose 專案的 [專案屬性] 中設定啟動動作。 在 docker-compose 專案節點上,以滑鼠右鍵按一下以開啟捷徑功能表,然後選擇 [屬性],或使用 Alt+Enter。 例如,您可以自訂 [服務 URL] 屬性來變更載入的頁面。
請按 F5。 以下是您啟動時所會看到的內容:
您可以使用 [容器] 視窗來監視容器。 如果您沒有看到視窗,請使用搜尋方塊、按 Ctrl+K、Ctrl+O,或按 Ctrl+Q。 在 [功能搜尋] 底下,搜尋
containers
,然後從清單中選擇 [檢視>其他 Windows> 容器]。展開 [解決方案容器] 節點,然後選擇 Docker Compose 專案的節點,以在此視窗的 [記錄] 索引標籤中檢視合併的記錄。
您也可以選取個別容器的節點,以檢視記錄、環境變數、檔案系統和其他詳細資料。
設定啟動設定檔
此解決方案具有 Redis 快取,但每次啟動偵錯工作階段時都重建 Redis 快取容器沒有效率。 若要避免這種情況,您可以設定幾個啟動設定檔。 建立一個設定檔以啟動 Redis 快取。 建立第二個設定檔以啟動其他服務。 第二個設定檔可以使用已在執行的 Redis 快取容器。 您可以從功能表列使用 [開始] 按鈕旁的下拉式清單,來開啟具有偵錯選項的功能表。 選取 [管理 Docker Compose 啟動設定]。
[管理 Docker Compose 啟動設定] 對話方塊隨即出現。 透過此對話方塊,您可以控制在偵錯工作階段期間啟動的服務子集 (其可以在附加或不附加偵錯工具的情況下啟動),以及啟動服務和 URL。 請參閱啟動 Compose 服務的子集 (部分機器翻譯)。
選擇 [新增] 以建立新設定檔,並將其命名為
Start Redis
。 然後將 Redis 容器設定為 [啟動但不偵錯],將另一個維持設定為 [不要啟動],然後選擇 [儲存]。然後,建立另一個不會啟動 Redis,但會啟動其他兩個服務的設定檔
Start My Services
。(選擇性) 建立第三個設定檔
Start All
以啟動所有服務。 您可以針對 Redis 選擇 [啟動但不偵錯]。從主 Visual Studio 工具列的下拉式清單中選擇 [啟動 Redis],按 F5。 Redis 容器會建置並啟動。 您可以使用 [容器] 視窗來查看其正在執行中。 接下來,從下拉式清單中選擇 [啟動我的服務],然後按 F5 來加以啟動。 現在您可以在許多後續的偵錯工作階段中讓 Redis 快取容器保持執行。 每次使用 [啟動我的服務] 時,那些服務都會使用相同的 Redis 快取容器。
恭喜您,您正在執行具有自訂 Docker Compose 設定檔的 Docker Compose 應用程式。
下一步
查看將容器部署至 Azure (部分機器翻譯) 的選項。
另請參閱
Docker Compose (英文)
容器工具 (部分機器翻譯)