共用方式為


DevOps

小提示

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

Azure 電子書的雲端原生 .NET 應用程式封面縮圖。

軟體顧問最喜歡的口頭禪是對任何提問都回答「這要看情況」。 這並不是因為軟體顧問喜歡不擔任職位。 這是因為軟體中沒有任何人能真正回答任何問題。 沒有絕對的對錯,而是相反的平衡。

例如,開發 Web 應用程式的兩個主要學校:單頁應用程式(SPA)與伺服器端應用程式。 一方面,用戶體驗通常在 SPA 上較佳,而 Web 伺服器的流量可以減少,使其可以簡單地使用靜態主機。 另一方面,SPA 通常較慢開發,而且更難以測試。 哪一個是正確的選擇? 嗯,這取決於你的情況。

雲端原生應用程式無法不受相同的二分法的影響。 在開發速度、穩定性和延展性方面,它們具有明顯的優勢,但管理它們可能會更加困難。

幾年前,將應用程式從開發移至生產環境的過程並不罕見,甚至更需要一個月的時間。 公司以每 6 個月或每年的步調發行軟體。 人們只需看 Microsoft Windows,即可對於在 Windows 10 永續更新時代之前所能接受的版本發佈頻率有所瞭解。 Windows XP 和 Vista 之間經過五年,Vista 與 Windows 7 之間還有三年。

如今,能夠快速發行軟體已被廣泛認識,這為行動敏捷的公司帶來巨大市場優勢,相較於那些行動緩慢的競爭對手。 因此,Windows 10 的主要更新現在大約每六個月一次。

讓更快速、更可靠的版本將價值傳遞給企業的模式和做法統稱為 DevOps。 它們包含跨越整個軟體開發生命週期的各種想法,從規劃應用程式到交付及操作該應用程式。

在微服務之前,DevOps 就已經出現了。沒有 DevOps 來簡化多個應用程式在生產環境中的發佈和運作,要推動向更小、更適合目的的服務的轉變是不可能的。

圖 10-1 搜尋趨勢顯示,在 DevOps 相當完善的概念之後,微服務的成長才會開始。

圖 10-1 - DevOps 和微服務。

透過良好的 DevOps 做法,您可以實現雲端原生應用程式的優點,而不會在實際操作應用程式的工作下窒息。

在 DevOps 方面沒有萬能良方。 沒有人可以銷售一個全面的解決方案,以發布和運行高品質的應用程式。 這是因為每個應用程式與其他應用程式截然不同。 不過,有一些工具可讓 DevOps 成為一個不那麼令人生畏的命題。 這些工具之一稱為 Azure DevOps。

Azure DevOps

Azure DevOps 具有很長的血統。 它的根源可以追溯到 Team Foundation Server 第一次搬到線上,以及隨後的多次名稱變更:Visual Studio Online 和 Visual Studio Team Services。 然而,多年來,它已經遠遠超過其前任。

Azure DevOps 分為五個主要元件:

圖 10-2 Azure DevOps 的五個主要區域

圖 10-2 - Azure DevOps。

Azure Repos - 支援可敬的 Team Foundation 版本控制 (TFVC) 和業界最愛 Git 的原始程式碼管理。 拉取請求提供一種方法,通過促進變更的討論來啟動社交編程。

Azure Boards - 提供問題和工作項目追蹤工具,可讓使用者挑選最適合他們的工作流程。 它隨附許多預先設定的範本,包括支援 SCRUM 和工作流程看板開發樣式的範本。

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

Azure 測試計劃 - 測試計劃功能所提供的測試管理和探勘測試支援確保每位 QA 人員都不會被遺漏。

Azure Artifacts - 一種工具供應源,允許公司創建自己的內部版本,如 NuGet、npm 和其他。 它具有雙重功能,不僅能作為上游套件的快取,還能在集中式存放庫失敗時發揮作用。

Azure DevOps 中的最上層組織單位稱為 Project。 在每個專案中,可以開啟和關閉各種元件,例如 Azure Artifacts。 這些元件各有不同的優點,適用於雲端原生應用程式。 三個最有用的是存放庫、面板和管線。 如果使用者想要在另一個存放庫堆疊中管理其原始程式碼,例如 GitHub,但仍會利用 Azure Pipelines 和其他元件,這是完全可能的。

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

GitHub 工作流程

GitHub 成立於 2009 年,是一個廣受歡迎的 Web 型存放庫,用於裝載專案、檔和程式代碼。 許多大型科技公司,如蘋果、亞馬遜、谷歌和主流公司都使用 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 專案中分割微服務的程式代碼可能會稍微更具挑戰性。

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

