教學課程:使用 Docker Compose 建立多容器應用程式
在本教學課程中,您會瞭解如何管理多個容器,並在Visual Studio中使用容器工具時進行通訊。 管理多個容器需要 容器協調流程,而且需要 Docker Compose 或 Service Fabric 等協調器。 針對這些流程,您使用 Docker Compose。 Docker Compose 非常適合在開發周期進行本機偵錯和測試。
您可以在 gitHub 上找到您在本教學課程中建立的完整範例,位於 https://github.com/MicrosoftDocs/vs-tutorial-samples
資料夾中的 。
先決條件
- Docker Desktop
- Visual Studio 2019,並已安裝 Web Development、Azure Tools 工作負載,以及/或 .NET 跨平台開發 工作負載
- Docker Desktop
- 已安裝 Visual Studio 2022,包含 Web 開發、Azure 工具 工作負載和/或 .NET 跨平臺開發 工作負載。 此安裝包含 .NET 8 開發工具。
建立 Web 應用程式專案
在 Visual Studio 中,建立名為 的 WebFrontEnd
專案,以使用 Razor 頁面建立 Web 應用程式。
請勿選取 [啟用 Docker 支援] 這個選項 。 您稍後會在程式中新增 Docker 支援。
請勿選取 [啟用 Docker 支援] 這個選項 。 您稍後會在程式中新增 Docker 支援。
建立 Web API 專案
將一個專案新增到相同的方案中,並將其命名為 MyWebAPI。 選取 [API] 作為專案類型,然後清除 [設定 HTTPS的複選框。 在此設計中,我們只使用 SSL 與客戶端通訊,而不是用於從相同 Web 應用程式中容器之間的通訊。 只有 WebFrontEnd
需要 HTTPS,而範例中的程式代碼會假設您已清除該複選框。 一般而言,Visual Studio 所使用的 .NET 開發人員憑證僅支援外部對容器要求,而不支援容器對容器要求。
將一個專案新增到相同的方案中,並將其命名為 MyWebAPI。 選取 [API] 作為專案類型,然後清除 [設定 HTTPS的複選框。
注意
在此設計中,我們只使用 HTTPS 與用戶端通訊,而不是用於從相同 Web 應用程式中容器之間的通訊。 只有
WebFrontEnd
需要 HTTPS,而範例中的程式代碼會假設您已清除該複選框。 一般而言,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,並在 [控制器] 底下新增檔案,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() { 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,而不是這個額外的程序代碼。 不過,由於程式碼使用 HTTP 而非 HTTPS 進行呼叫,您必須在 Web API 專案中將 UseHttpsRedirection 的呼叫註解掉。
//app.UseHttpsRedirection();
新增 Docker Compose 支援
在
WebFrontEnd
專案中,選擇 新增 > 容器協調器支援。 Docker 支援選項 對話框隨即出現。選擇 Docker Compose。
選擇您的目標OS,例如Linux。
Visual Studio 會在方案中 docker-compose 節點中建立
.dockerignore
檔案和 檔案,而該專案會以粗體字型顯示,其中顯示其為啟始專案。docker-compose.yml 如下所示:
services: webfrontend: image: ${DOCKER_REGISTRY-}webfrontend build: context: . dockerfile: WebFrontEnd/Dockerfile
第一行指定的
version
是 Docker Compose 檔案版本。 您通常不應該變更它,因為工具會使用它來瞭解如何解譯檔案。.dockerignore
檔案包含您不希望 Docker 包含在容器中的檔案類型和擴展名。 這些檔案通常與開發環境和原始檔控制相關聯,而不是您正在開發的應用程式或服務的一部分。查看輸出窗格的 [Container Tools] 區段,以取得執行中命令的詳細數據。 您可以看到命令列工具
docker-compose
用來設定及建立運行時間容器。在 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
您新增容器編排的第一個專案會設定為可在執行或偵錯時啟動。 您可以在 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 專案設定為 Start 但不偵錯,讓 WebFrontEnd 專案保持開始偵錯,然後選擇 [儲存]。新設定被選為下一個 F5的預設值。
按 F5 確認它如您所預期般運作。
恭喜您,您正在執行具有自定義 Docker Compose 設定檔的 Docker Compose 應用程式。
在
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 在未提高許可權的情況下無法存取。
在
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-compose
YML 檔案進行一些變更。 這兩項服務均已包含。services: webfrontend: image: ${DOCKER_REGISTRY-}webfrontend build: context: . dockerfile: WebFrontEnd/Dockerfile mywebapi: image: ${DOCKER_REGISTRY-}mywebapi build: context: . dockerfile: MyWebAPI/Dockerfile
將快取新增至
docker-compose.yml
檔案:redis: image: redis
請確定縮排與其他兩個服務位於相同的層級。
(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 要求。您新增容器編排的第一個專案會設定為可在執行或偵錯時啟動。 您可以在 Docker Compose 專案的 項目屬性 中設定啟動動作。 在 [Docker Compose] 項目節點上,右鍵點擊以開啟操作功能表,然後選擇 [屬性],或使用 [Alt+Enter]。 例如,您可以透過自訂 服務的 URL 屬性來變更加載的頁面。
按 F5。 以下是您在啟動時看到的內容:
您可以使用 [容器] 視窗來監視容器。 如果您沒有看到視窗,請使用搜尋方塊、按 Ctrl Ctrl+K、Ctrl+O,或按 ctrl Ctrl+Q。 在 [功能搜尋]底下,搜尋
containers
,然後從清單中選擇 [檢視>其他 Windows>容器]。展開 [方案容器] 節點,然後選擇您的 Docker Compose 專案的節點,以在此視窗的 [日誌] 標籤中檢視合併的日誌。
您也可以選取個別容器的節點,以檢視記錄、環境變數、文件系統和其他詳細數據。
設置啟動配置檔
此解決方案具有 Azure Cache for Redis,但每次開始偵錯會話時重建快取容器並不有效。 若要避免這種情況,您可以設定幾個啟動設定檔。 建立一個配置檔以啟動 Azure Cache for Redis。 建立第二個使用者帳戶以啟動其他服務。 第二個配置檔可以使用已經執行的快取容器。 從功能表列,您可以使用 [開始] 按鈕旁的下拉式清單來開啟具有偵錯選項的功能表。 選取 [管理 Docker Compose 啟動設定]。
[管理 Docker Compose 啟動設定] 對話框隨即出現。 透過此對話框,您可以控制在偵錯會話期間啟動的服務子集、以及以附加或不附加偵錯工具的方式啟動的服務子集,並管理啟動服務和 URL。 請參閱 啟動 Compose 服務的子集。
選擇 新增 來建立新的設定檔,並將它命名為
Start Redis
。 然後,將 Redis 容器設定為 Start 但不偵錯,將另一個設定為 [不要啟動],然後選擇 [儲存]。然後建立另一個配置檔
Start My Services
,不會啟動 Redis,而是啟動其他兩個服務。(選擇性)建立第三個配置檔
Start All
以啟動所有專案。 您可以選擇 開始 Redis 而不進行偵錯。從主要 Visual Studio 工具列的下拉式清單中,選擇 啟動 Redis。 Redis 容器建置完成後會啟動,且不啟用偵錯模式。 您可以使用 [容器] 視窗來查看其正在執行中。 接下來,從下拉式清單中選擇 [[啟動我的服務],然後按 F5 啟動它們。 現在,您可以讓快取容器在後續的多次除錯會議中持續運行。 每次您使用 啟動我的服務時,這些服務都會使用相同的快取容器。
恭喜您,您正在執行具有自定義 Docker Compose 設定檔的 Docker Compose 應用程式。
後續步驟
查看將 容器部署至 Azure的選項。