共用方式為


DevOps

提示

此內容摘錄自《建構適用於 Azure 的雲端原生 .NET 應用程式》電子書,您可以在 .NET Docs 找到此電子書,或免費下載可離線閱讀的 PDF。

Cloud Native .NET apps for Azure eBook cover thumbnail.

回應任何問題時,軟體顧問最愛的口號就是「看情況」。 這並不是因為軟體顧問喜歡不表示立場, 而是因為任何軟體問題都沒有真正的答案。 沒有絕對的正確與錯誤,而是在兩端取得平衡。

舉 Web 應用程式開發的兩大陣營為例:單頁應用程式 (SPA) 與伺服器端應用程式。 一方面,使用者使用 SPA 的體驗通常較好,且可有效降低 Web 伺服器流量,託管方式就像靜態託管一樣簡單。 但另一方面,SPA 開發速度通常較慢,且較難以測試。 哪一個是正確的選擇? 這同樣取決於您的情況。

雲端原生應用程式在同樣的二分法情境下也不例外。 在開發速度、穩定性和延展性方面,這類應用程式具有顯著優勢,但在管理上則可能較為困難。

早在幾年前,將開發環境的應用程式移至實際執行環境時,流程往往需要一個月或更長時間。 公司發行軟體的步調為 6 個月一次,甚或每年一次。 人們必須熟悉 Microsoft Windows,才能了解在 Windows 10 前差強人意的漫長發行步調。 在 Windows XP 與 Vista 之間經過了五年,Vista 與 Windows 7 之間則有三年。

而目前大體上已完善建立,能快速發行軟體,讓快速成長的公司掌握龐大的市場優勢,領先步調緩慢的競爭對手。 為此,Windows 10 的主要更新現在約每六個月一次。

要為企業提供價值,更快速可靠的發行模式和做法,統稱為 DevOps。 其中包含整個軟體發展生命週期的繁多概念:從應用程式的指定、交付到操作等等。

DevOps 出現的時間在微服務前,更小、且更符合目的;沒有 DevOps,服務便無法在實際執行環境中輕鬆發行和操作多個應用程式。

Figure 10-1 Search trends show that the growth in microservices doesn't start until after DevOps is a fairly well-established idea.

圖 10-1 - DevOps 和微服務。

透過良好的 DevOps 做法,便可發揮雲端原生應用程式的優點,免於在實際操作應用程式時工作堆積如山。

在 DevOps 方面,沒有所謂的全能者。 沒有人能販售一款可發佈及操作優質應用程式的全方位完整解決方案。 這是因為每款應用程式與其他所有應用程式都十分不同。 然而,有些工具可大幅降低 DevOps 的進入門檻。 其中一項工具便是 Azure DevOps。

Azure DevOps

Azure DevOps 的家族史相當長。 其根源可追溯至 Team Foundation Server 首次上線,而後多次變更名稱:Visual Studio Online 和 Visual Studio Team Services。 但經過這些年,現在也已大幅超越以往版本。

Azure DevOps 分成五個主要元件:

Figure 10-2 The five major areas of Azure DevOps

圖 10-2 - Azure DevOps。

Azure Repos - 原始程式碼管理,支援可敬的 Team Foundation 版本控制 (TFVC),以及業界最愛的 Git。 提取要求提供了一種方式,在變更時促進變更的相關討論,有助於社交程式設計。

Azure Boards - 提供問題與工作項目追蹤工具,可讓使用者挑選最適合的工作流程。 其中有許多預先設定的範本,包含支援 SCRUM 和 Kanban 開發樣式的範本。

Azure Pipelines - 支援與 Azure 緊密整合的組建和發行管理系統。 組建可在 Windows、Linux 到 macOS 等各種平台上執行。 組建代理程式可於雲端或內部部署佈建。

Azure Test Plans - 有了Test Plans 功能所提供的測試管理和探勘測試支援,任何 QA 人員都能掌握最新狀況。