圖 10-3 - 一個與許多存放庫的比較。

每個微服務的存放庫

第一眼,這種方法似乎是分割微服務原始程式碼的最邏輯方法。 每個存放庫都可以包含建置一個微服務所需的程序代碼。 這種方法的優點很容易看得見:

  1. 建置和維護應用程式的指示可以新增至每個存放庫根目錄的自述檔。 瀏覽存放庫時,很容易找到這些指示,減少開發人員的啟動時間。
  2. 每個服務都位於邏輯位置,可透過知道服務的名稱輕鬆找到。
  3. 可以輕鬆地設定組建,使其只有在對所擁有的資料庫進行變更時才會觸發。
  4. 進入存放庫的變更數目僅限於處理專案的少數開發人員。
  5. 藉由限制開發人員具有讀取和寫入許可權的存放庫,即可輕鬆設定安全性。
  6. 擁有小組可以變更存放庫層級設定,僅需與其他人進行最少的討論。

微服務背後的其中一個重要概念是,服務應該被隔離並彼此分開。 使用網域驅動設計來決定服務的界限時,服務會做為交易界限。 資料庫更新不應跨越多個服務。 此相關數據的集合稱為系結內容。 此概念體現在將微服務數據隔離到一個獨立且自主的資料庫中,與其他服務分開。 將這個想法一路傳遞至原始程式碼是有道理的。

不過,這種方法並非沒有問題。 我們這個時代棘手的開發問題之一是管理相依性。 請考慮構成平均 node_modules 目錄的檔案數目。 全新安裝類似 create-react-app 的內容可能會帶來數千個套件。 如何管理這些相依性的問題很困難。

如果相依性已更新,則下游套件也必須更新此相依性。 不幸的是,這需要開發工作,因此,node_modules 目錄最終會有單一套件的多個版本,每一個版本都是其他套件的相依性,而這些其他套件的版本更新步伐略有不同。 部署應用程式時,應該使用哪個版本的相依性? 在目前生產中的版本是什麼? 目前處於 Beta 的版本,但很可能在消費者接觸到時已經進入生產環境。 僅使用微服務無法解決的困難問題。

有許多專案依賴的函式庫。 藉由將微服務分配到每個存放庫中,可以最佳方式使用內部存放庫 Azure Artifacts 來解決內部相依性。 程式庫的組建會將其最新版本推送至 Azure Artifacts 供內部使用。 下游專案仍必須手動更新,才能相依於新更新的套件。

另一個缺點會在服務之間移動程式代碼時呈現。 雖然相信應用程式的第一個分割是 100 個% 正確,但現實是,我們很少如此有先見之明,不會犯任何服務部門錯誤。 因此,這些功能及驅動這些功能的程式代碼需要從一個服務移動到另一個服務,從一個存放庫移動到另一個存放庫。 從某個存放庫躍升到另一個存放庫時,程式代碼會失去其歷程記錄。 有許多情況,特別是在稽核的情況下,在一段程式代碼上擁有完整歷程記錄是無價的。

最後和最重要的缺點是協調變更。 在真正的微服務應用程式中,服務之間不應該有部署相依性。 應該可以依任何順序部署服務 A、B 和 C,因為它們有鬆散結合。 不過,事實上,有時最好同時進行跨越多個存放庫的變更。 一些範例包括更新連結庫以關閉安全性漏洞,或變更所有服務所使用的通訊協定。

若要進行跨存放庫變更,必須依次提交每個存放庫的變更。 每個儲存庫中的每次變更都必須個別提交拉取請求並進行審核。 此活動可能難以協調。

使用許多存放庫的替代方法是將所有原始程式碼放在一個巨大的單一存放庫中。

單一存放庫

在這種方法中,有時稱為 monorepository,每個服務的原始程式碼都會放入相同的存放庫中。 起初,這種方法似乎是個糟糕的主意,很可能會使處理原始程式碼變得笨拙。 然而,以這種方式工作有一些明顯的優點。

第一個優點是更容易管理項目之間的相依性。 專案可以直接彼此進口,而不是依賴某些外部成品供應。 這表示更新是即時的,而且在開發人員工作站上的編譯時可能會發現衝突的版本。 實際上,將一些整合測試左移。

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

另一個優點是,可以在單一提交中跨服務邊界進行廣泛的變更。 此活動可減少可能需要個別檢閱的潛在數十個變更的負擔。

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

