正確比較 Kubernetes 應用、替換和修補

Kubernetes 有多種更新資源的選項:套用、編輯、修補和替換。 對於每種方法的作用以及何時使用它們存在混亂。 讓我們弄清楚一下。

正確比較 Kubernetes 應用、替換和修補

如果 在谷歌上搜尋 短語“kubernetes apply vs replacement”位於 回覆 StackOverflow,這是不正確的。 搜索時 「kubernetes apply vs patch」第一個連結是文檔 kubectl patch,其中不包括比較 apply и patch。 本文將介紹不同的選項,以及每個選項的正確使用方法。

在 Kubernetes 資源的生命週期(服務、部署、入口等)中,有時您需要變更、新增或刪除該資源的某些屬性。 例如,新增註解、增加或減少副本數量。

Kubernetes CLI

如果您已經透過 CLI 使用 Kubernetes 集群,那麼您已經熟悉 apply и edit. 團隊 apply 從檔案中讀取資源規格並對 Kubernetes 叢集進行“upsert”,即如果資源不存在則建立資源,如果存在則更新資源。 團隊 edit 透過 API 讀取資源,然後將資源規格寫入本機文件,然後在文字編輯器中開啟該文件。 編輯並儲存檔案後, kubectl 將透過 API 發回所做的更改,API 會仔細地將這些變更套用到資源。

並不是每個人都知道這些指令 patch и replace. 團隊 patch 允許您更改資源規範的一部分,僅在命令列上提供更改的部分。 團隊 replace 工作原理與 edit,但一切都需要手動完成:您需要下載當前版本的資源規範,例如使用 kubectl get -o yaml,編輯它,然後使用 replace 根據更改的規範更新資源。 團隊 replace 如果讀取和替換資源之間發生任何更改,則將無法運作。

庫伯內斯API

您可能熟悉這些方法 CoreV1().Pods().Update(), replaceNamespacedServicepatch_namespaced_deployment,如果您透過以下方式使用集群 Kubernetes API 的客戶端程式庫 使用某種程式語言。 該庫使用以下方法透過 HTTP 請求處理這些方法 PUT и PATCH... 其中 update и replacePUTpatch,無論它多麼微不足道,都會使用 PATCH.

它應該指出的是 kubectl 也可以透過 API 與叢集配合使用。 換句話說, kubectl是 Go 語言用戶端程式庫之上的包裝器,除了標準 API 功能之外,它在很大程度上提供了以更緊湊和可讀的形式提供子命令的能力。 例如,您可能已經註意到,該方法 apply 上一段沒有提到。 目前(2020年XNUMX月, 約譯員)所有邏輯 kubectl apply, IE。 建立不存在的資源並更新現有資源,完全在程式碼端工作 kubectl。 正在努力 關於邏輯傳輸 apply API 方面,但仍處於測試階段。 下面我會詳細寫一下。

預設打補丁

最佳使用 patch,如果您想更新資源。 這就是兩個客戶端庫在 Kubernetes API 之上運作的方式 kubectl (這並不奇怪,因為它是客戶端庫的包裝器, 約譯員).

策略性地工作

所有球隊 kubectl apply, edit и patch 使用方法 PATCH 在 HTTP 請求中更新現有資源。 如果您更詳細地研究命令的實現,那麼它們都使用該方法 策略合併修補 更新資源,儘管命令 patch 可以使用其他方法(更多內容請見下文)。 策略合併修補方法試圖透過將提供的規範與現有規範合併來「做到正確」。 更具體地說,它嘗試組合物件和數組,這意味著更改往往是相加的。 例如,運行命令 patch 在 pod 容器規格中使用新的環境變量,會導致該環境變數被添加到現有的環境變數中,而不是覆寫它們。 若要刪除使用此方法,您必須在提供的規格中將參數值強制設定為 null。 哪支球隊 kubectl 最好用於更新嗎?