Azure Artifacts - 成品摘要,可讓公司建立自己的內部 NuGet 版本、npm 和其他版本。 若集中式存放庫失敗,則可作為快取上游套件的雙重用途。

Azure DevOps 中的最上層組織單位稱為「專案」。 在每個專案中,Azure Artifacts 等各種元件可開啟和關閉。 這些元件各提供雲端原生應用程式的不同優點。 最實用的三個是存放庫、面板和管線。 若使用者要在另一個存放庫堆疊 (如 GitHub) 中管理其原始程式碼,但仍要運用 Azure Pipelines 和其他元件,這完全可行。

幸虧在選取存放庫時,開發小組有許多選項。 其中一項是 GitHub。

GitHub 動作

GitHub 建立於 2009 年,為主控專案、文件和程式碼的熱門 Web 存放庫。 許多大型科技公司,例如 Apple、Amazon、Google 及各主流企業皆使用 GitHub。 GitHub 使用名稱為 Git 的開放原始碼、分散式版本控制系統,作為其基礎。 接著,則會新增一組自己的功能,包含瑕疵追蹤、功能與提取要求、任務管理,以及每個程式碼基底的 Wiki。

隨著 GitHub 發展,也會新增 DevOps 功能。 例如,GitHub 有自己的持續整合/持續傳遞 (CI/CD) 管線,稱為 GitHub Actions。 GitHub Actions 為支援社群的工作流程自動化工具。 此工具可讓 DevOps 小組整合現有工具、混合和比對新產品,並融入軟體生命週期,包含現有的 CI/CD 合作夥伴。」

GitHub 有超過 4000 萬位使用者,使其成為全球最大的原始程式碼主機服務。 在 2018 年 10 月,Microsoft 已購入 GitHub。 Microsoft 已承諾 GitHub 將維持開放平台,任何開發人員都能參與及擴充。 該平台會繼續以獨立公司形式運作。 GitHub 提供企業、小組、專業及免費帳戶等方案。

原始檔控制

雲端原生應用程式的程式碼在編排上可能很不容易。 雲端原生應用程式通常是由彼此通訊的小型應用程式組成網路,而不是一個巨型應用程式。 正如同運算領域的一切,程式碼的最佳排列仍是個未解的問題。 有些使用不同配置的應用程式成功範例,但兩個變數似乎最受歡迎。

在實際開始進行原始程式碼控制前,建議先判斷適合的專案數目。 單一專案支援多個存放庫和建置管線。 面板則稍微複雜一點,但任務同樣可輕鬆指派給單一專案中的多個小組。 單一 Azure DevOps 專案可支援數百位、甚或數千位開發人員。 這可能是最佳做法,因為可為所有開發人員提供單一位置,當開發人員不確定應用程式所屬的專案時,如此可減少尋找時的混淆狀況。

在 Azure DevOps 專案中分割微服務程式碼的挑戰性可能更高一點。

Figure 10-3 Single versus Multiple Repositories

圖 10-3 - 單一與多個存放庫。

具各微服務特性的存放庫

初步看起來,這似乎是分割微服務原始程式碼最具邏輯的方法。 各存放庫皆可包含建置一個微服務所需的程式碼。 這項方法的優點顯而易見:

  1. 用於建置和維護應用程式的指示,可新增至各存放庫根目錄的讀我檔案。 這些指示在瀏覽存放庫時容易尋找,有助於提升開發人員的效率。
  2. 每個服務皆位於邏輯位置,知道服務名稱即可輕鬆找到。
  3. 組建可輕鬆設定,只在變更主控存放庫時才會觸發。
  4. 進入存放庫的變更數目僅限於處理專案的少數開發人員。
  5. 輕鬆設定安全性,僅限具備讀取和寫入權限的開發人員存取存放庫。
  6. 主控小組只需與他人進行最低限度的討論,便可變更存放庫層級設定。

微服務背後的其中一項重要概念,即是服務應彼此隔離開來。 使用網域導向設計來決定服務界限時,服務則作為交易界限。 資料庫更新不應跨多個服務進行。 此相關資料的集合稱為界限上下文。 此概念展現在微服務資料及資料庫其餘服務的區隔上,維持分開、自主。 整體流程至原始程式碼,貫串此概念非常合理。