單一存放庫方法也有許多缺點。 其中一個最令人擔憂的是,擁有單一存放庫會引發安全性考慮。 如果每個服務模型存放庫中的存放庫內容外泄,遺失的程式代碼數量最少。 使用單一存放庫,公司擁有的一切都可能會丟失。 過去發生了許多例子,破壞了整個遊戲開發工作。 擁有多個存放庫會減少暴露面積,這是大多數安全實務中理想的特點。

單一存放庫的大小可能會快速變成無法管理。 這會產生一些有趣的效能影響。 可能需要使用特殊化工具,例如 Git 虛擬文件系統,其原本是設計來改善 Windows 小組開發人員的體驗。

使用單一存放庫的自變數通常會歸結為 Facebook 或 Google 將此方法用於原始程式碼排列的自變數。 如果這種方法對這些公司來說已經足夠好,那麼,當然,這是所有公司的正確方法。 事實是,很少有公司像Facebook或谷歌的規模一樣經營。 這些規模發生的問題與大多數開發人員將面臨的問題不同。 對公鵝好的東西未必對母鵝也好。

最後,任一解決方案都可以用來裝載微服務的原始程式碼。 不過,在大部分情況下,單一存放庫的管理和工程上的額外負荷所帶來的微小優勢並不值得。 將程式代碼分割成多個存放庫可鼓勵更好的關注區隔,並鼓勵開發小組之間的自主性。

標準目錄結構

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

圖 10-4 電子郵件和登入服務的標準目錄結構

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

每當建立新的專案時,就應該使用放置正確結構的範本。 此樣本也可以包含這類有用的項目,例如範本 README 檔案和 azure-pipelines.yml。 在任何微服務架構中,專案之間的高度差異會使對服務進行大量作業更加困難。

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

工作管理

管理任何專案中的工作可能很困難。 在前面,有無數問題可以回答關於要設定的工作流程類型,以確保最佳的開發人員生產力。

雲端原生應用程式通常小於傳統軟體產品,或至少分成較小的服務。 追蹤與這些服務相關的問題或工作,與任何其他軟體項目一樣重要。 沒有人想失去某工作項目的追蹤,或向客戶解釋其問題未被妥善記錄。 面板是在專案層級設定,但在每個專案中,可以定義區域。 這些功能可將問題分解到不同的元件中。 將整個應用程式的所有工作保留在一個地方的優點是,更容易將工作專案從一個小組移到另一個小組,因為他們更容易瞭解。

Azure DevOps 隨附許多預先設定的熱門範本。 在最基本的組態中,需要知道的是待辦專案的內容、人員正在處理的工作,以及完成的工作。 重要的是要瞭解建置軟體的過程透明度,以便優先排序工作並向客戶回報已完成的任務。 當然,很少有軟體專案遵循像to dodoingdone一樣簡單的流程。 人們很快就會開始新增像是 QADetailed Specification 的步驟到過程中。

敏捷式方法的其中一個重要部分是定期自我反省。 這些評論旨在讓您深入瞭解小組所面對的問題,以及如何加以改善。 這通常表示透過開發程式變更問題和功能流程。 擴充版面的布局加入額外階段是合適且有益的。

面板中的階段並不是唯一的組織工具。 根據面板的組態,會有工作專案的階層。 最細微的項目可以出現在看板上是任務。 預設情況下,任務包含欄位:標題、描述、優先順序、剩餘工作量的估計,以及連結至其他工作項目或開發項目的功能(分支、提交、合併請求、構建等等)。 工作項目可以分類為應用程式的不同區域和不同的迭代(短期衝刺),使查找它們變得更容易。

圖 10-5 Azure DevOps 中的範例工作

圖 10-5 - Azure DevOps 中的工作。

[描述欄位] 支援常用的樣式(粗體、斜體、底線和刪除線),以及插入圖片的功能。 這可讓它成為在指定工作或 Bug 時使用的強大工具。

工作可以整合進功能,以定義較大的工作項目。 接著,功能可以 匯總成 Epic。 將任務分類在這個層級中可讓您更輕鬆地瞭解大型功能距離發佈有多近。

圖 10-6 基本程式範本中預設設定的工作項目類型

圖 10-6 - Azure DevOps 中的工作專案。

在 Azure Boards 中,有不同類型的議題檢視模式。 尚未排程的專案會出現在待辦專案中。 從那裡,他們可以被指派到衝刺期。 衝刺是一個時間框架,在此期間預計會完成一些工作。 這項工作可以包含任務,以及票證的處理。 一旦到達那裡,就可以從衝刺看板區段管理整個衝刺。 此檢視會顯示工作進展情況,並包含一個燃盡圖,以持續更新衝刺成功的可能性預估。

