Terraform 工作流程:合併前應用 vs 合併後應用
如果您曾經管理過雲基礎設施, 您可能遇到過 Terraform, 這是該領域最流行的基礎設施即代碼工具。2023 年, Hashicorp 配置語言 (HCL) 再次成爲 GitHub 年度 Octoverse 報告 [1] 中增長最快的語言之一, 同比增長 36%。
隨着採用率的提高, 團隊一次又一次地面臨同樣的問題:
" 我們應該在將拉取請求合併回主分支後運行 terraform apply
, 還是在合併之前運行?"
在本文中, 我們將研究這兩種不同的方法, 並回答生命的終極問題。
關於 Terraform 的有狀態性質
基礎設施即代碼工具 (如 Terraform 和 OpenTofu) 的 CI/CD 與用於應用程序的管道不同, 因爲 Terraform 嚴重依賴於狀態, 該狀態描述了最新部署(由 terraform apply
觸發) 的結果。
將 Terraform 和 OpenTofu 中的狀態視爲單一事實來源, 其中包含所有信息, 如配置和元數據, 以及敏感值, 如雲基礎設施的機密。
團隊通常使用 遠程後端 [2] , 如 AWS S3 或 Google Cloud Storage, 來對狀態文件進行版本控制、安全保護和加密。
與其他可以獨立並行運行的 CI 管道不同, Terraform 的 CI 管道可以讀取和修改狀態。這使得它們在使用單個狀態文件時不適合並行化。
以下是有關 Terraform 中狀態及其影響的一些事實:
-
Terraform 狀態的主要目的是存儲遠程系統中的對象與配置中聲明的資源實例之間的綁定。
-
因此, Terraform 的狀態充當數據庫, 將 Terraform 配置映射到現實世界 (已部署的雲基礎設施)。
-
Terraform 狀態還跟蹤元數據, 如資源依賴關係。
-
Terraform 使用遠程鎖定來防止多個用戶意外地同時在同一配置和狀態上運行 Terraform。這確保每次 Terraform 運行都從最新更新的狀態開始。
-
在給定時間內, 每個狀態只能調用一次
terraform apply
。默認情況下, 每次apply
都會爲當前運行獨佔鎖定狀態, 使其不適合並行部署。
Terraform 的有狀態性質使得每次運行 terraform apply
都可能依賴於任何其他運行。這意味着, 與傳統的 CI 不同, 每個管道都可以獨立並行運行, Terraform 管道通常按順序運行, 因此是阻塞的 (一次只能運行一個調用 terraform apply
的工作流)。
Terraform 工作流程
現在我們知道 Terraform 管道必須按順序運行, 讓我們來研究兩種最常見的工作流程。
合併後應用
這個工作流程確保主分支始終反映基礎設施的期望狀態。目標是在這個期望狀態和已部署資源的實際狀態之間達成 1:1 的映射。
工作流程
-
打開引入一些更改的 PR。
-
CI/CD 管道檢查代碼的正確性 (例如
terraform fmt
、terraform validate
、terraform test
), 運行測試和第三方工具 。[3] 它還爲每次提交生成一個可供審閱者查看的計劃terraform plan
。 -
審閱者審查代碼, 請求更改或批准拉取請求。
-
一旦拉取請求合併回主分支, 管道就會應用步驟 2 中創建的最新審查過的計劃, 以準確部署審閱者批准的更改。
優點
-
主分支始終充當單一事實來源 (因此反映基礎設施的當前狀態)。
-
在應用操作之前解決來自不同進行中 PR 的衝突, 防止對資源的實際狀態產生影響。
-
通過避免合併前驗證的複雜性來簡化 CI/CD 管道。
缺點
-
僅在合併後向開發人員提供反饋, 這會減慢調試和問題解決的速度。
-
從合併後的失敗部署中恢復可能具有挑戰性和破壞性。例如, 如果應用在合併回主分支時失敗, 則需要額外的拉取請求。這可能會使主分支因糾正失敗的應用操作的迭代步驟而變得雜亂。
合併後應用
工作流程的美妙之處在於其簡單性。在大多數通用 CI/CD 提供商 (如 GitHub Actions、GitLab CI/CD、BitBucket Pipelines 等) 中, 無需額外的基礎設施或工具即可配置此工作流程。
問題所在:不穩定的應用
應用後合併工作流程的最大缺點是,大多數 Terraform 錯誤在計劃階段是不可見的。例如,在運行應用時經常會遇到權限問題、錯誤配置或達到配額等邊緣情況,這些在計劃階段無法捕獲。
原因是許多提供商無法在應用更改之前進行深入驗證。例如,AWS 提供商大多能夠在嘗試應用 S3 存儲桶之前驗證其配置是否正確;但是,提供商無法知曉您的 AWS 賬戶中配置的任何阻止創建公共存儲桶的策略。如果存在這樣的策略,應用將失敗。
這常常給團隊一種錯誤的信念,認爲看似準備好合併的拉取請求將毫無問題地部署,只是在點擊合併按鈕後纔不愉快地感到驚訝。
這些可能性使應用階段成爲工作流程中不可預測的部分。例如,當應用失敗時,唯一的修復方法是在網絡問題(如超時)的情況下重新運行管道,或打開新的拉取請求以修復錯誤配置。這會讓開發人員再次經歷整個循環,可能會耗費時間並影響開發人員的神經。
合併前應用
不穩定的應用是一些團隊採用 "合併前應用" 工作流程的主要原因,允許他們在拉取請求中通過評論或任何其他觸發器在將更改合併回主分支之前應用更改。
這在需要時處理 PR 中的失敗,然後將新的基礎設施代碼合併到默認分支中。它承諾保持主分支的整潔,沒有迭代步驟的雜亂。
工作流程
-
打開引入一些更改的 PR。
-
CI/CD 管道檢查代碼的正確性(例如
terraform fmt
、terraform validate
、terraform test
),運行測試和第三方工具。它還爲每次提交生成一個terraform plan
,供審閱者查看。 -
審閱者查看代碼更改和計劃文件。
-
審閱者或作者在 PR 內觸發應用(可選擇經常創建新計劃也可以觸發)。
-
管道從步驟 2 獲取持久化的計劃文件,並使用先前生成的計劃文件運行
terraform apply
。 -
一旦
terraform apply
成功運行,PR 就會合併到主分支中。
優點
-
保證只有成功驗證和應用的更改纔會合併並集成到主分支中。
-
在更改到達主分支之前捕獲錯誤和問題,保持主分支的 git 歷史整潔。
-
提高迭代速度,對於修復特定環境中失敗的應用運行很有用。
缺點
-
主分支通常落後於雲基礎設施的實際狀態,這與 GitOps 教導我們的一切相違背。此外,如果有多個 PR,哪一個代表所需狀態?
-
開發人員開始花費大量時間重新基於分支以拉取最新更改並避免衝突。
-
增加設置和維護支持合併前應用的管道所需的複雜性和時間。
-
需要額外的工具來防止競爭條件和衝突。
-
這通常會導致鎖定衝突,從而帶來糟糕的協作體驗。
-
需要 RBAC 或類似的權限管理來管理誰可以觸發計劃和應用。
雖然 "合併前應用" 承諾解決不穩定應用的問題,但它帶來了額外的複雜性和成本。這意味着每當您想從拉取請求內應用更改時,您將面臨一系列全新的問題需要解決:
-
我們如何防止多個拉取請求向相同資源添加更改,從而導致衝突?
-
我們如何確保 PR 總是在運行應用後合併?
-
我們如何在 PR 內的評論等事件上編排
terraform plan
和terraform apply
等命令? -
我們如何限制只有某些個人和團隊才能運行例如
terraform apply
?
開源和商業供應商如 Atlantis[4] 、 Digger[5] 和 Terrateam[6] 存在,提供工具來克服這些挑戰,具有 PR 級鎖定、自動計劃和自動合併等功能。
雖然有工具可以解決複雜工作流程引入的問題很好,但是否應該考慮 "合併前應用" 工作流程仍然值得爭議。
何時使用合併後應用與合併前應用
所以現在我們已經瞭解了 apply-after-merge
和 apply-before-merge
工作流程的區別, 應該使用哪一個呢? 請看以下比較, 以詳細瞭解基於您的環境的潛在影響:
基於上述事實, 我們認爲大多數團隊應該使用 apply-after-merge
工作流程, 因爲它易於採用和管理, 衝突的可能性較小, 不需要額外的工具, 並確保主分支始終作爲單一的事實來源!
單體狀態的問題
apply-before-merge
往往在單體和大型狀態文件中更有問題。例如, 如果您使用 apply-before-merge
, 引入對單個 Terraform 狀態更改的單個 Pull Request 將鎖定所有其他使用稱爲 PR 級鎖定的概念的 Pull Request, 以避免衝突。因此, 團隊在處理單體狀態文件時只能一次處理一個 Pull Request。
除非您將狀態拆分爲多個較小的狀態文件, 否則像 apply-before-merge
這樣的工作流程很有可能會阻礙您的工程速度。
事實上, 拆分狀態被認爲是最佳實踐 [7] , 可以限制影響範圍, 加快 CI/CD 運行時間, 並在處理大型 IaC 代碼庫時實現更好的協作。
額外收穫: 通過查看 5000 個真實 IaC 部署學到的經驗
在 Terramate, 我們與客戶密切合作, 以確定最適合他們需求的工作流程。總的來說, 我們的團隊已經審查了超過 5000 個 Terraform 部署, 趨勢很明顯: apply-before-merge
更有可能在長期內造成問題並減慢團隊速度, 更不用說需要額外工具帶來的複雜性了。
使用 apply-before-merge 策略, 更改可能在 Pull Request 中多次成功應用, 這給人一種虛假的穩定感。在任何時候, main
分支中看似穩定的代碼都可能因外部數據源 (如 SSM 參數) 或不太嚴格的版本固定而中斷。因此, 無論您如何合併, 識別故障 (例如, 通過漂移檢測) 都是至關重要的。通過實施 apply-after-merge
, 可以大大降低引入循環的可能性。
總結本文, 這裏有一個關於 豐田生產系統 [8] "安燈繩" 的軼事。在九十年代, 豐田擁有世界上最高效的汽車工廠。其他汽車製造商的高管參觀了生產設施, 無法相信每個在裝配線上工作的人都可以關閉整個系統——這是多麼浪費生產力啊。
但實際上, 關閉整個系統, 識別問題並一次解決一個, 是保持裝配線順利運行的關鍵成功因素之一。同樣的原則也適用於基礎設施即代碼的工作流程。如果主分支不穩定, 絕對必須首先解決, 並識別和解決根本原因。
當您 apply-after-merge
時, 上述問題就不會發生。合併的代碼會被應用, 您會有一個很好的、有序的事件序列。
總結
在本文中, 我們瞭解了 Terraform 和 OpenTofu 中可用的不同工作流程。本文的主要要點是, 簡單性是可靠性和穩定性的關鍵驅動因素, 這就是爲什麼團隊應該專注於採用 apply-after-merge
來管理他們的 IaC 部署。
如果您一直堅持到最後, 謝謝您。如果您有興趣瞭解如何使用通用 CI/CD 系統設置 apply-after-merge
管道, 我們建議您查看我們的 Terraform 和 OpenTofu CI/CD 藍圖 [9] , 這是一系列預配置的生產級工作流程, 用於在 GitHub Actions[10] 和 GitLab CI/CD[11] 中採用 apply-after-merge
工作流程。每個藍圖都帶有預配置的預覽、部署和漂移檢測管道, 可幫助您快速啓動和運行 Terraform 和 OpenTofu 自動化!
此外, 我們很想了解您正在使用的工作流程以及原因。歡迎加入我們的 Discord 社區 [12] 並分享您的設置詳情。
參考鏈接
- Octoverse 報告: https://github.blog/2023-11-08-the-state-of-open-source-and-ai/
- 遠程後端: https://developer.hashicorp.com/terraform/language/settings/backends/remote
- 。: http://tooling.it/
- Atlantis: https://www.runatlantis.io/
- Digger: https://digger.dev/
- Terrateam: https://terrateam.io/
- 拆分狀態被認爲是最佳實踐: https://terramate.io/rethinking-iac/why-you-should-break-down-your-terraform-into-stacks/
- 豐田生產系統: https://www.sixsigmadaily.com/what-is-an-andon-cord/
- Terraform 和 OpenTofu CI/CD 藍圖: https://terramate.io/docs/cli/automation/
- GitHub Actions: https://terramate.io/docs/cli/automation/github-actions/
- GitLab CI/CD: https://terramate.io/docs/cli/automation/gitlab-ci/
- Discord 社區: https://terramate.io/discord
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/dvcxnWFmjPiS2QG9POk-2A