設計管線
在此單元中,您會跟著 Tailspin Web 小組的腳步,看他們如何定義 Space Game 網站的發行管線。
在規劃發行管線時,一開始通常會先識別該管線的階段 (也就是主要部分)。 請確定您已在相同 Microsoft 帳戶下,登入 Azure 入口網站和 Azure DevOps。 例如,在上一個課程模組中,Andy 和 Mara 的基本管線就有對應至 Azure App Service 執行個體的部署階段。
在本課程模組中,您會促使階段發生轉變。 在每個階段內,您會將 Space Game 網站部署至與該階段相關聯的環境。
定義好需要的階段之後,請考慮要如何促使階段發生轉變。 每個階段都可以定義成功準則,符合後才允許組建進入下一個階段。 Azure Pipelines 提供數種方式來協助您控制管線中發生轉變的條件和時間。 整體來說,這些方法可用於發行管理。
在本節中,您會:
- 了解常見的管線階段彼此有何差異,例如組建、開發、測試和預備。
- 了解如何使用手動、排程和持續部署觸發程序控制成品在何時進入管線中的下一個階段。
- 查看發行核准如何暫停管線,直到核准者接受或拒絕發行為止。
會議
Tailspin Web 小組齊聚一堂。 在使用 Azure Pipelines 建立發行管線中,該小組已規劃好目前的短期衝刺工作。 每項工作都與 Space Game 網站的發行管線建置有關。
記得嗎,該小組針對其短期衝刺決定了以下五項工作:
- 建立多階段管線。
- 將 Web 應用程式連線到資料庫。
- 將品質測試自動化。
- 將效能測試自動化。
- 改善發行步調。
該小組這次開會的目的,是要討論第一項工作,也就是建立多階段管線。 在小組定義管線之後,它可以從其基本概念證明移至包含更多階段、品質檢查和核准的發行管線。
Amita 和 Tim 是第二次看 Andy 和 Mara 示範發行管線了。 他們看到成品已建置完成並安裝在 App Service 上。
您需要哪些管線階段?
當您想要實作發行管線時,請務必先找出您需要的階段。 您的需求會決定您選擇的階段。 讓我們在旁邊看看該小組如何決定他們的階段。
Tim:好,我已經了解自動化管線的概念了。 我喜歡如何輕鬆地部署至 Azure。 但我們要從這個示範的哪個地方開始呢? 我們需要可實際用於發行的東西。
Amita:沒錯! 我們需要再新增其它階段。 例如,目前,我們沒有任何測試階段的位置。
Tim:我們還需要一個階段來向管理階層展示新的功能。 沒有管理階層核准,我無法讓任何東西進入生產環境。
Andy:當然可以! 既然發行管線的用途已加快,我們該如何讓此管線執行我們需要什麼?
Mara:我們先寫下需求,以便規劃後續的步驟。 從我們已經擁有的東西開始吧。
Mara 走向白板,並寫下現有的管線。
Mara:組建階段會建置原始程式碼並產生套件。 在我們的案例中,這個套件是 .zip 檔案。 部署階段會在 App Service 執行個體上安裝 .zip 檔案 (也就是 Space Game 網站)。 我們的發行管線中缺少什麼?
新增開發階段
Andy:或許有些偏頗,不過我認為我們需要開發階段。 這個階段應該是成品建置好之後的第一個停留點。 開發人員不可能一直從本機開發環境執行整個服務。 例如,電子商務系統可能需要網站、產品資料庫,以及付款系統。 我們需要這樣一個階段來容納應用程式一切所需。
在我們的案例中,Space Game 網站的排行榜功能會從外部來源讀取高分記錄。 但現在它讀取的是檔案中的虛構分數。 設定開發階段會讓我們有環境可以將 Web 應用程式與實際資料庫做整合。 該資料庫保有的可能還是虛構分數,但這會讓我們更接近最終的應用程式。
Mara:這樣很好。 我們還不會與實際的資料庫整合。 但在開發階段,我們可以部署到可新增資料庫的環境。
Mara 在白板上更新了她畫的圖。 她把「部署」換成「開發」以顯示開發階段。
Andy:你點出了一件有趣的事。 我們每次在 GitHub 中推送變更時,都會建置應用程式。 這是否表示,每個組建在完成之後都會升階至開發階段?
Mara:不斷建置應用程式,可以讓我們獲得關於組建和測試是否狀況良好的重要意見反應。 但我們只想在將程式碼合併至某些中央分支,例如 main 分支或其他某些發行分支時,才升階至開發階段。 我會更新圖示來顯示該需求。
Mara:我認為要實現這種升階很容易。 我們可以定義只有在發行分支上發生變更時,才會升階至開發階段的條件。
什麼是條件?
在 Azure Pipelines 中,可以根據管線狀態使用條件執行工作或作業。 您在以前的課程模組中已使用過條件。
請記住,您可以指定的一些條件如下:
- 只有在先前所有的相依工作都成功時。
- 即使先前的相依性失敗、除非已取消執行。
- 即使先前的相依性失敗、即使已取消執行。
- 只有在先前的相依性失敗時。
- 某些自訂條件。
以下是基本範例:
steps:
- script: echo Hello!
condition: always()
always()
條件會使此工作無條件地列印 "Hello!",即使先前的工作失敗也一樣。
如果您未指定條件,則會使用這個條件:
condition: succeeded()
內建的 succeeded()
函式會檢查上一個工作是否成功。 如果上一個工作失敗,則使用相同條件的現在這個工作和之後的工作都會略過而不執行。
在此,您想要建置有下列指定的條件:
- 上一個工作成功。
- 目前 Git 分支的名稱為 release 。
若要建置此條件,您可以使用內建 and()
函式。 此函式會檢查是否每個條件都成立。 若有任何條件不成立,整體條件就會失敗。
若要取得當前分支的名稱,請使用內建的 Build.SourceBranchName
變數。 您可以透過幾種方式來存取條件內的變數。 在此您會使用 variables[]
語法。
若要測試變數的值,您可以使用內建 eq()
函式。 此函式會檢查其引數是否相等。
考慮到這一點,您套用了此條件,只在目前的分支名稱是「發行」時才執行開發階段:
condition: |
and
(
succeeded(),
eq(variables['Build.SourceBranchName'], 'release')
)
and()
函式中的第一個條件會檢查上一個工作是否成功。 第二個條件會檢查目前的分支名稱是否等於 版本 。
在 YAML 中,您使用管道 (|
) 語法來定義橫跨多行的字串。 您可以將條件定義於單行中,但我們要以此方式撰寫條件,使其更容易讀取。
注意
在本課程模組中,我們會使用發行分支作為範例。 您可以結合多個條件來定義所需的行為。 例如,您可以建立這樣的條件:只在提取要求針對 main 分支觸發組建時,才執行該階段。
在下一個單元中,當您設定 開發 階段時,您會使用更完整的範例。
如需 Azure Pipelines 中條件的更完整描述,請參閱運算式文件。
Mara:藉由使用條件,您可以控制哪些變更會升階到哪個階段。 我們可以針對任何變更產生組建成品,以驗證組建並確認其狀況良好。 當我們準備好時,就可以將這些變更合併到發行分支,並將該組建升階到開發階段。
新增測試階段
Mara:到目前為止,我們已經擁有組建和開發階段。 接下來呢?
Amita:接下來我們可以新增測試階段嗎? 我覺得這是最適合用來測試最新變更的地方。
Mara 將測試階段新增到白板上所畫的圖。
Amita:我在想我是否需要常常測試應用程式。 每次 Mara 或 Andy 進行變更時,我就會收到電子郵件通知。 變更會整天進行,我老是不知道該何時介入。 我想要一天看一次組建就好,最好是我剛進辦公室的時候。 能做到這一點嗎?
Andy:當然。 為什麼我們不在非上班時間部署至測試階段? 例如,每天凌晨 3 點傳送組建給你。
Mara:這主意不錯。 反正如果有需要,我們隨時都可以手動觸發這個程序。 例如,我們可以在需要你立即確認重要的錯誤修正時,加以觸發。
Mara 更新她畫的圖,以顯示組建會在每天凌晨 3 點,從開發階段進入測試階段。
什麼是觸發程序?
Amita:很好,我們已經知道一個階段要如何進入到另一個階段。 但我們要如何控制階段的執行時間?
Mara:在 Azure Pipelines 中,我們可以使用觸發程序。 觸發程序會定義階段的執行時間。 Azure Pipelines 提供數種類型的觸發程序。 我們的選擇如下:
- 持續整合 (CI) 觸發程序
- 提取要求 (PR) 觸發程序
- 已排程的觸發程序
- 完成組建觸發程序
CI 和 PR 觸發程序可讓您控制哪些分支會參與整個程序。 例如,您想要在有任何分支發生變更時建置專案。 已排程的觸發程序會在特定時間開始部署。 完成組建觸發程序會在另一個組建 (例如相依元件的組建) 成功完成時執行組建。 看來我們需要的是已排程的觸發程序。
什麼是已排程的觸發程序?
已排程的觸發程序會使用 cron 語法,讓組建依照定義的排程來執行。
在 Unix 和 Linux 系統上,很多人使用 cron 將作業排程在設定好的時間間隔執行,或在特定的時間執行。 在 Azure Pipelines 中,已排程的觸發程序會使用 cron 語法來定義階段的執行時間。
cron 運算式包含可用來比對某些時間參數的欄位。 這些欄位如下所示:
mm HH DD MM DW
\ \ \ \ \__ Days of week
\ \ \ \____ Months
\ \ \______ Days
\ \________ Hours
\__________ Minutes
例如,這個 cron 運算式描述「每天凌晨 3 點」:0 3 * * *
cron 運算式可包含特殊字元,以指定值清單或值範圍。 在此範例中,星號 (*) 會比對出 [天]、[月] 和 [星期幾] 欄位內的所有值。
換句話說,此 cron 運算式所代表的意思如下:
- 在 0 分時、
- 在第三小時、
- 在當月的任何一天、
- 在任何月份、
- 在當週的任何一天、
- 執行作業
若要指定只在星期一到星期五這幾天的凌晨 3 點,則要使用此運算式:0 3 * * 1-5
注意
實務上,您可以相對於 UTC 時間來調整您 cron 排程中的時間,讓管線在您和小組所希望的時間開始執行。 實務上,您可以相對於 UTC 時間來調整您 cron 排程中的時間,讓管線在您和小組所希望的時間開始執行。
若要在 Azure Pipelines 中設定已排程的觸發程序,您需要在 YAML 檔案中放入 schedules
區段。 以下是範例:
schedules:
- cron: '0 3 * * *'
displayName: 'Deploy every day at 3 A.M.'
branches:
include:
- release
always: false
在這個 schedules
區段中:
cron
會指定 cron 運算式。branches
會指定只從release
分支部署。always
會指定是要無條件地 (true
) 執行部署,還是只在release
分支自上次執行之後有所變更時才執行 (false
)。 在這裡,您要指定false
,因為您只需要在release
分支自上次執行之後有所變更時才需要部署。
整個管線會在 Azure Pipelines 執行已排程的觸發程序時開始執行。 在其他情況下,例如當您將變更推送至 GitHub 時,管線也會執行。 若執行階段只是為了回應已排程的觸發程序,則可以使用條件來檢查組建的原因是否為已排程的執行。
以下是範例:
- stage: 'Test'
displayName: 'Deploy to the Test environment'
condition: and(succeeded(), eq(variables['Build.Reason'], 'Schedule'))
Test
這個階段只會在上一個階段成功且內建的 Build.Reason
管線變數等於 Schedule
時才執行。
您稍後會在本課程模組中看到更完整的範例。
Amita:這樣很好。 我甚至不需要手動挑選發行並進行安裝。 這已經為我做好了準備。
Andy:別忘了,我們也可以在之後將更多作業自動化。 這些並非一成不變的。 管線會隨著我們的改善和學習而演變。
新增預備階段
Tim:輪到我了。 我需要一個階段來執行更多的壓力測試。 我們也需要一個階段,以便向管理階層示範如何取得其核准。 目前,我們可以將這兩個需求合併成所謂的預備階段。
Andy:Tim,你說得很好。 有預備 (或生產前) 環境很重要。 此預備環境往往是將功能或錯誤修正送達使用者之前的最後一個停留點。
Mara 將預備階段新增至她在白板上畫的圖。
Amita:我們使用已排程的觸發程序將變更從開發階段升階到測試階段。 但是,我們如何將變更從 測試 升級為 預備? 是不是也必須透過排程來進行升階?
Mara:我認為最好的處理方式是發行核准。 發行核准能夠讓你以手動方式將變更從一個階段升階到下一個階段。
Amita:這聽起來就是我需要的功能! 發行核准讓我有時間先測試最新的變更,再向管理階層展示組建。 我可以在準備就緒後再將組建升階。
Mara 更新她畫的圖,以顯示只在 Amita 核准後,從讓組建從測試進入到預備階段。
Tim:我也可以想像出,我們使用發行核准,在管理階層簽核之後,從預備升階至生產的情形。 我永遠無法預測這會花費多少時間。 管理階層簽核之後,我就可以核准發行,並手動將其升階到生產階段。 但發行核准是如何運作的?
什麼是發行核准?
發行核准可用來暫停管線,直到核准者接受或拒絕發行為止。 若要定義您的發行工作流程,您可以結合核准、條件和觸發程序。
回想一下,在使用 Azure Pipelines 建立發行管線中,您於管線設定中定義了一個環境來代表您的部署環境。 以下是來自您現有管線的範例:
- stage: 'Deploy'
displayName: 'Deploy the web application'
dependsOn: Build
jobs:
- deployment: Deploy
pool:
vmImage: 'ubuntu-20.04'
environment: dev
variables:
- group: Release
您的環境可以包含發行的特定準則。 準則能指定哪些管線可以部署到該環境,以及需要哪些人工核准才能將發行從一個階段升階到下一個階段。
稍後在本課程模組中,您會定義 預備 環境,並將自己指派為核准者,將 Space Game Web 應用程式從 測試 階段升級 至 預備環境 。
按照需要進行少量或多量的自動化
Azure Pipelines 可讓您彈性地將某些階段自動化,同時又能手動控制尚未準備好進行自動化的階段。
Tim:我很滿意我們可以定義準則以將變更從某個階段升階到下一個階段。 但我們在管線中定義了一些手動準則。 我覺得 DevOps 就是將一切自動化。
Mara:你說得沒錯。 DevOps 的目的就是要將重複且容易出錯的工作自動化。 但有時還是需要人力介入。 例如,我們要在管理階層核准後才能發行新功能。 當我們在自動化部署方面獲得更多的經驗後,我們就可以將更多的手動步驟自動化,以加快程序的進展速度。 例如,我們可以在測試 階段自動化 更多品質檢查,因此 Amita 不需要核准每個組建。
Tim:好辦法。 我們現在就按照這個計畫,看看之後要如何加快系統速度。
Amita:說到計畫,我們可以總結一下接下來的步驟嗎?
方案
在 Tailspin 小組進入後續步驟之前,我們來複習一下他們的計畫。
Mara:我們想要建置的發行管線是這樣的。
Mara 指向白板。
Mara:總而言之,我們的步驟是:
- 在每次將變更推送至 GitHub 時產生組建成品。 這個步驟發生在組建階段。
- 將組建成品升階至開發階段。 當組建階段成功,且變更位於發行分支上時,就會自動執行此步驟。
- 每天凌晨 3 點將組建成品升階到測試階段。我們會使用排程的觸發程式自動升級組建成品。
- 在 Amita 測試並核准組建之後,將組建成品升階至預備階段。 我們使用發行核准來將組建成品升階。
在管理階層核准組建之後,我們就可以將組建成品部署到生產環境。
Amita:過程會不會很麻煩? 感覺需要做很多工作。
Mara: 我不認為太糟糕了。 每個階段都彼此分開。 階段不是連續的。 每個階段都有一組自己的工作。 舉例來說,在測試階段發生的事,只會留在測試階段。
我們管線中的每個部署階段也都有自己的環境。 例如,當我們將應用程式部署至開發或測試階段時,環境是 App Service 執行個體。
最後,我們一次只測試一個發行版本。 我們絕不會在管線途中變更發行。 我們在開發階段中使用的發行與預備階段相同,而且每個發行都有自己的版本號碼。 如果有發行在其中一個階段中斷,我們會加以修正並使用新的版本號碼來重新建置此發行。 這個新發行接著會從頭開始經歷管線的每個環節。
關於品質的一些事
您剛看到小組設計管線,其應用程式會從組建到預備。 這個管線的重點不只是為了讓他們工作起來更輕鬆。 還要確保其提供給客戶的軟體有良好的品質。
要如何測量發行程序的品質呢? 您無法直接測量發行程序的品質。 您只能測量程序是否運作良好。 如果您不斷變更程式,則可能表示發生錯誤。 如果發行老是在管線的特定位置失敗,也可能表示發行程序有問題。
發行是否老是在特定一天或特定時間失敗? 是否老是在部署至特定環境後失敗? 請找出這種種模式,以了解是否與發行程序的某些方面相依或相關。
想要追蹤發行程序品質有一個好辦法,那就是建立發行品質的視覺效果。 例如,新增儀表板 Widget,以顯示每個發行的狀態。
如果您想要測量發行本身的品質時,可以在管線內執行所有種類的檢查。 例如,您可以在執行管線時,進行不同類型的測試,例如負載測試和 UI 測試。
使用品質閘門也是檢查發行品質的絕佳方式。 品質閘門種類繁多。 例如,工作項目閘門可以確認需求程序的品質。 您也可以新增更多安全性和合規性檢查。 例如,您是否遵守四眼原則,或您是否具有適當的可追蹤性?
當您逐步完成此學習路徑時,您會看到許多這些技術付諸實踐。
最後,當您設計品質發行程式時,請考慮您需要提供給使用者的檔或版本資訊種類。 要讓文件時時保持在最新狀態並不容易。 您可以考慮使用工具,例如 Azure DevOps 版本資訊產生器。 產生器是一種函式應用程式,內含由 HTTP 觸發的函式。 每當您使用 Azure Blob 儲存體在 Azure DevOps 中建立新的發行版本時,產生器就會建立 Markdown 檔案。