如果您使用以下方式建立和管理資源 kubectl apply,更新時最好始終使用 kubectl apply這樣 kubectl 可以管理配置並正確追蹤應用程式之間請求的變更。 優勢一直用 apply 其優點是它會追蹤先前應用的規範,使其能夠知道何時明確刪除規範屬性和陣列元素。 這允許您使用 apply 刪除屬性和陣列元素,而正常的策略合併將無法運作。 團隊 edit и patch 不要更新註釋 kubectl apply 用於追蹤其更改,因此透過 Kubernetes API 追蹤和進行的任何更改,但透過命令進行 edit и patch,對後續命令不可見 apply即, apply 即使它們沒有出現在輸入規範中,也不會刪除它們 apply (文檔說 edit и patch 更新所使用的註釋 apply,但實際上 - 不)。

如果你不使用該指令 apply,可以用作 editpatch,選擇最適合所做更改的命令。 當新增和變更 BOM 屬性時,兩種方法大致相同。 刪除規格屬性或陣列元素時 edit 行為類似一次啟動 apply,包括追蹤規範編輯前後的情況,以便您可以明確地從資源中刪除屬性和陣列元素。 您需要在規格中明確地將屬性值設為 null patch將其從資源中刪除。 使用策略合併修補刪除數組元素更為複雜,因為它需要使用合併指令。 請參閱下面的其他升級方法,以了解更可行的替代方案。

在客戶端庫中實作更新方法,其行為與上述命令類似 kubectl,應該在請求中設置 content-type в application/strategic-merge-patch+json。 如果要刪除規範中的屬性,則需要以類似的方式將它們的值明確設定為 null kubectl patch。 如果需要刪除陣列元素,則應在更新規範中包含合併指令或使用不同的更新方法。

其他更新方法

Kubernetes 支援另外兩種更新方法: JSON 合併補丁 и JSON補丁。 JSON 合併修補方法採用部分 Kubernetes 規格作為輸入,並支援與策略合併修補方法類似的合併物件。 兩者的區別在於它只支援數組替換,包括pod規範中的容器數組。 這表示在使用 JSON 合併補丁時,您需要為所有容器提供完整的規範,以防任何容器的任何屬性發生變更。 因此,此方法對於從 BOM 中的陣列中刪除元素非常有用。 在命令列上,您可以使用以下命令選擇 JSON 合併補丁 kubectl patch --type=merge。 使用 Kubernetes API 時,應該使用 request 方法 PATCH 和安裝 content-type в application/merge-patch+json.

JSON 修補方法不是提供資源的部分規範,而是以數組形式提供您想要對資源進行的更改,其中數組的每個元素代表對資源所做更改的描述。 這種方法是一種更靈活、更強大的方式來表達所做的更改,但代價是以單獨的非 Kubernetes 格式列出所做的更改,而不是發送部分資源規範。 在 kubectl 您可以使用選擇 JSON 補丁 kubectl patch --type=json。 使用 Kubernetes API 時,此方法使用請求方法 PATCH 和安裝 content-type в application/json-patch+json.

我們需要信心 - 使用替換

在某些情況下,您需要確保在讀取資源和更新資源之間沒有對資源進行任何變更。 換句話說,您應該確保所有更改都會 原子。 在這種情況下,要更新資源,您應該使用 replace。 例如,如果您有一個具有由多個來源更新的計數器的 ConfigMap,則應確保兩個來源不會同時更新計數器,從而導致更新遺失。 為了進行演示,請使用此方法想像一系列事件 patch:

  • A和B從API取得資源的目前狀態
  • 每個都透過將計數器增加 XNUMX 並分別在「更新者」註釋中新增「A」或「B」來本地更新規範
  • 而且資源更新速度快一點
  • B 更新資源

結果,更新 A 丟失。 上次操作 patch 獲勝,計數器增加 XNUMX 而不是 XNUMX,並且“updated-by”註釋的值以“B”結尾且不包含“A”。 讓我們將上述內容與使用該方法完成更新時發生的情況進行比較 replace:

  • A和B從API取得資源的目前狀態
  • 每個都透過將計數器增加 XNUMX 並分別在「更新者」註釋中新增「A」或「B」來本地更新規範
  • 而且資源更新速度快一點
  • B 嘗試更新資源,但更新被 API 拒絕,因為資源版本在規格中 replace 與 Kubernetes 中資源的當前版本不匹配,因為 A 的替換操作增加了資源的版本。

