Azure DevOps In Action - 設計支援Docker/Container的Pipeline

近幾年Docker/Container技術相當被業界重視,而微軟的 .net 開發技術也適時的支援了容器化的功能。為了實現容器化, .net 開發技術必須支援跨平台,特別是 asp.net,這也造就了 .net core的誕生。

因此,現在您不管用何種開發工具,也可以產出能運行在Linux環境上的asp.net應用程式,這同時也表示,asp.net理所當然的也可以支援Linux Container了。

Docker file

要讓asp.net專案產出支援Docker的image非常簡單,你可以在建立asp.net專案的時候,勾選『啟用Docker』,『Docker OS』選擇Linux:
enter image description here
或者,你也可以在一開始沒有啟用Docker支援的專案中,點選滑鼠右鍵,選擇加入→Docker支援:
enter image description here
Visual Studio會幫你在專案中建立一個類似底下這樣的Docker File:

FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
WORKDIR /src
COPY ["webapp01.csproj", ""]
RUN dotnet restore "./webapp01.csproj"
COPY . .
WORKDIR  "/src/."
RUN dotnet build "webapp01.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "webapp01.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "webapp01.dll"]

這個docker file就是我們用來建立docker image的關鍵。

總的來說,透過asp.net建立一個容器化應用的流程是底下這樣:
enter image description here

asp.net的原始程式碼無須修改,只要加入了docker file,就足以產生docker image,而產生出的docker image,我們需要將其送上Docker Hub(或其他registry,例如azure container registry),以供用戶下載使用。

上面這一段動作,平時大多都可以在Visual Studio中完成。如果你的開發工具是VS Code,那你也可以透過 .net CLI搭配Docker Command來完成。從原始程式碼依照docker file的流程產出image的這個動作我們一般稱為docker build。

Docker task

知道上面的概念後,我們接著來看,現在我們想要實現的,就是在Azure DevOps當中來設計出可以自動完成docker build並且將產出的image推送上docker hub的自動化Pipeline。

其中的關鍵在於『Docker』task:
enter image description here

你可以先透過asp.net core範本建立一個Pipeline,並且在流程中加入Docker task。這個task本身就足以運行docker build與docker push指令:
enter image description here

藉此把產出的image送上docker hub(或azure container resgistry)。

其中有幾個需要稍微說明一下的參數,Container registry的部分,請選擇『New』:
enter image description here

接著,在出現的視窗中,選擇Docker Hub,然後輸入你的Docker ID與密碼即可:
enter image description here

按下Verify之後,系統會驗證你的帳密正確性,如果確定沒有錯誤,你就可以設定一個連線的名稱,然後按下Verify and Save將其儲存:
enter image description here

儲存後,你就可以在Container registry下拉選項中看到該連線項目:
enter image description here

另外,還有幾個你需要注意的選項:
enter image description here

像是 repository 路徑你必須給你在docker hub上所建立的repository名稱(上圖A),而上圖B之中的,則是專案的docker file所在路徑,一般保留上述這樣即可,這表示Pipeline會在專案的所有檔案中搜尋。

而Tags的部分,我們之所以用『$(Build.BuildId)』,是因為這個數字每一次build都不同,這樣如果你要把成品(docker image)上傳到Docker Hub的時候,才不會因為版號相同而有所衝突。

例如,這個建立好的docker image如下:
enter image description here

由於你每次建置的(Build.BuildId)都不會相同,這樣,即便pipeline被多次重覆執行,也不會發生錯誤,而(Build.BuildId)都不會相同,這樣,即便pipeline被多次重覆執行,也不會發生錯誤,而(Build.BuildId)剛好也可以做為類似版號的存在。

若pipeline正確執行,其結果會是:

你會發現,pipeline中的docker push指令順利完成,同時docker hub上的image也更新了一版:
enter image description here

從上面的介紹中你可能也會發現,其實一開始並不一定要使用asp.net core範本來做為pipeline的設計基礎,其實用空的範本(empty)也可以,因為,整個build project與build image的動作,其實都是透過docker task中的指令來完成的,因此,原本asp.net core的那幾個restore/build/pulish動作根本是可以直接槓掉(或移除)的:
enter image description here

只需要透過docker task即可幫我們完成相關的工作。除非您希望在Build Docker Image之前,先進行單元測試,這樣的話,則可以考慮保留asp.net core預設範本中的tasks。

以上,就可以輕鬆的自動化產生docker image並送上registry囉。

留言

這個網誌中的熱門文章

原來使用 .net 寫個 MCP Server 如此簡單

使用LM Studio輕鬆在本地端以API呼叫大語言模型(LLM)

開啟 teams 中的『會議轉錄(謄寫)』與Copilot會議記錄、摘要功能

在VS Code當中使用 Azure DevOps MCP Server

原來使用 .net 寫個 MCP Client 也如此簡單