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囉。

留言

這個網誌中的熱門文章

使用 Airtable 在小型需求上取代傳統資料庫

使用Semantic Kernel 建立自然語言請假系統

精彩(且驚人)的Semantic Kernel入門範例

在 LINE Bot 開發中使用Semantic Kernel建立自然語言請假系統

專業的價值...