但此方法也並非沒有問題。 目前其中一項較險峻的開發問題是管理相依性。 試想構成平均 node_modules 目錄的檔案數目。 全新安裝 create-react-app 這類內容,可能會帶入數千個套件。 這些相依性的管理問題並不容易。

若相依性已更新,下游套件也必須更新此相依性。 可惜這需要進行開發工作,因此,node_modules 目錄的單一套件最後會有多個版本,且各自相依於版本步調有些微差異的其他幾個套件。 部署應用程式時應使用哪個相依性版本? 實際執行環境中的目前版本? 目前為搶鮮版 (Beta) 的版本,但可能會在使用者進入實際執行環境時轉為實際執行狀態? 只靠微服務無法解決各類困難問題。

各式各樣的專案與程式庫相依。 將微服務分為每個存放庫各一個,最有利於使用內部存放庫 Azure Artifacts 解析內部相依性。 程式庫的組建會將最新版本推送至 Azure Artifacts,以供內部使用。 下游專案仍必須手動更新,才能相依於最近更新的套件。

另一項缺點則顯現在移動服務之間的程式碼時。 相信「應用程式首先分割為微服務總沒錯」的想法固然好,但事實上,我們無法總是具先見之明,而不發生任何服務分割的錯誤。 因此,驅動應用程式的功能和程式碼必須在服務之間、存放庫之間移動。 當程式碼從某存放庫跳到另一個存放庫,歷程記錄則會遺失。 在許多情況下,特別是稽核時,程式碼片段的完整歷程記錄便相當寶貴。

最後一項最重要的缺點是協調變更。 在真正的微服務應用程式中,服務之間不應有部署相依性。 服務 A、B 和 C 應要可依任何順序部署,因為三者關聯鬆散。 但實際上,有時會需要同時進行跨多個存放庫的變更。 幾個範例包含:更新程式庫以關閉安全性漏洞,或變更所有服務使用的通訊協定。

若要進行跨存放庫變更,則需要各個存放庫的連續認可。 各存放庫的每項變更皆必須分別提取要求和檢閱。 此活動可能難以協調。

使用許多存放庫的一項替代方案,便是將所有原始程式碼放置於一個全知的大型存放庫。

單一存放庫

這項方法有時稱為 monorepository,意即每個服務的原始程式碼皆放置於同一個存放庫。 這項方法乍看似乎並不妥當,可能會讓原始程式碼的處理效率低落。 然而,這種方式有幾項顯著的優點。

第一個優點是專案間的相依性更容易管理。 專案可直接匯入彼此,而不是依賴某些外部成品摘要。 這表示更新為立即性的,且衝突版本可在開發人員工作站編譯時發現。 實際上,某些整合測試移向了流程早期。

在專案間移動程式碼時,現在更容易保留歷程記錄,因為檔案會偵測為已移動,而非已重寫。

另一個優點是,跨服務界限的各類變更都能在單一認可中進行。 此活動可減少個別檢閱數十項可能變更的額外負荷。

有許多工具可執行程式碼的靜態分析,以偵測不安全的程式設計做法,或有問題的 API 用途。 在多個存放庫的領域內,每個存放庫皆須逐一查看,才能找出其中的問題。 單一存放庫則可在單一位置執行分析。

單一存放庫的做法也有許多缺點。 令人擔憂的其中一點是,使用單一存放庫有安全性考量。 若依服務模型的某個存放庫內容洩漏,遺失的程式碼量則最少。 使用單一存放庫時,公司擁有的一切皆可能遺失。 過去就有許多實際範例,嚴重阻礙整體遊戲開發工作。 在大多數理想的安全性做法中,應減少多個存放庫公開的介面區。

單一存放庫的大小可能很快會成長為難以管理。 如此會產生一些有意義的效能影響。 您可能需要使用 Git 的虛擬檔案系統 等專用工具,原本設計用於改善 Windows 小組開發人員的體驗。

