3 路合併到 werf:使用 Helm 部署到 Kubernetes

我們(不僅僅是我們)等待已久的事情發生了: 韋爾夫,我們用於構建應用程式並將其交付到 Kubernetes 的開源實用程序,現在支援使用 3 路合併補丁來應用更改! 除此之外,還可以將現有的 K8s 資源採用到 Helm 版本中,而無需重建這些資源。

3 路合併到 werf:使用 Helm 部署到 Kubernetes

如果它很短,那我們把 WERF_THREE_WAY_MERGE=enabled - 我們得到部署「如 kubectl apply”,與現有的 Helm 2 安裝相容,甚至更多。

但讓我們從理論開始:三向合併修補到底是什麼,人們是如何想出產生它們的方法的,以及為什麼它們在基於 Kubernetes 基礎設施的 CI/CD 流程中很重要? 之後,讓我們看看 werf 中的 3-way-merge 是什麼,預設使用哪些模式以及如何管理它。

什麼是三向合併補丁?

因此,我們首先將 YAML 清單中所述的資源部署到 Kubernetes 中。

為了使用資源,Kubernetes API 提供了以下基本操作:建立、修補、取代和刪除。 假設在他們的幫助下,有必要建構一個方便的、連續的資源向叢集的部署。 如何?

kubectl 命令式指令

在 Kubernetes 中管理物件的第一種方法是使用 kubectl 命令式指令來建立、修改和刪除這些物件。 簡單的說:

  • 團隊 kubectl run 您可以執行部署或作業:
    kubectl run --generator=deployment/apps.v1 DEPLOYMENT_NAME --image=IMAGE
  • 團隊 kubectl scale — 更改副本數量:
    kubectl scale --replicas=3 deployment/mysql
  • 等等

