本文已超過一年。較舊的文章可能包含過時的內容。請檢查頁面中的資訊自發布以來是否已變得不正確。
與 Kluctl 和伺服器端套用共存共榮
這篇部落格文章的靈感來自先前一篇關於 進階伺服器端套用 的 Kubernetes 部落格文章。該部落格文章的作者列出了應用程式和控制器在切換到伺服器端套用(以下簡稱 SSA)時的多項優點。尤其是關於 CI/CD 系統 的章節,促使我做出回應並寫下我的想法和經驗。
這些想法和經驗是我過去 2 年在 Kluctl 上工作的成果。我將 Kluctl 描述為「將大型 Kubernetes 部署組合在一起的缺失環節,這些部署由多個較小的部分 (Helm/Kustomize/...) 以可管理且統一的方式組成。」
為了基本了解 Kluctl,我建議造訪 kluctl.io 網站並閱讀文件和教學課程,例如 微服務示範教學課程。或者,您可以觀看 Rawkode Academy YouTube 頻道上的 Kluctl 實作介紹,其中展示了實作示範課程。
還有一個 Kluctl 交付情境 用於 podtato-head 示範專案。
活著也讓別人活
Kluctl 遵循的主要哲學之一是 「活著也讓別人活」,這表示它將盡力與在您的叢集外部或內部運行的任何其他工具或控制器協同工作。除非您明確告知,否則 Kluctl 不會覆寫它失去所有權的任何欄位。
如果沒有使用 SSA,則不可能(或至少困難數倍)實現這一點。伺服器端套用允許 Kluctl 偵測到何時遺失欄位的擁有權,例如當另一個控制器或運算子將該欄位更新為另一個值時。然後,Kluctl 可以根據這些決策,逐欄位決定是否需要在重試之前強制套用。
SSA 之前的日子
Kluctl 的第一個版本基於 shell 輸出到 kubectl
,因此隱式地依賴於用戶端套用。當時,SSA 仍處於 alpha 階段,並且錯誤很多。老實說,我當時甚至不知道有 SSA 這回事。
用戶端套用的工作方式有一些嚴重的缺點。最明顯的一個缺點(如果時間足夠長,您肯定會自己偶然發現)是它依賴於添加到物件的註解 (kubectl.kubernetes.io/last-applied-configuration
),從而帶來了巨大註解值的所有限制和問題。此類問題的一個很好的例子是 CRD 太大,以至於它們不再適合註解的值。
另一個缺點可以透過查看名稱(用戶端套用)來發現。用戶端端表示每個用戶端都必須自行提供套用邏輯,而當時只有在 kubectl
內部正確實作了套用邏輯,這使得很難在控制器內部複製。
這將 kubectl
作為相依性(以可執行檔或 Go 套件的形式)新增到所有想要利用套用邏輯的控制器。
但是,即使有人設法從控制器內部運行用戶端套用,您最終得到的解決方案也無法控制其內部工作方式。例如,在發生外部變更的情況下,無法個別決定要覆寫哪些欄位以及要放棄哪些欄位。
發現 SSA 套用
我從未對上述解決方案感到滿意,然後不知何故偶然發現了 伺服器端套用,當時它仍處於 beta 階段。透過 kubectl apply --server-side
進行實驗立即揭示,SSA 的真正威力無法透過 shell 輸出到 kubectl
來輕鬆利用。
kubectl
中實作 SSA 的方式不允許對衝突解決進行足夠的控制,因為它只能在「不強制套用任何內容並產生錯誤」和「強制套用所有內容而不顯示任何寬恕!」之間切換。
然而,API 文件明確指出,SSA 能夠透過簡單地選擇要包含哪些欄位以及要從提供的物件中省略哪些欄位,來控制欄位層級的衝突解決。
遠離 kubectl
這表示 Kluctl 必須先遠離 shell 輸出到 kubectl
。只有在完成此操作後,我才能正確地實作具有強大衝突解決能力的 SSA。
為了實現這一點,我首先實作了透過 Kubernetes 用戶端程式庫存取目標叢集。這也產生了顯著加快 Kluctl 速度的良好副作用。它還透過確保正在運行的 Kluctl 命令不會因在運行時外部修改 kubeconfig 而被打亂,從而提高了 Kluctl 的安全性和可用性。
實作 SSA
在切換到 Kubernetes 用戶端程式庫後,利用 SSA 感覺很容易。Kluctl 現在必須將每個 manifest 作為 PATCH
請求的一部分傳送到 API 伺服器,這表示 Kluctl 想要執行 SSA 操作。然後,API 伺服器會以 OK 回應(HTTP 狀態碼 200)或 Conflict 回應(HTTP 狀態 409)回應。
如果收到 Conflict 回應,則該回應的主體包含有關衝突的機器可讀詳細資訊。然後,Kluctl 可以使用這些詳細資訊來找出哪些欄位發生衝突,以及哪些參與者(欄位管理員)取得了衝突欄位的擁有權。
然後,對於每個欄位,Kluctl 將決定是否應忽略衝突,或者是否應強制套用衝突。如果任何欄位需要強制套用,Kluctl 將在忽略的欄位被省略且 API 呼叫上設定 force
標誌的情況下重試套用操作。
如果忽略衝突,Kluctl 將向用戶發出警告,以便用戶可以做出適當的反應(或永遠忽略它...)。
基本上就是這樣。這就是利用 SSA 所需的全部內容。非常感謝並讚揚 Kubernetes 開發人員使其成為可能!
衝突解決
Kluctl 有一些簡單的規則來判斷是否應忽略或強制套用衝突。
它首先根據常用於執行手動修改的工具中的已知欄位管理員字串清單檢查欄位的參與者(欄位管理員)。這些工具例如 kubectl
和 k9s
。使用這些工具執行的任何修改都被視為「暫時性」,並將被 Kluctl 覆寫。
如果您將 Kluctl 與 kubectl
一起使用,並且不希望覆寫 kubectl
中的變更(例如,在腳本中使用),則可以在命令列上為 kubectl
指定 --field-manager=<manager-name>
,並且 Kluctl 不會套用其特殊的啟發法。
如果 Kluctl 不知道欄位管理員,它將檢查是否已請求對該欄位強制套用。可以透過不同的方式請求強制套用
- 透過將
--force-apply
傳遞給 Kluctl。這將導致在發生衝突時強制套用所有欄位。 - 透過將
kluctl.io/force-apply=true
註解新增到相關物件。這將導致在發生衝突時強制套用該物件的所有欄位。 - 透過將
kluctl.io/force-apply-field=my.json.path
註解新增到相關物件。這只會導致在發生衝突時強制套用與 JSON 路徑相符的欄位。
每當已知某些其他參與者錯誤地聲明欄位時(例如,ECK 運算子對 nodeSets 欄位執行此操作),都需要將欄位標記為強制套用,您可以確保 Kluctl 始終將這些欄位覆寫為原始值或新值。
未來,Kluctl 將允許對衝突解決進行更多控制。例如,CLI 將允許在欄位層級控制強制套用。
DevOps 與控制器
那麼 Kluctl 中的 SSA 如何實現「活著也讓別人活」?
它允許傳統管道(例如 Github Actions 或 Gitlab CI)、控制器(例如 HPA 控制器或 GitOps 樣式控制器)甚至從本機運行部署的管理員共存。
無論您在基礎架構自動化旅程中的哪個位置,Kluctl 都能為您找到一席之地。從在您的 PC 上使用腳本運行部署,一直到使用程式碼定義的管道進行完全自動化的 CI/CD,Kluctl 旨在補充適合您的工作流程。
即使在完全自動化所有內容之後,您也可以在需要時使用您的管理員權限進行干預,並運行 kubectl
命令來修改欄位並阻止 Kluctl 覆寫它。您只需切換到 Kluctl 不會覆寫的欄位管理員(例如「admin-override」)。
一些重點
伺服器端套用是一項很棒的功能,對於 Kubernetes 中控制器和工具的未來至關重要。所涉及的控制器數量只會越來越多,而適當的協同工作模式是必須的。
我相信與 CI/CD 相關的控制器和工具應利用 SSA 來執行適當的衝突解決。我也相信其他控制器(例如 Flux 和 ArgoCD)也會受益於欄位層級的相同類型衝突解決控制。
共同努力並制定一套標準化的註解來控制與 CI/CD 相關工具的衝突解決,這甚至可能是一個好主意。
另一方面,與 CI/CD 無關的控制器應確保它們在修改物件時不會造成不必要的衝突。根據 伺服器端套用文件,強烈建議控制器始終執行強制套用。在遵循此建議時,控制器應真正確保僅在套用的物件中包含與控制器相關的欄位。否則,肯定會發生不必要的衝突。
在許多情況下,控制器的目的是僅修改它們管理的物件的狀態子資源。在這種情況下,控制器應僅修補狀態子資源,而不應觸及實際物件。如果遵循此做法,則不可能發生衝突。
如果您是這類控制器的開發人員,並且不確定您的控制器是否符合上述規範,只要嘗試檢索由您的控制器管理的物件,並查看 managedFields
(您需要將 --show-managed-fields -oyaml
傳遞給 kubectl get
),以查看是否有任何欄位被意外宣告。