使用單一存放庫的論點,往往歸因於 Facebook 或 Google 使用此方法來排列原始程式碼。 若方法對這些公司夠好,當然對所有公司也是正確的方法。 但事實是,很少公司的經營規模能比擬 Facebook 或 Google。 這類規模發生的問題與大部分開發人員所面臨的問題不同。 對一方有益的,未必對另一方也有益。

最終,兩項解決方案都能用於主控微服務的原始程式碼。 但在大部分情況下,相較於經營管理及工程的額外負荷,單一存放庫的微薄效益並不划算。 將程式碼分割為多個存放庫,不僅可提倡關注點分離,也能促進開發小組的自主性。

標準目錄結構

無論單一與多個存放庫的爭論如何,每項服務都會有自己的目錄。 讓開發人員快速跨專案的最佳化效益之一,即是維護標準目錄結構。

Figure 10-4 A standard directory structure for both the email and sign-in services

圖 10-4 - 標準目錄結構。

建立新專案時,應使用結構正確的範本。 此範本也可包含這類實用項目,例如基本架構的讀我檔案及 azure-pipelines.yml。 在任何微服務架構中,專案間的大幅差異會令服務的大量作業更為困難。

有許多工具可提供整個目錄的範本化,其中包含數個原始程式碼目錄。 Yeoman 在 JavaScript 領域很受歡迎,GitHub 最近發行了存放庫範本,提供許多相同的功能。

工作管理

管理任何專案的任務可能都不容易。 還有無數個關於設定工作流程類型的問題有待解答,以確保維持最佳的開發人員生產力。

雲端原生應用程式通常小於傳統軟體產品,或至少分為小型的服務。 追蹤與這些服務相關的問題或任務,與任何其他軟體專案一樣重要。 誰都不希望某些工作項目跟不上進度,或要向客戶說明問題未正確記錄。 面板於專案層級進行設定,但區域可在每個專案內定義。 如此可細分幾個不同元件的問題。 在單一位置保留整個應用程式的所有工作,優點是更容易將某個小組的工作項目移至另一個小組,因為這些項目更方便理解。

Azure DevOps 隨附幾個預先設定的熱門範本。 在最基本的組態中,只需要知道待處理的項目、正在處理的項目,以及已完成的項目。 請務必了解建置軟體的流程,以便排定工作的優先順序,向客戶回報完成的任務。 當然,很少有軟體專案的流程會簡單到只有 to dodoingdone。 使用者無須花許多時間,就能開始在流程中新增 QADetailed Specification 等步驟。

敏捷式方法的其中一項重點,即是定期自我檢查。 這些檢查的目的,是為小組面臨的問題及改善方式提供深入解析。 這通常表示透過開發流程來變更問題和功能流程。 因此,為面板配置擴充其他階段是十分穩健的做法。

面板中的階段不是唯一的組織工具。 工作項目可能有階層,視面板組態而定。 面板上可能出現的最細微項目都是一項任務。 立即可用的任務包含標題、描述、優先順序、剩餘工作量估計,以及連結至其他工作項目或開發項目 (分支、認可、提取要求、組建等) 的功能。 工作項目可分類為不同應用程式區域及不同反覆項目 (短期衝刺),以方便尋找。

Figure 10-5 An example task in Azure DevOps

圖 10-5 - Azure DevOps 中的任務。

描述欄位支援您預期的一般樣式 (粗體、斜體底線和刪除線) ,以及插入影像的功能。 這可成為指定工作或 Bug 時使用的強大工具。

任務可彙總為功能,以定義單位較大的工作。 功能可再彙總為 Epic。 此階層中的任務分類可讓您輕鬆了解推出大型功能的進度。

Figure 10-6 Work item types configured by default in the Basic process template

圖 10-6 - Azure DevOps 中的工作項目。