乍一看,這種方法似乎很方便。 但也存在問題:

  1. 這個很難(硬 自動化.
  2. 反映配置 在 Git 中? 如何查看叢集發生的變化?
  3. 如何提供 再現性 重啟時的配置?
  4. ...

顯然,這種方法不太適合將應用程式和基礎設施儲存為程式碼(IaC;甚至 Git 操作 作為一種更現代的選擇,在 Kubernetes 生態系統中越來越受歡迎)。 因此,這些命令在 kubectl 中沒有進一步的開發。

建立、取得、取代和刪除操作

與初級 創建 很簡單:將清單傳送給操作人員 create kube api 和資源已建立。 清單的 YAML 表示形式可以儲存在 Git 中並使用以下命令建立 kubectl create -f manifest.yaml.

С 去除 也很簡單:替換相同的 manifest.yaml 從 Git 到團隊 kubectl delete -f manifest.yaml.

手術 replace 允許您用新的配置完全取代資源配置,而無需重新建立資源。 這意味著在對資源進行更改之前,使用以下操作查詢當前版本是合乎邏輯的 get,更改它並通過操作更新它 replace。 內建 kube apiserver 樂觀鎖定 並且,如果手術後 get 物件發生了變化,那麼操作 replace 這是行不通的。

要將配置儲存在 Git 中並使用替換更新它,您需要執行以下操作 get,將 Git 中的配置與我們收到的配置合併,然後執行 replace。 預設情況下,kubectl只允許你使用指令 kubectl replace -f manifest.yaml哪裡 manifest.yaml — 需要安裝的已經完全準備好的(在我們的例子中是合併的)清單。 事實證明,用戶需要實現合併清單,這不是一件小事...

還值得注意的是,雖然 manifest.yaml 並且儲存在Git中,我們無法事先知道是否需要建立一個物件或更新它——這必須由使用者軟體來完成。

合計: 我們可以持續推出嗎 僅使用建立、替換和刪除,確保基礎架構配置與程式碼一起儲存在 Git 中並方便 CI/CD?

原則上,我們可以...為此 您將需要實施合併操作 宣言和某種約束力:

  • 檢查集群中是否存在對象,
  • 執行初始資源創建,
  • 更新或刪除它。

更新時請注意 資源可能已更改 自上次以來 get 並自動處理樂觀鎖定的情況 - 進行重複的更新嘗試。

然而,當 kube-apiserver 提供了另一種更新資源的方式時,為什麼要重新發明輪子:操作 patch,這可以緩解用戶所描述的一些問題?

打補丁

現在我們來看看補丁。

補丁是將變更應用於 Kubernetes 中現有物件的主要方式。 手術 patch 它的工作原理如下:

  • kube-apiserver 使用者需要傳送 JSON 形式的補丁並指定對象,
  • apiserver 本身將處理物件的目前狀態並將其轉換為所需的形式。

在這種情況下不需要樂觀鎖定。 此操作比替換更具聲明性,儘管乍看之下似乎相反。

因此:

  • 使用操作 create 我們根據 Git 的清單建立一個對象,
  • 在...的幫助下 delete — 如果不再需要該對象,則刪除,
  • 在...的幫助下 patch — 我們更改對象,將其變為 Git 中描述的形式。

然而,要做到這一點,您需要創建 正確的補丁!

補丁在 Helm 2 中的工作原理:2 路合併

當您首次安裝版本時,Helm 會執行以下操作 create 用於圖表資源。

更新每個資源的 Helm 版本時:

  • 考慮上一個圖表的資源版本與目前圖表版本之間的補丁,
  • 套用此補丁。

我們將這個補丁稱為 2路合併補丁,因為它的創建涉及兩個宣言:

  • 先前版本的資源清單,
  • 目前資源的資源清單。

刪除操作時 delete 在 kube apiserver 中,會呼叫在上一版本中宣告但在目前版本中未宣告的資源。

2 路合併補丁方法有一個問題:它會導致 與叢集中資源的真實狀態和 Git 中的清單不同步.

用例子說明問題

  • 在 Git 中,圖表儲存一個清單,其中字段 image 部署很重要 ubuntu:18.04.
  • 用戶透過 kubectl edit 將該欄位的值變更為 ubuntu:19.04.
  • 重新部署 Helm 圖表時 不產生補丁,因為場 image 先前版本的發行版和目前圖表中的內容是相同的。
  • 重新部署後 image 遺體 ubuntu:19.04,儘管圖表顯示 ubuntu:18.04.

我們失去了同步性並失去了聲明性。

什麼是同步資源?

一般來說 充分 無法取得正在運行的叢集中的資源清單與來自 Git 的資源清單之間的匹配。 因為在真實的清單中可能存在服務註釋/標籤、附加容器和其他由某些控制器動態新增和從資源中刪除的資料。 我們不能也不想將這些資料保留在 Git 中。 但是,我們希望在 Git 中明確指定的欄位在推出時採用適當的值。

原來如此一般 同步資源規則:推出資源時,您只能變更或刪除 Git 清單中明確指定的欄位(或在先前版本中指定但現在已刪除)。

3路合併補丁

大意 3路合併補丁:我們在 Git 的清單的最後應用版本和 Git 的清單的目標版本之間產生補丁,同時考慮到正在運行的叢集中清單的當前版本。 產生的補丁必須符合同步資源規則:

  • 新增到目標版本的新欄位是使用補丁新增的;
  • 使用補丁重置上次應用版本中先前存在且目標版本中不存在的欄位;
  • 物件目前版本中與清單目標版本不同的欄位將使用修補程式進行更新。

就是根據這個原理產生補丁的 kubectl apply:

  • 清單的最後應用版本儲存在物件本身的註解中,
  • target - 取自指定的 YAML 文件,
  • 當前的一個來自正在運行的叢集。

現在我們已經理清了理論,是時候告訴你我們在 werf 中做了什麼。

將變更應用於 werf

此前,werf 與 Helm 2 一樣,使用 2 路合併補丁。

修復補丁

為了切換到新類型的補丁 - 3-way-merge - 第一步我們引入了所謂的 修復補丁.

部署時,使用標準的2路合併補丁,但werf另外產生一個補丁,將資源的真實狀態與Git中編寫的內容同步(這樣的補丁是使用上述相同的同步資源規則創建的) 。

如果發生去同步,則在部署結束時,使用者會收到一條警告,其中包含相應的訊息以及必須套用的修補程式才能使資源達到同步形式。 這個補丁也記錄在專門的註釋中 werf.io/repair-patch。 假設用戶的手 他自己 將套用此補丁:werf 根本不會套用它。

產生修復補丁是一種臨時措施,可讓您實際測試基於三向合併原則的修補程式創建,但不會自動套用這些修補程式。 目前,該操作模式預設為啟用。

僅適用於新版本的三向合併補丁

從 1 年 2019 月 XNUMX 日開始,werf 的 beta 和 alpha 版本開始 默認情況下 使用成熟的 3 路合併修補程式僅將變更套用至透過 werf 推出的新 Helm 版本。 現有版本將繼續使用2路合併+修復補丁的方式。

可以透過設定明確啟用此操作模式 WERF_THREE_WAY_MERGE_MODE=onlyNewReleases 現在。

注意:此功能在 werf 中出現了多個版本:在 alpha 通道中,它已經準備好版本 v1.0.5-alpha.19,以及在測試版頻道中 - 與 v1.0.4-beta.20.

適用於所有版本的三向合併補丁

從 15 年 2019 月 3 日開始,werf 的 beta 和 alpha 版本開始預設使用完整的 XNUMX 路合併修補程式將變更套用至所有版本。

可以透過設定明確啟用此操作模式 WERF_THREE_WAY_MERGE_MODE=enabled 現在。

資源自動縮放該怎麼辦?

Kubernetes 中有兩種類型的自動縮放:HPA(水平)和 VPA(垂直)。

水平方向自動選擇副本數量,垂直方向-資源數量。 副本數量和資源需求均在資源清單中指定(請參閱資源清單)。 spec.replicasspec.containers[].resources.limits.cpu, spec.containers[].resources.limits.memory и 他人).

