Kubernetes 有多種更新資源的選項:套用、編輯、修補和替換。 對於每種方法的作用以及何時使用它們存在混亂。 讓我們弄清楚一下。
如果 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()
, replaceNamespacedService
或 patch_namespaced_deployment
,如果您透過以下方式使用集群 PUT
и PATCH
... 其中 update
и replace
舊 PUT
和 patch
,無論它多麼微不足道,都會使用 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
,可以用作 edit
和 patch
,選擇最適合所做更改的命令。 當新增和變更 BOM 屬性時,兩種方法大致相同。 刪除規格屬性或陣列元素時 edit
行為類似一次啟動 apply
,包括追蹤規範編輯前後的情況,以便您可以明確地從資源中刪除屬性和陣列元素。 您需要在規格中明確地將屬性值設為 null patch
將其從資源中刪除。 使用策略合併修補刪除數組元素更為複雜,因為它需要使用合併指令。 請參閱下面的其他升級方法,以了解更可行的替代方案。
在客戶端庫中實作更新方法,其行為與上述命令類似 kubectl
,應該在請求中設置 content-type
в application/strategic-merge-patch+json
。 如果要刪除規範中的屬性,則需要以類似的方式將它們的值明確設定為 null kubectl patch
。 如果需要刪除陣列元素,則應在更新規範中包含合併指令或使用不同的更新方法。
其他更新方法
Kubernetes 支援另外兩種更新方法: 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 開發人員正在致力於實現邏輯 apply
的 kubectl
在 Kubernetes API 中。 邏輯學 apply
在 Kubernetes 1.18 中可用: kubectl apply --server-side
或透過 API 使用該方法 PATCH
с content-type
application/apply-patch+YAML
.
注意:JSON 也是有效的 YAML,因此您可以將規範作為 JSON 發送,即使
content-type
將application/apply-patch+yaml
.
除了這個邏輯 kubectl
透過 API 可供所有人使用, apply
在伺服器端,追蹤誰負責規範中的字段,從而允許安全的多重存取以實現無衝突編輯。 換句話說,如果 apply
伺服器端將變得更加廣泛,針對不同客戶端將出現通用的安全資源管理介面,例如kubectl、Pulumi或Terraform、GitOps,以及使用用戶端程式庫自行編寫的腳本。
結果
我希望這篇關於更新叢集中資源的不同方法的簡短概述對您有所幫助。 很高興知道這不僅僅是應用與替換;還可以使用應用程式、編輯、修補或替換來更新資源。 畢竟,原則上,每種方法都有自己的應用領域。 對於原子更改,替換是更好的選擇;否則,您應該透過 apply 使用策略合併補丁。 至少,我希望您明白,在搜尋「kubernetes apply vs replacement」時不能信任 Google 或 StackOerflow。 至少在本文取代目前答案之前。
來源: www.habr.com