在上述情況下,B 必須重新取得資源,變更新狀態並重試 replace。 這將導致計數器增加 XNUMX,並且“更新者”註釋在末尾包含“AB”。

上面的例子意味著當執行 replace 整個資源被完全取代。 規格用於 replace,不能是部分的,或像這樣的部分 apply,但完整,包括添加 resourceVersion 到規範元數據中。 如果您還沒有啟用 resourceVersion 或者您提供的版本不是最新版本,更換將被拒絕。 所以最好的使用方法是 replace – 立即讀取資源、更新並取代。 使用 kubectl,它可能看起來像這樣:

$ kubectl get deployment my-deployment -o json 
    | jq '.spec.template.spec.containers[0].env[1].value = "new value"' 
    | kubectl replace -f -

值得注意的是,以下兩個命令,順序執行,將會執行成功,因為 deployment.yaml 不包含財產 .metadata.resourceVersion

$ kubectl create -f deployment.yaml
$ kubectl replace -f deployment.yaml

這似乎與上面所說的相矛盾,即「新增 resourceVersion 到規範元資料中。」這樣說是錯的嗎?不,不是,因為如果 kubectl 注意到你沒有指定 resourceVersion,它會從資源中讀取它並將其添加到您指定的規範中,然後才執行它 replace。 因為如果你依賴原子性,這可能是危險的,所以魔法完全在側面起作用 kubectl,在使用與 API 配合使用的客戶端程式庫時,不應依賴它。 在這種情況下,您將必須讀取當前的資源規範,更新它然後執行 PUT 要求。

你無法打補丁——我們會進行替換

有時您需要進行一些 API 無法處理的變更。 在這些情況下,您可以透過刪除並重新建立資源來強制替換資源。 這是使用完成的 kubectl replace --force。 執行該命令會立即刪除資源,然後根據提供的規格重新建立它們。 API 中沒有「強制替換」處理程序,為了透過 API 執行此操作,您需要執行兩個操作。 首先,您需要透過設定來刪除資源 gracePeriodSeconds 為零 (0) 和 propagationPolicy 在「背景」中,然後使用所需的規格重新建立該資源。

警告:這種方法有潛在危險,可能會導致未定義的狀態。

在伺服器端應用

如上所述,Kubernetes 開發人員正在致力於實現邏輯 applykubectl 在 Kubernetes API 中。 邏輯學 apply 在 Kubernetes 1.18 中可用: kubectl apply --server-side 或透過 API 使用該方法 PATCH с content-type application/apply-patch+YAML.

注意:JSON 也是有效的 YAML,因此您可以將規範作為 JSON 發送,即使 content-typeapplication/apply-patch+yaml.

除了這個邏輯 kubectl 透過 API 可供所有人使用, apply 在伺服器端,追蹤誰負責規範中的字段,從而允許安全的多重存取以實現無衝突編輯。 換句話說,如果 apply 伺服器端將變得更加廣泛,針對不同客戶端將出現通用的安全資源管理介面,例如kubectl、Pulumi或Terraform、GitOps,以及使用用戶端程式庫自行編寫的腳本。

結果

我希望這篇關於更新叢集中資源的不同方法的簡短概述對您有所幫助。 很高興知道這不僅僅是應用與替換;還可以使用應用程式、編輯、修補或替換來更新資源。 畢竟,原則上,每種方法都有自己的應用領域。 對於原子更改,替換是更好的選擇;否則,您應該透過 apply 使用策略合併補丁。 至少,我希望您明白,在搜尋「kubernetes apply vs replacement」時不能信任 Google 或 StackOerflow。 至少在本文取代目前答案之前。

正確比較 Kubernetes 應用、替換和修補

來源: www.habr.com

添加評論