問題:如果使用者在圖表中配置資源,以便為資源或副本指定某些值,並且為此資源啟用自動縮放器,則每次部署時 werf 都會將這些值重設為圖表清單中寫入的值。

該問題有兩種解決方案。 首先,最好避免在圖表清單中明確指定自動縮放值。 如果由於某種原因該選項不適合(例如,因為可以輕鬆設定初始資源限制和圖表中的副本數量),則 werf 提供以下註釋:

  • werf.io/set-replicas-only-on-creation=true
  • werf.io/set-resources-only-on-creation=true

如果有這樣的註釋,werf將不會在每次部署上重設對應的值,而只會在最初建立資源時設定它們。

有關更多詳細信息,請參閱項目文檔 HPA и VPA.

禁止使用3路合併補丁

使用者目前可以使用環境變數禁止在werf中使用新補丁 WERF_THREE_WAY_MERGE_MODE=disabled。 然而,開始 自1年2020月XNUMX日起,該禁令將不再適用。 並且只能使用 3 路合併補丁。

採用werf中的資源

掌握了透過 3 路合併補丁套用變更的方法,使我們能夠立即實現將叢集中現有的資源採用到 Helm 版本中這樣的功能。

Helm 2 有一個問題:如果不從頭開始重新建立該資源,則無法將資源新增至叢集中已存在的圖表清單中(請參閱。 #6031, #3275)。 我們教導 werf 接受現有資源以進行釋放。 為此,您需要在正在運行的叢集中的資源的當前版本上安裝註釋(例如,使用 kubectl edit):

"werf.io/allow-adoption-by-release": RELEASE_NAME

現在需要在圖表中描述資源,下次 werf 部署具有適當名稱的版本時,現有資源將被接受到該版本中並保持在其控制之下。 此外,在接受資源釋放的過程中,werf 會使用相同的 3 路合併補丁和同步資源規則,將資源的當前狀態從正在運行的叢集帶到圖表中描述的狀態。

注意: 環境 WERF_THREE_WAY_MERGE_MODE 不影響資源的採用 - 在採用的情況下,請務必使用 3 路合併補丁。

詳細資訊 - 在 文件.

結論和未來計劃

我希望讀完這篇文章後,大家能夠更清楚什麼是三向合併補丁以及它們為何出現。 從werf專案開發的實際角度來看,它們的實施是改進Helm-like部署的另一步。 現在您可以忘記使用 Helm 3 時經常出現的設定同步問題。同時,Helm 版本中新增了一個新的實用功能,即採用已下載的 Kubernetes 資源。

類似 Helm 的部署仍然存在一些問題和挑戰,例如 Go 模板的使用,我們將繼續解決這些問題和挑戰。

有關資源更新方法和採用的資訊也可以在以下位置找到: 本文檔頁面.

頭盔3

值得特別注意的 釋放 就在前幾天,Helm 的新主要版本 - v3 - 也使用了 3 路合併補丁並擺脫了 Tiller。 新版本的 Helm 需要 移民 現有安裝將其轉換為新版本的儲存格式。

Werf 目前已經放棄使用 Tiller,改用 3-way-merge 並且添加了 蒙諾戈耶德魯戈耶,同時保持與現有 Helm 2 安裝的兼容性(無需執行遷移腳本)。 因此,在 werf 切換到 Helm 3 之前,werf 用戶不會失去 Helm 3 相對於 Helm 2 的主要優勢(werf 也有)。

然而,werf 到 Helm 3 程式碼庫的切換是不可避免的,並且將在不久的將來發生。 據推測,這將是 werf 1.1 或 werf 1.2(目前,werf 的主要版本是 1.0;有關 werf 版本控制設備的更多信息,請參閱 這裡)。 在此期間,Helm 3 將有時間穩定下來。

聚苯乙烯

另請閱讀我們的博客:

來源: www.habr.com

添加評論