---
# System prepended metadata

title: 'Hands-on : Azure DevOps Service (.NET Core Container)'
tags: [Azure DevOps, Container, MTC 2021, Workshop, .NET Core]

---

###### tags: `Workshop`  `.NET Core` `Azure DevOps` `Container` `MTC 2021`
# Hands-on : Azure DevOps Service (.NET Core Container)
In this workshop you would learn how to accerlate developing .NET core web on Azure App Service.

[TOC]

## 連結既有專案及基本設定
- 進入 [Azure DevOps Service](https://dev.azure.com/)
- 登入先前註冊的帳號
- 查看左下角 **[Organization Setting]**
![](https://i.imgur.com/ZTx67YV.png)
- **[User]** 可以添加組織成員
![](https://i.imgur.com/GHcAIRP.png)
    - **[Permission]** > **[Project Collection Admin]** > **[Add]** 授權此成員可建立 project 的權限
    ![](https://i.imgur.com/gqbYrYW.png)
- 點選 **[Billing]**，選擇 **[Set up billing]**，選擇你要扣款的 Azure 訂閱 (免費試用/MSDN 訂閱不可使用)
- 將 **[Access Level]** 更改為 Stakeholder
![](https://i.imgur.com/lV2bn5d.png)

## 1/ 需求及專案管理
### 建立以 Scrum 為範本的新專案
- 建立新專案：**[首頁](https://dev.azure.com)** > **[+ New Project]**
    ![](https://i.imgur.com/8UouHlu.png)
- 填寫 Project Name，Visibility 選擇 **[Private]**，點開 **[Advanced]**，Work item process 選擇 **[Scrum]**
    ![](https://i.imgur.com/Xu8BMhD.png =400x)
### 邀請使用者加入 Project
- 點選右上角的 [invite]
    ![](https://i.imgur.com/cX2RKwY.png)
- 新增人員完整 email
    ![](https://i.imgur.com/NdBl1TI.png =400x)
- 被加入的人員將會收到 Azure DevOps 的邀請信，首次需透過信中的驗證連結加入
- 畫面下方會顯示成功添加使用者訊息
    ![](https://i.imgur.com/RO7Lojj.png =400x)
- 或在 Members 的欄位中會看到新添加的人員
    ![](https://i.imgur.com/IDT0zlW.png =400x)
### Feature 管理
- 在左方的 Boards 底下，點選 **[Work items]** 後選取 **[+ New Work Item]**，然後選擇 **[Feature]**
    ![](https://i.imgur.com/XhZiLTa.png)
- 填寫 Feature 資訊，參考簡報中的專案，將標題填入 `公車動態`，可自行填寫底下欄位，完成後點選 [Save]
    ![](https://i.imgur.com/26iax0h.png)
- 點選 **[Back to Work Items]**
    ![](https://i.imgur.com/9G7YqJp.png)
- 再新增一個 Feature
    ![](https://i.imgur.com/nMTMrzz.png =400x)
- 填寫 `班次時刻表`
    ![](https://i.imgur.com/V4poO4X.png)
- 點選左邊欄位 Boards 下的 **[Boards]**，將右上角的 **[Backlog items]** 切換到 **[Features]**
    ![](https://i.imgur.com/dHkmlrJ.png)
- 可以看到剛剛新增的兩則功能
    ![](https://i.imgur.com/PKenV51.png)
### Product Backlog Items (PBI) 管理
- 在 `公車動態` 的 Feature 中選取 **[...]**，選擇 **[+ Add Product Backlog Item]**
![](https://i.imgur.com/RPxM8gs.png =500x)
- 填寫 `即時動態查詢`
    ![](https://i.imgur.com/WrsEwhi.png =300x)
- 依照上步驟再填入`出門提醒`
- 在 `班次時刻表` 的 Featue 中依據先前步驟分別新增 PBI `時刻表查詢`和 `搭車提醒`
- 填寫完成
    ![](https://i.imgur.com/HyMLiCq.png =500x)
### Sprint 及 task 規劃
- 選擇左邊欄位中的 **[Backlogs]**
    ![](https://i.imgur.com/XzmVhqI.png)
- 透過 **[+ New Work Item]** 再新增一個`DevOps Workshop` 的 PBI
    ![](https://i.imgur.com/W3SqY0g.png)
- 點選右上角的拉霸圖示，選擇 Side Pane 下的 **[Planning]**
    ![](https://i.imgur.com/MkTDe5K.png)

- 拖曳 `即時動態查詢` 這個 PBI 到右邊的 **[Sprint 1]**
    ![](https://i.imgur.com/tVUeJhj.png)
- 點選 **[Sprint 1]** 跳轉到 Sprint 的頁面
    ![](https://i.imgur.com/q31v7jn.png =400x)
- 點選頁面上方 **[Taskboard]**
    ![](https://i.imgur.com/bJPB1VN.png)
- 可以看到變成敏捷看板的視角，並且是在 Sprint 1 這個週期中
    ![](https://i.imgur.com/wHUyOIG.png)
- 在 `DevOps Workshop` PBI 的欄位點選 **[+]** 來新增以下 :
    - `修改README`
    - `練習 Azure Board`
    ![](https://i.imgur.com/8uUKUKM.png)
- 在 `即時動態查詢` PBI 的欄位點選 **[+]** 來新增以下 task :
    - `整合公車動態即時資訊API`
    - `查詢欄位`
    - `動態資訊呈現頁面`
- 完成填寫
    ![](https://i.imgur.com/FsqRQCV.png)
- 將 `練習 Azure Board` 拖曳到 **[In Progress]** 的欄位
    ![](https://i.imgur.com/dDjLmfb.png)
- 完成狀態的變更
    ![](https://i.imgur.com/wwWnZjx.png)
### 工單搜索功能
- 點選左方欄位 Boards 下的 **[Queries]**，然後點選 **[+ New query]**
    ![](https://i.imgur.com/dvXFo96.png)
- 在 Work Item Type 的地方，Value 選擇 **[Task]**
    ![](https://i.imgur.com/CA8qBz1.png)
- 在 State 的地方，Value 選擇 **[In Progress]**
    ![](https://i.imgur.com/fxSpxKr.png)
- 點選 **[Run query]**
    ![](https://i.imgur.com/mFgWA66.png)
- 執行後的結果會顯示目前在 project 中哪些 task 狀態為 in progress
    ![](https://i.imgur.com/D739m61.png)
- 點選 **[Save query]**
    ![](https://i.imgur.com/MuXQwj2.png)
- 完成欄位填寫，將 **[Floder]** 選擇到 **[Shared Queries]**，點選 **[OK]** 即可儲存
    ![](https://i.imgur.com/jl58Mrq.png =400x)

## 2/ 版本控制
### 匯入範例程式碼
- 點選左方欄位 Repo 底下的 **[Files]**，點選頁面中的 **[Import]**
    ![](https://i.imgur.com/YKFDeYX.png)
- 複製以下連結貼到 **[Clone URL]** 中
    ```
    https://github.com/huier23/AspNetCoreSample.git
    ```
- 完成後點選 **[Import]**
    ![](https://i.imgur.com/sTGcm4H.png =350x)
- 顯示正在進行匯入
    ![](https://i.imgur.com/N1bJUgO.png)
- 完成後會看到成功畫面並且跳轉到匯入的程式碼
    ![](https://i.imgur.com/RAwPZ0c.png)

### Pull Request 練習
- 點選頁面上方的 **[master]**，點選 **[+ New Branch]**
    ![](https://i.imgur.com/elZK7AB.png)
- 建立一個 `dev` 分支，點選 **[create]**
    ![](https://i.imgur.com/FhQrorK.png =350x)
- 建立完成後會看到上方分支已經切換到 `dev`
    ![](https://i.imgur.com/mUuGRDb.png)
- 修改 **[README]** 檔案
    ![](https://i.imgur.com/yAmLjKK.png)
- 點選 **[Edit]** 可以開始修改
    ![](https://i.imgur.com/o71lfPC.png)
- 在文件中最下方填入任意文字，這邊示範填入 `## pull request teset`，然後點選右上角 **[commit]**
    ![](https://i.imgur.com/AzKl9AH.png)
- 會跳出 Commit 視窗，點選 **[Search work items by ID or title]**，尋找到先前建立的 task `修改 README`，完成後點選下方的 **[Commit]**
    ![](https://i.imgur.com/FMLjNrA.png =400x)
- 點選左方選單 Repos 下的的 **[Commits]** 可以查看程式碼的歷史 commit 紀錄
    ![](https://i.imgur.com/YzRukzB.png)
- 點選左方選單 Repos 下的的 **[Branches]** 可以查看程式碼的分支紀錄
    ![](https://i.imgur.com/HJX6EDK.png)
- 點選左方選單 Repos 下的的 **[Pull Request]**，點選上方通知訊息條的 **[Create a pull request]**
    ![](https://i.imgur.com/urUGwfO.png)
- 確認是從 `dev` 合併到 `master`
    ![](https://i.imgur.com/aPR2Whu.png =450x)
- 在 **[Reviewers]** 的欄位搜尋並選擇自己
    ![](https://i.imgur.com/MVPl2CE.png =400x)
- 點選 **[Create]**
    ![](https://i.imgur.com/PwSCVVO.png =400x)
- 接著會跳轉到 pull request 的 review 畫面，點選右上角的 **[Approve]**
    ![](https://i.imgur.com/MAEeMQX.png)
- 點選旁邊的 **[Complete]**
    ![](https://i.imgur.com/VksU22p.png)
- 確認 **[Delete dev after merging]** 是勾選狀態，並點選下方的 **[Complete merge]**
    ![](https://i.imgur.com/AqbSHI9.png =350x)
- 完成畫面
    ![](https://i.imgur.com/qtVhbUi.png)
- 回到 **[Files]**，查看 **[README]**
    ![](https://i.imgur.com/dkeemQb.png)
- 在 master 上，已經更新為剛剛的修改的版本
    ![](https://i.imgur.com/r9dzXsg.png)

## 3/ 建立 Azure 上 Azure Container Registry 資源
- 連結到 **[Azure Portal](https://portal.azure.com/)**
- 上方的搜尋列中搜尋 `Container Registry`，點選下方搜尋結果 **Container registries**
    ![](https://i.imgur.com/qUVNojG.png)
- 點選 **[+ Create]**
    ![](https://i.imgur.com/vwfEp89.png)
- 在 Resource Group 的欄位點選 **[+ Create New]**，自行填入要命名的資源群組名稱
    ![](https://i.imgur.com/gQHKWPp.png)
- 將其餘資訊填寫完成，**[SKU]** 選擇為 **standard**，最後選擇 **Review + create**
    ![](https://i.imgur.com/zFbXDpb.png)
- 確認資訊沒問題，選擇 **Create**
    ![](https://i.imgur.com/7WhRH33.png =550x)
- 完成後到建立好的 Container Registry 資源，點選 **Overview** 中的 **[Update]**
![](https://i.imgur.com/pr5xkV4.png)
- 將 **Admin User** 更改為 **Enable** 後 Save
![](https://i.imgur.com/MfY5Z5R.png =450x)

## 4/ 建立 Build Pipeline
### 建立程式碼的第一條 Build Pipeline
- 選擇左方選單列中 Pipelines 下的 **[Pipelines]**，點選 **[Create Pipeline]**
    ![](https://i.imgur.com/5RQojNb.png)
- 選擇畫面下方說明文字中的 **[Use the classic editor]**
    ![](https://i.imgur.com/9FycaSt.png =400x)
- 選擇程式碼來源及分支，這裡無須特別操作，直接可以選擇 Continue
    ![](https://i.imgur.com/Tc0zfsc.png)
- 在右上方的搜尋欄位尋找 `docker`，找到 **Docker Container**，點選 **[Apply]**
    ![](https://i.imgur.com/MWxKFga.png)
<!-- - 點選在 **Agent Job 1** 旁邊的 **+**，選到第一個 **.NET Core** 按 **[Add]**
    ![](https://i.imgur.com/iwoeK5H.png)
- 將 .NET Core 的 task 長按，用拖移方式移動到第一位
    ![](https://i.imgur.com/2vsbjFM.png =450x)
- 修改 .NET Core task 的內容
    - **Command** : **test**
    - **Path to project(s)** : `**/**.UnitTest/**.csproj`
    ![](https://i.imgur.com/7RT1rbm.png) -->
- 選到 Build an image，完成內容
    - **Azure Subscription** : **<建立 ACR 資源時使用的訂閱>**
    - **Azure Container Registry** : **<建立的 ACR 名稱>**
    - **Docker File** : 選擇 Dockerfile 檔案
    - **Image Name** : `$(Build.Repository.Name):$(Build.BuildNumber)`
    ![](https://i.imgur.com/lBrYaSG.png)
- 選到 Push an image，完成內容
    - **Azure Subscription** : **<建立 ACR 資源時使用的訂閱>**
    - **Azure Container Registry** : **<建立的 ACR 名稱>**
    - **Docker File** : 選擇 Dockerfile 檔案
    - **Image Name** : `$(Build.Repository.Name):$(Build.BuildNumber)`
    ![](https://i.imgur.com/jqARmHo.png)
- 選擇 **Pipeline** 的地方，將 **Agent Specification** 選到 **Ubuntu-20.04**
- 選擇上方列表的 **[Triggers]** tab，將畫面右方的 [Enable continuous integration] 打勾
    ![](https://i.imgur.com/LfSoWnh.png)
- 完成後點選上方的 **[Save & queue]** ，選擇 **[Save & queue]** 後在跳出的視窗點選 **[Save and run]**
    ![](https://i.imgur.com/BMzuHxx.png)

<!-- 
### 紀錄 Bug
- 執行到一半會發現顯示錯誤
    ![](https://i.imgur.com/KuZdY5f.png)
- 點選上方 **[Tests]** 的 tab，點選下方 **[IndexPageTest]** 後會看到 Error message 顯示為： *`Assert.AreEqual failed. Expected:<DevOps Workshop>. Actual:<Success!>.`*
    ![](https://i.imgur.com/jhc0hr8.png)
- 將錯誤訊息是窗關閉，點選頁面中 **[Bug]** 的按鈕，選擇 **[Create Bug]**
    ![](https://i.imgur.com/oCtD2Yz.png)
- 詳細錯誤訊息已自動帶入，點選 Related Work 欄位中的 **[+ Add link]** 並選擇 **[Existing item]**
    ![](https://i.imgur.com/Y79oia1.png)
- Link Type 選擇 **[Parent]**，Work items to link 選擇剛剛建立的 **[DevOps Workshop]** PBI
    ![](https://i.imgur.com/0vBFIpB.png =400x)
- 點選 **[Save & Close]**
    ![](https://i.imgur.com/gf4HKTt.png)
- 點選左方選單的 **[Sprints]** 在剛剛建立的 Bug 那欄點選 **[+]**
    ![](https://i.imgur.com/73OS5KM.png)
- 填入標題 `更正標題為 DevOps Workshop` 
    ![](https://i.imgur.com/80pkpLD.png)
- 點選剛剛建立的 task ，將以下資訊填寫到 Description，然後點選 **[Save & Close]**
    ```
    修改 Controllers / HomeController.cs 將標題修正
    ```
    ![](https://i.imgur.com/SwwqoKO.png)
### 修復 Bug
- 回到 Files ，點選到 *AspNetCore.Sample.Web* > *Controllers* > *HomeController.cs*
    ![](https://i.imgur.com/Vn6fUgd.png)
    ![](https://i.imgur.com/eHlVODE.png)
    ![](https://i.imgur.com/vGNTcS4.png)

- 修改第 13 行，將原本的 "Success!" 修改為 "DevOps Workshop"
    ```csharp=11
            public IActionResult Index()
            {
                ViewData["Message"] = "DevOps Workshop";

                return View();
            }
    ```
- 修改完成後點選右上方的 Commit
    ![](https://i.imgur.com/PwrY0Jj.png)
- **[Work items to link]** 欄位選擇先前建立的 `更正標題為 DevOps Workshop` task
    ![](https://i.imgur.com/XyEYC0U.png =300x)
- 此時回到 **[Pipeline]** 發現 pipeline 已自動執行，點選 pipeline
    ![](https://i.imgur.com/LZii14l.png)
- 可看到有兩次執行紀錄，點選最新一次的執行紀錄
    ![](https://i.imgur.com/vv4f89q.png)
- 可以查第二次執行的內容，點選 **[Agent Job]**
    ![](https://i.imgur.com/qL3nYOI.png)
- 可以查看各個 task 的 Log 細節
    ![](https://i.imgur.com/i4v7XY3.png)
 -->
## 5/ 建立 Azure 上 App Service 資源
- 回到首頁左方的選單列表，找到 App Service 並點選
    ![](https://i.imgur.com/oWHoffv.png)
- 點選 **[+ Create]**
    ![](https://i.imgur.com/iuuYM0x.png)
- 在 Resource Group 的欄位選擇和建立 Container Registry 時同一個資源群組
- 將其餘資訊填寫完成
    - **Publish** : Docker Container
    - **Region** : Southeast Asia
    - **Linux Plan (Southeast Asia)** 的欄位點選 **[Create new]**，並輸入自行定義的名稱
    ![](https://i.imgur.com/bhZdSze.png =600x)
    - **Pricing plan** 欄位點選 **[Explorer pricing plans]**
    ![](https://i.imgur.com/yiw1Ppc.png)
    - 選擇 **Standard S1** 後點擊 **[Select]**
    ![](https://i.imgur.com/V1Qo227.png)
<!--     - Sku and size 欄位點選 **[Change size]**
    ![](https://i.imgur.com/jbcFGqT.png)
    - 在跳出的視窗選擇 **[Production]**，規格選擇 **[S1]**
    ![](https://i.imgur.com/45SS5Fx.png =500x) -->
- 完成後點選下方 **[Next: Docker >]** 的按鈕
- 將以下資訊填寫完成，完成後點選下方 **[Review + Create]**
    - **Image Source** : Azure Container Registry
    - **Registry** : (選擇先前建立的 Container Registry)
    - **Image** : (唯一選擇)
    - **Tag** : (唯一選擇)
    - **Satrup Command** : (留白即可)
    ![](https://i.imgur.com/gq06w9K.png)
- 接下來會進入 review 的頁面，點選 **[Create]**
    ![](https://i.imgur.com/IZ45ukV.png =400x)
- 建立完成後會挑轉到資源正在建立中的頁面，先不要關閉
### 利用 App Service 建立多個部屬環境
- 建立完成後會顯示資源已建立完成，點選 **[Go to resource]**
    ![](https://i.imgur.com/D7jlAEV.png)
- 選擇 App Service 左方選單中 Deployment 區塊中的 **[Deployment Slots]**
    ![](https://i.imgur.com/O9O4yt3.png)
- 點選上方的 [Add Slot]，將 slot 的名稱設定為 `dev`，點選 **[Add]** 添加，並將 `Clone settings from` 的來源設定為 Production
    ![](https://i.imgur.com/uWnFUUE.png)
<!--     ![](https://i.imgur.com/6LoTLtb.png) -->
- 出現 *Successfully created slot 'dev'* 的訊息後，點選 **[Close]**
    ![](https://i.imgur.com/4v9utAy.png =350x)

## 6/ 建立 Release Pipeline
### Dev 環境
- 在左方選單列選擇 Pipelines 下的 **[Release]**，進入後點選 **[New Pipeline]**
    ![](https://i.imgur.com/WgaXG4O.png)
- 找到 **[Azure App Service deplotment]**，點選 **[Apply]**
    ![](https://i.imgur.com/6Nf89s0.png)
- 將 Stage name 更改為 `Dev`，完成後點選 **[X]** 關閉視窗
    ![](https://i.imgur.com/xk1WJby.png)
- 選擇 `Dev` stage 內的 **[1 job, 1 task]**
    ![](https://i.imgur.com/QNhDTaH.png)
- Azure Subscription 的部分選擇建立 App Service 資源時所選擇的訂閱，選擇完成後點選藍色的 **[Authorize]** 按鈕
    ![](https://i.imgur.com/Ehvc6TA.png)
- 在 **[App Type]** 選擇 **Web App for Containers (Linux)**
    ![](https://i.imgur.com/poRMy4Q.png)
- 等待授權完成，在 App Service name 找到剛剛建立的 App Serivce 資源，**Registry or Namespace** 填入`<Azure Container Registry Name>.azurecr.io` (Azure Container Registry Name 為先前建立的 ACR 資源)
    - 可在 Azure Portal 上，建立的 ACR 資源 Overview 中找到 **Login Server**
    ![](https://i.imgur.com/TvX5X9a.png)
    - 複製並填入為 Registry
    ![](https://i.imgur.com/97zdUe9.png)
<!-- - Tag 設定為 `$(Release.Artifacts.<source-alias>.BuildId)` -->
- 在 Azure Portal 上的 Container Registry 資源中，左方欄位 [Repository] 找到要使用的 image 的 repository name
    ![](https://i.imgur.com/VqragNA.png)
- 回到 Azure DevOps 將 **[Repository]** 填入 repository name
    ![](https://i.imgur.com/L6PR0Pf.png)
- 點選 **[Deploy Azure App Service]** 這個 task，將右邊欄位中的 **[Deploy to Slot or App Service Environment]** 打勾，Reource Group 選擇 App Service 的資源群組 (應該只會有一個)，Slot 的部分將 Production 更改為 **[dev]**
    ![](https://i.imgur.com/u0jSs8C.png)
- 完成後點選右上角的 **[Save]**，點選 **[OK]**
    ![](https://i.imgur.com/hPwuEcL.png)
### Production 環境
- 選擇上方列表的 **[Pipeline]** 列表
    ![](https://i.imgur.com/LOYG6wr.png)
- 將鼠標移動到 **[Dev]** stage，會出現 **[+]**，點選添加一個新的 stage
    ![](https://i.imgur.com/w78mFR2.png =400x)
- 選擇在 select a template 底下的 **[Empty job]**
    ![](https://i.imgur.com/WpNMcqK.png)
- 將 stage 名稱更改為 `Production`，完成後點選 **[X]** 關閉
    ![](https://i.imgur.com/RC0VFpC.png)
- 點選 Production 的 **[1 job, 0 task]**
    ![](https://i.imgur.com/HragtQy.png)
- 點選在 Agent Job 中的 **[+]**
    ![](https://i.imgur.com/ylPY0hB.png)
- 在 Add tasks 中選到 **[Deploy]**，找到 **[Azure App Service manage]**，點選 **[Apply]**
    ![](https://i.imgur.com/DRrofPP.png)
- 點選 **[Swap Slots:]** task，將欄位資訊填寫完整
    - **Azure Subscription** : 建立 App Service 的訂閱
    - **Action** : Swap Slots
    - **App Service Name** : 建立的 App Service 名稱
    - **Resource Group** : 建立的 App Service 資源群組
    - **Source Slot** : dev
    - 確保 **[Swap with Production]** 打勾
    ![](https://i.imgur.com/RgXJlRD.png)
- 點選右上角的 **[Save]**，然後 **[OK]**
- 點選上方列表的 **[Pipeline]**
![](https://i.imgur.com/12aMrEF.png)

### 細節調整
- 點選在 Artifacts 方格中的 **[+ Add an artifact]**
    - **Source type** : Build
    - **Source (build pipeline)** : 先前建立的 build pipeline
    ![](https://i.imgur.com/PezUOlp.png)
- 選擇完成後點選 **[Add]**
- 點選上步驟建立的來源方框中右上角的閃電符號，在 Continuous deployment trigger 下將 **[Disable]** 更改為 **[Enable]**，完成後點選 **[X]** 關閉視窗 
    ![image](https://hackmd.io/_uploads/rJQbu-Ym0.png)
<!-- - 點選 Artifacts | + Add 的 **[+Add]** 再添加一個來源，選擇 **[6 more artifact types]** 展開
![](https://i.imgur.com/m0PV4Zm.png) -->
<!-- - 點選在 Artifacts 方格中的 **[+ Add an artifact]**，選擇 **[6 more artifact types]** 展開
    ![](https://i.imgur.com/Y2poTjq.png)
- 選擇 **[Azure Container Registry]**，將下方欄位根據先前建立的資源依序填寫完成以連結至現有的 Azure Container Registry 資源，最後點選 **[+Add]** 添加完成
![](https://i.imgur.com/mmHUSrO.png =400x) -->
<!-- - 點選上步驟建立的 Azure Container Registry 來源方框中右上角的閃電符號，在 Continuous deployment trigger 下將 **[Disable]** 更改為 **[Enable]**，完成後點選 **[X]** 關閉視窗 
    ![](https://i.imgur.com/XXQ2SWi.png) -->
- 在 Dev 的 stage 中點選右邊的人頭，在跳出的視窗中將 **[Post-deployment approvals]** 改為 **[Enabled]**，並在 **[Approvers]** 欄位中選擇自己，完成後點選 **[X]** 關閉視窗
    ![](https://i.imgur.com/keQT29v.png)
- 在 Production 的 stage 中點選左邊的人頭，在跳出的視窗中將 **[Pre-deployment approvals]** 改為 **[Enabled]**，並在 **[Approvers]** 欄位中選擇自己，完成後點選 **[X]** 關閉視窗
    ![](https://i.imgur.com/YyaQCul.png)
- 將上方 All Pipelines > **[New release pipeline]** 修改為 `Release to Azure`
    ![](https://i.imgur.com/15nHnUX.png)
- 點選到上方列表的 **[Options]**，點擊到 **[Integrations]** 的欄位，將以下兩項目打勾
    - [x] Report deployment status to Work
    - [x] Report deployment status to Boards
        - **Dev** > Testing
        - **Production** > Production
    ![](https://i.imgur.com/2ZAvW6B.png)
- 點選回 **[Pipeline]**
    ![](https://i.imgur.com/vzcj5bT.png)
- 點選 Save
    ![](https://i.imgur.com/D0M5YSK.png)
- 接著選擇 **[Create Release]**
    ![](https://i.imgur.com/5HZ9JKX.png)
- 在跳出的視窗中點選 **[Create]**
    ![](https://i.imgur.com/ZwQkgI9.png =400x)
- 視窗上方會有一則訊息，點選 **[release 1]**，可以查看目前部屬進度
    ![](https://i.imgur.com/9gahL01.png)
### 環境驗證及審核
- 當 Dev stage 的部署狀態變更為 *Pending approval* 時(如一直未改變狀態可點選 **[Refresh]** 更新狀態)，此時回到 **[Azure Portal](https://portal.azure.com)** 上，找到剛剛建立的資源群組，選擇 type 為 *App Service (slot)* 的 **dev** 資源 
    ![](https://i.imgur.com/r8wYHba.png)
- 選擇頁面中 URL 的連結
    ![](https://i.imgur.com/TwlsIzx.png)
- 顯示新的網頁已經完成部署
    ![](https://i.imgur.com/2ArwLxS.png)
<!-- - 將網址列中的 `-dev` 拿掉，進入網頁
    ![](https://i.imgur.com/IWhZMYX.png =400x)
- Production 的環境尚未部屬，仍在舊的頁面
    ![](https://i.imgur.com/GQrDO4R.png) -->
- 已確認在 Dev 環境中部署正確，回到 Azure DevOps 中點選 Dev stage 的 **[Approve]**
    ![](https://i.imgur.com/WXbnlmc.png)
- 在跳出的視窗點選 **[Approve]**，然後 **[X]** 關閉
    ![](https://i.imgur.com/tpuVc0E.png)
- 確認 Dev 完成
    ![](https://i.imgur.com/HiNQ8TU.png)
- 此時 Prodction 的狀態也會變更為 pending approval，點選 **[Approve]** 開始進行 Production 的部屬
    ![](https://i.imgur.com/gNqBKtc.png)
- 確認 Production 的部署正確

## 7/ 實際更新上版一次
- 回到 **[Pipelines]**，點選先前建立的 build pipeline
    ![](https://i.imgur.com/i1xIKuH.png)
- 進入後點選右上角的 **[Edit]**
    ![](https://i.imgur.com/vdOW7Sj.png)
- 將鼠標移動到 **[dotnet test]** task 按右鍵，選擇 **[Disable selected task(s)]**，點選 **[Save]**
    ![](https://i.imgur.com/C6iA0v7.png)
- 回到 Sprints，在 **[DevOps Workshop]** 的 PBI 中，新增一個 task 為 `將首頁標題添加今天日期`
    ![](https://i.imgur.com/VKgqjWY.png)
- 回到 Files ，點選到 *AspNetCore.Sample.Web* > *Controllers* > *HomeController.cs*
- 修改第 13 行，將原本的 "DevOps Workshop" 修改為 "DevOps Workshop - 0701"，修改完成後點選 **[Commit]**
    ```csharp=11
            public IActionResult Index()
            {
                ViewData["Message"] = "DevOps Workshop - 0701";

                return View();
            }
    ```
    ![](https://i.imgur.com/JH6GLku.png)

- **[Work items to link]** 欄位選擇先前建立的 `將首頁標題添加今天日期` task
    ![](https://i.imgur.com/l1v6nUX.png =400x)
- 此時回到 **[Pipeline]** 發現 pipeline 已自動執行
    ![](https://i.imgur.com/LZii14l.png)
- 待 build pipeline 執行完成後回到 release pipeline 會發現已自動啟動部署流程
    ![](https://i.imgur.com/1WYQKtv.png)
- 根據先前的步驟進行審核及檢查的動作
<!-- - 回到 **[Sprint]** 中，`將首頁標題添加今天日期` task 查看內容，可以在 Deployment 及 Development 中看到建置及部屬的狀況
    ![](https://i.imgur.com/3XhXXGV.png) -->
## 8/ Dashboard
- 左邊選單列中的 Overview 下點選 **[Dashboards]**，點選 **[Add a widget]**
    ![](https://i.imgur.com/fdESMt0.png)
- 選擇 **[Assign to me]**，然後點選 **[Add]**
    ![](https://i.imgur.com/UHRuj9v.png)
- 可再添加 **[Deployment Status]**、**[New Work Item]**，**[Query Tile]** 或自行添加其他項目
    ![](https://i.imgur.com/R84Rnzl.png =300x)
    ![](https://i.imgur.com/70N5zCJ.png =300x)
    ![](https://i.imgur.com/kcD9rZ4.png =300x)

- 完成後選擇 **[Done Editing]**
    ![](https://i.imgur.com/Xp3eATq.png)
- 點選 Deployment Status 進行設定，將 size 改為 **[3x2]**，並填入 **[Build pipeline]** 和 **[Linked release pipelines]**，設定完成後點選 **[Save]**
    ![](https://i.imgur.com/bb01CHu.png)
- 點選 **[Query Tile]**，**[Select Queries]** 選擇 **[Shared Query]** > **[Task in Progress]**(先前在 query 內建立的)
    ![](https://i.imgur.com/Xls4I1l.png)

## 9/ 清除資源
- 點選左方選單列表中的 **[Project Settings]**，捲到最下方有 **[Delete]** 的按鈕可以進行移除
    ![](https://i.imgur.com/LRgoeOt.png)
- 到 [Azure Portal](https://portal.azure.com/)
- 找到建立的資源群組，點選頁面中的 **[Delete resource group]**，在欄位中填入資源群組的名稱，選擇 **[Delete]** 即可完成清除
    ![](https://i.imgur.com/67QVi65.png)


## Reference
- [Hands-on : Azure DevOps Service (.NET Core Web)](https://hackmd.io/@msazuredev/B1nlR8un_)
- [Register free Azure account](https://azure.microsoft.com/zh-tw/free/)
- [Azure DevOps Service 免費試用申請教學](https://hackmd.io/@msazuredev/HkaaHy2AO)
- [Pipeline caching](https://learn.microsoft.com/en-us/azure/devops/pipelines/release/caching?view=azure-devops)
- [Sample Code (ASP .NET Core)](https://github.com/huier23/AspNetCoreSample.git)
- [HelloWorld.Lib](https://github.com/huier23/HelloWorld.Lib.git) 
- [Azure DevOps Service Tag Released](https://devblogs.microsoft.com/devops/azure-devops-service-tag-released/)
- [Hands-on : Azure DevOps Service (Azure Kubernetes Service)](https://hackmd.io/@msazuredev/ByonLS_mY)