Azure Boards 中的問題有不同的檢視類型。 尚未排程的專案會顯示於待處理項目。 這些項目可由此處指派給短期衝刺。 短期衝刺是一種時間方塊,預期某些工作量的完成期間。 這項工作可包含任務,以及票證解決。 一旦開啟,即可從 [短期衝刺面板] 區段管理整個短期衝刺。 此檢視會顯示工作進度,包含待執行工作的圖表,可提供短期衝刺是否成功的持續更新估計。

Figure 10-7 A board with a sprint defined

圖 10-7 - Azure DevOps 中的面板。

現在 Azure DevOps 中的 Boards 應已具備大量功能。 開發人員能輕鬆檢視處理中的內容。 專案經理也可檢視即將進行的工作及現有工作的概觀。 主管可查看許多與資源與容量有關的報告。 可惜的是,雲端原生應用程式尚不能免於追蹤工作的需求。 但若必須追蹤工作,仍有些部分的體驗優於 Azure DevOps。

CI/CD 管線

持續整合 (CI) 和持續傳遞 (CD) 問世後,因此軟體開發生命週期有了史無前例的革命性進展。 專案的原始程式碼會建置及執行自動化測試,簽入變更時即可提早攔截錯誤。 在持續整合組建問世前,從存放庫提取程式碼時,往往才發現未通過測試,甚或無法建置。 這導致了發生中斷的根本原因。

傳統上,將軟體傳送到實際執行環境需要大量的文件及步驟清單。 每一步都需要手動完成,流程非常容易出錯。

Figure 10-8 A checklist

圖 10-8 - 檢查清單。

持續傳遞是持續整合的好夥伴,意即全新建置的套件會部署至環境。 人工流程無法調整規模,以因應開發速度,因此自動化更為重要。 指令碼會取代檢查清單,執行相同任務時比任何人類都更快速、精確。

持續傳遞提供的環境可能是測試環境;但也可能是實際執行環境,就像許多大型科技公司的做法。 後者需要投入高品質的測試,以確保變更時不會導致使用者執行中斷。 如同持續整合在早期攔截程式碼的問題,持續傳遞也會在早期攔截部署流程中的問題。

雲端原生應用程式凸顯了建置和傳遞流程自動化的重要性。 部署會更頻繁發生,並部署至更多環境,因此手動部署幾乎是不可能的事。

Azure 組建

Azure DevOps 提供一組工具,讓持續整合和部署比以往更加容易。 這些工具位於 Azure Pipelines。 第一項是 Azure Builds,這項工具可大規模執行以 YAML 為基礎的組建定義。 使用者可使用自己的組建機器 (若組建需要精心設定的環境,則很適合),也可在 Azure 裝載的虛擬機器集區 (時常重新) 中使用機器。 這些裝載的組建代理程式已預先安裝各式各樣的開發工具,不僅適用於 .NET 開發,也適用於 JAVA、Python、iPhone 等各類開發。

DevOps 包含各類立即可用的組建定義,供任何組建自訂。 組建定義會在名稱為 azure-pipelines.yml 的檔案中定義,並簽入存放庫,以便與原始程式碼一併進行版本設定。 如此可讓您輕鬆變更分支中的組建管線,因為變更可僅簽入該分支。 圖 10-9 顯示在完整架構上建置 ASP.NET Web 應用程式的範例 azure-pipelines.yml

name: $(rev:r)

variables:
  version: 9.2.0.$(Build.BuildNumber)
  solution: Portals.sln
  artifactName: drop
  buildPlatform: any cpu
  buildConfiguration: release

pool:
  name: Hosted VisualStudio
  demands:
  - msbuild
  - visualstudio
  - vstest

steps:
- task: NuGetToolInstaller@0
  displayName: 'Use NuGet 4.4.1'
  inputs:
    versionSpec: 4.4.1

- task: NuGetCommand@2
  displayName: 'NuGet restore'
  inputs:
    restoreSolution: '$(solution)'