圖 10-7 已定義短期衝刺的面板

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

現在應該很明顯,Azure DevOps 中的 Boards 功能強大。 對於開發人員來說,有容易查看正在進行的工作。 專案經理可檢視即將進行的工作並概覽現有工作。 對於管理者來說,有很多有關資源和產能的報告。 ** 可惜的是,雲端原生應用程式並沒有什麼神奇之處可以消除追蹤工作的必要性。 但是,如果您必須追蹤工作,某些地方的體驗優於在 Azure DevOps 中的體驗。

CI/CD 管線

在軟體開發生命週期中,幾乎沒有其他變化像持續整合(CI)和持續交付(CD)的出現那樣具有革命性。 在簽入變更時,立即針對專案的原始程式碼建置和執行自動化測試,會提早攔截錯誤。 在持續整合組建出現之前,從存放庫提取程式碼並發現它未通過測試或甚至無法建置,並不罕見。 這導致追蹤到故障的來源。

傳統上,將軟體寄送到生產環境需要廣泛的檔和步驟清單。 在容易出錯的程式中,需要手動完成上述每個步驟。

圖 10-8 檢查清單

圖 10-8 - 檢查清單。

持續整合的伴侶是持續交付,其中剛建置的套件會部署到一個環境。 手動程式無法調整以符合開發速度,因此自動化變得更加重要。 檢查清單會由腳本取代,這些腳本可以比任何人員更快且更準確地執行相同的工作。

持續交付的環境可能是測試環境,或者,如同許多主要科技公司正在做的一樣,可能是生產環境。 後者需要投資於高品質的測試,以提供信心,確保任何變更不會打斷用戶的生產環境。 正如持續整合能在程式碼初期抓住問題一樣,持續交付能在部署過程初期檢測到問題。

雲端原生應用程式強調了自動化建置和交付流程的重要性。 部署次數變得更加頻繁,且涉及的環境更多,手動進行部署幾乎變得不可能。

Azure 建置

Azure DevOps 提供一組工具,讓持續整合和部署比以往更容易。 這些工具位於 Azure Pipelines 底下。 其中第一個是 Azure 組建,這是大規模執行 YAML 型組建定義的工具。 用戶可以攜帶自己的建置機器(非常適合需要精心配置環境的建置工作),或者使用來自 Azure 託管虛擬機器的不斷更新的集區的電腦。 這些裝載的組建代理程式會預安裝各種開發工具,不僅適用於 .NET 開發,而且適用於從 Java 到 Python 到 iPhone 開發的所有專案。

DevOps 包含各種現成可用的組建定義,可針對任何組建自定義。 組建定義是在名為 azure-pipelines.yml 的檔案中定義,並簽入存放庫,以便與原始程式碼一起進行版本設定。 這使您更容易在分支中變更組建管線,因為您可以將變更提交到該分支。 在完整架構上建置 ASP.NET Web 應用程式的範例 azure-pipelines.yml 如圖 10-9 所示。

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環境以進行手動測試。 最後,程式代碼會推送至生產環境,讓每個人都可以看到該程序代碼。

圖 10-10 具有開發、QA 和生產階段的範例發行管線

圖 10-10 - 發行流程

建置中的每個階段都可以由上一個階段完成自動觸發。 不過,在許多情況下,這並不理想。 將程式代碼移至生產環境可能需要某人的核准。 Releases 工具可藉由在發行管線的每個步驟上允許核准者來支援此功能。 您可以設定規則,讓特定人員或人員群組在進入正式環境之前,必須先批核發行。 這些閘道允許手動質量檢查,也允許遵守任何與控制進入生產環境相關的法規需求。

每個人都會取得組建管線

設定許多建置管線不需要任何成本,因此每個微服務至少要有一個組建管線是有好處的。 在理想情況下,微服務可獨立部署至任何環境,因此讓每個微服務都能透過自己的管線發行,而不會釋放大量不相關的程式代碼是完美的。 每個管線可以擁有一套自己的審批流程,以允許每個服務的建置過程有所不同。

版本發佈管理

使用 Releases 功能的其中一個缺點是無法在已提交的 azure-pipelines.yml 檔案中定義。 您可能想要這樣做的原因有很多,從具有個別分支發行定義到在專案範本中包含發行基本架構。 幸運的是,工作正在進行中,將部分階段支持轉移到組建元件中。 這稱為多階段組建,且 第一個版本現已推出