- task: VSBuild@1
  displayName: 'Build solution'
  inputs:
    solution: '$(solution)'
    msbuildArgs: '-p:DeployOnBuild=true -p:WebPublishMethod=Package -p:PackageAsSingleFile=true -p:SkipInvalidConfigurations=true -p:PackageLocation="$(build.artifactstagingdirectory)\\"'
    platform: '$(buildPlatform)'
    configuration: '$(buildConfiguration)'

- task: VSTest@2
  displayName: 'Test Assemblies'
  inputs:
    testAssemblyVer2: |
     **\$(buildConfiguration)\**\*test*.dll
     !**\obj\**
     !**\*testadapter.dll
    platform: '$(buildPlatform)'
    configuration: '$(buildConfiguration)'

- task: CopyFiles@2
  displayName: 'Copy UI Test Files to: $(build.artifactstagingdirectory)'
  inputs:
    SourceFolder: UITests
    TargetFolder: '$(build.artifactstagingdirectory)/uitests'

- task: PublishBuildArtifacts@1
  displayName: 'Publish Artifact'
  inputs:
    PathtoPublish: '$(build.artifactstagingdirectory)'
    ArtifactName: '$(artifactName)'
  condition: succeededOrFailed()

圖 10-9 - 範例 azure-pipelines.yml

此組建定義可使用幾項內建任務來建立組建,如同建立一組樂高一樣簡單 (比巨型的千年鷹號更簡單)。 例如,NuGet 任務會還原 NuGet 套件,VSBuild 任務則會呼叫 Visual Studio 組建工具來執行實際的編譯。 Azure DevOps 中有數百項不同的可用任務,以及數千項由社群維護的任務。 無論您要執行的組建任務為何,都可能有人已建置過。

組建可透過手動、簽入、排程、或完成另一項組建等方式觸發。 在大部分情況下,組建會建議在每次簽入時進行。 您可篩選組建,針對存放庫的不同部分或不同分支執行不同組建。 適用的情境例如:快速執行組建,並減少對提取要求的測試、以及在夜間針對主幹執行完整迴歸套件等。

組建的最終結果為一系列檔案,稱為組建成品。 這些成品可傳遞至組建流程中的下一步,或新增至 Azure Artifacts 摘要,以便其他組建取用。

Azure DevOps 版本

組建會負責將軟體編譯為可傳送的套件,但成品仍必須推送至測試環境,才能完成持續傳遞。 因此,Azure DevOps 使用一項不同工具,名稱為 Releases。 Releases 工具會使用組建可使用的相同任務程式庫,但加入了「階段」的概念。 階段是安裝套件的隔離環境。 例如,產品可能會使用開發、QA 和實際執行環境。 程式碼會持續傳遞至開發環境,以便執行自動化測試。 一旦這些測試通過發行,便會移至 QA 環境,以進行手動測試。 最後,程式碼會推送至每個人皆可檢視的實際執行環境。

Figure 10-10 An example release pipeline with Develop, QA, and Production phases

圖 10-10 - 發行管線

組建中的各階段皆可在前一階段完成時自動觸發。 但在許多情況下,這並不理想。 將程式碼移至實際執行環境可能需要有人核准。 發行工具支援此功能,讓發行管線的每個步驟皆有核准者。 您可設定規則,讓版本必須由特定人員或群組簽署,才能進入實際執行環境。 這些關卡允許進行手動品質檢查,以及確認符合進入實際執行環境相關的任何法規需求。

每個人都能取得組建管線

設定許多組建管線無需任何成本,因此各微服務至少有一個組建管線會有些好處。 理想上,微服務可獨立部署至任何環境,因此完美狀況是讓每項微服務都能透過自己的管線發行,而不會發出大量無關聯的程式碼。 每個管線都能有自己的核准集,允許每項服務的組建流程有所變化。

版本控制發行

使用 Releases 功能的其中一項缺點,則是該功能無法在簽入的 azure-pipelines.yml 檔案中定義。 執行此動作有許多可能的原因,例如各分支具有發行定義、在專案範本中包含發行基本架構等。 幸好,將部分階段支援移至組建元件的工作持續進行中。 這稱為多階段組建,現已推出第一版