使用配置檔案宣告式管理 Kubernetes 物件
透過將多個物件配置檔案儲存在一個目錄中並使用 kubectl apply
來根據需要遞迴建立和更新這些物件,可以建立、更新和刪除 Kubernetes 物件。此方法會保留對活動物件所做的寫入,而不會將更改合併回物件配置檔案中。kubectl diff
還會提供 apply
將進行的更改的預覽。
準備工作
安裝 kubectl
。
你需要擁有一個 Kubernetes 叢集,並且 kubectl 命令列工具必須配置為與你的叢集通訊。建議在至少有兩個不作為控制平面主機的節點的叢集上執行本教程。如果你還沒有叢集,可以使用 minikube 建立一個,或者使用以下 Kubernetes 演練環境之一:
要檢查版本,請輸入 kubectl version
。
權衡
kubectl
工具支援三種物件管理方式
- 命令式命令
- 命令式物件配置
- 宣告式物件配置
有關每種物件管理的優缺點討論,請參閱Kubernetes 物件管理。
概述
宣告式物件配置要求對 Kubernetes 物件定義和配置有深入的理解。如果你尚未閱讀,請閱讀並完成以下文件:
以下是本文件中使用的術語的定義:
- 物件配置檔案 / 配置檔案:定義 Kubernetes 物件配置的檔案。本主題演示如何將配置檔案傳遞給
kubectl apply
。配置檔案通常儲存在原始碼管理中,例如 Git。 - 即時物件配置 / 即時配置:Kubernetes 叢集觀察到的物件的即時配置值。這些值儲存在 Kubernetes 叢集儲存中,通常是 etcd。
- 宣告式配置編寫器 / 宣告式編寫器:對即時物件進行更新的人員或軟體元件。本主題中提及的即時編寫器會修改物件配置檔案並執行
kubectl apply
來寫入更改。
如何建立物件
使用 kubectl apply
建立指定目錄中所有由配置檔案定義的物件,除了那些已經存在的物件之外:
kubectl apply -f <directory>
這將在每個物件上設定 kubectl.kubernetes.io/last-applied-configuration: '{...}'
註解。該註解包含用於建立物件的物件配置檔案的內容。
注意
新增-R
標誌以遞迴處理目錄。這是一個物件配置檔案的示例:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
minReadySeconds: 5
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
執行 kubectl diff
以列印將要建立的物件
kubectl diff -f https://k8s.io/examples/application/simple_deployment.yaml
注意
diff
使用 server-side dry-run,這需要在 kube-apiserver
上啟用。
由於 diff
在空執行模式下執行伺服器端應用請求,因此它需要授予 PATCH
、CREATE
和 UPDATE
許可權。有關詳細資訊,請參閱空執行授權。
使用 kubectl apply
建立物件
kubectl apply -f https://k8s.io/examples/application/simple_deployment.yaml
使用 kubectl get
列印即時配置
kubectl get -f https://k8s.io/examples/application/simple_deployment.yaml -o yaml
輸出顯示 kubectl.kubernetes.io/last-applied-configuration
註解已寫入即時配置,並且與配置檔案匹配:
kind: Deployment
metadata:
annotations:
# ...
# This is the json representation of simple_deployment.yaml
# It was written by kubectl apply when the object was created
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"apps/v1","kind":"Deployment",
"metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
"spec":{"minReadySeconds":5,"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
"spec":{"containers":[{"image":"nginx:1.14.2","name":"nginx",
"ports":[{"containerPort":80}]}]}}}}
# ...
spec:
# ...
minReadySeconds: 5
selector:
matchLabels:
# ...
app: nginx
template:
metadata:
# ...
labels:
app: nginx
spec:
containers:
- image: nginx:1.14.2
# ...
name: nginx
ports:
- containerPort: 80
# ...
# ...
# ...
# ...
如何更新物件
你還可以使用 kubectl apply
更新目錄中定義的所有物件,即使這些物件已經存在。這種方法實現了以下目的:
- 在即時配置中設定配置檔案中出現的欄位。
- 清除即時配置中已從配置檔案中移除的欄位。
kubectl diff -f <directory>
kubectl apply -f <directory>
注意
新增-R
標誌以遞迴處理目錄。這是一個配置檔案的示例:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
minReadySeconds: 5
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
使用 kubectl apply
建立物件
kubectl apply -f https://k8s.io/examples/application/simple_deployment.yaml
注意
為了說明目的,上面的命令引用的是單個配置檔案而不是一個目錄。使用 kubectl get
列印即時配置
kubectl get -f https://k8s.io/examples/application/simple_deployment.yaml -o yaml
輸出顯示 kubectl.kubernetes.io/last-applied-configuration
註解已寫入即時配置,並且與配置檔案匹配:
kind: Deployment
metadata:
annotations:
# ...
# This is the json representation of simple_deployment.yaml
# It was written by kubectl apply when the object was created
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"apps/v1","kind":"Deployment",
"metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
"spec":{"minReadySeconds":5,"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
"spec":{"containers":[{"image":"nginx:1.14.2","name":"nginx",
"ports":[{"containerPort":80}]}]}}}}
# ...
spec:
# ...
minReadySeconds: 5
selector:
matchLabels:
# ...
app: nginx
template:
metadata:
# ...
labels:
app: nginx
spec:
containers:
- image: nginx:1.14.2
# ...
name: nginx
ports:
- containerPort: 80
# ...
# ...
# ...
# ...
使用 kubectl scale
直接更新即時配置中的 replicas
欄位。這不使用 kubectl apply
。
kubectl scale deployment/nginx-deployment --replicas=2
使用 kubectl get
列印即時配置
kubectl get deployment nginx-deployment -o yaml
輸出顯示 replicas
欄位已設定為 2,並且 last-applied-configuration
註解不包含 replicas
欄位。
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
# ...
# note that the annotation does not contain replicas
# because it was not updated through apply
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"apps/v1","kind":"Deployment",
"metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
"spec":{"minReadySeconds":5,"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
"spec":{"containers":[{"image":"nginx:1.14.2","name":"nginx",
"ports":[{"containerPort":80}]}]}}}}
# ...
spec:
replicas: 2 # written by scale
# ...
minReadySeconds: 5
selector:
matchLabels:
# ...
app: nginx
template:
metadata:
# ...
labels:
app: nginx
spec:
containers:
- image: nginx:1.14.2
# ...
name: nginx
ports:
- containerPort: 80
# ...
更新 simple_deployment.yaml
配置檔案,將映象從 nginx:1.14.2
更改為 nginx:1.16.1
,並刪除 minReadySeconds
欄位。
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.16.1 # update the image
ports:
- containerPort: 80
應用對配置檔案所做的更改
kubectl diff -f https://k8s.io/examples/application/update_deployment.yaml
kubectl apply -f https://k8s.io/examples/application/update_deployment.yaml
使用 kubectl get
列印即時配置
kubectl get -f https://k8s.io/examples/application/update_deployment.yaml -o yaml
輸出顯示即時配置發生以下更改:
replicas
欄位保留了由kubectl scale
設定的值 2。這是因為該欄位已從配置檔案中省略。image
欄位已從nginx:1.14.2
更新為nginx:1.16.1
。last-applied-configuration
註解已更新為新的映象。minReadySeconds
欄位已清除。last-applied-configuration
註解不再包含minReadySeconds
欄位。
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
# ...
# The annotation contains the updated image to nginx 1.16.1,
# but does not contain the updated replicas to 2
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"apps/v1","kind":"Deployment",
"metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
"spec":{"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
"spec":{"containers":[{"image":"nginx:1.16.1","name":"nginx",
"ports":[{"containerPort":80}]}]}}}}
# ...
spec:
replicas: 2 # Set by `kubectl scale`. Ignored by `kubectl apply`.
# minReadySeconds cleared by `kubectl apply`
# ...
selector:
matchLabels:
# ...
app: nginx
template:
metadata:
# ...
labels:
app: nginx
spec:
containers:
- image: nginx:1.16.1 # Set by `kubectl apply`
# ...
name: nginx
ports:
- containerPort: 80
# ...
# ...
# ...
# ...
警告
不支援將kubectl apply
與命令式物件配置命令 create
和 replace
混用。這是因為 create
和 replace
不會保留 kubectl apply
用於計算更新的 kubectl.kubernetes.io/last-applied-configuration
。如何刪除物件
有兩種方法可以刪除由 kubectl apply
管理的物件。
推薦做法:kubectl delete -f <filename>
使用命令式命令手動刪除物件是推薦的方法,因為它更明確地說明了要刪除的內容,並且不太可能導致使用者意外刪除某些內容。
kubectl delete -f <filename>
替代方法:kubectl apply -f <directory> --prune
作為 kubectl delete
的替代方法,你可以使用 kubectl apply
在清單從本地檔案系統中的目錄中移除後識別要刪除的物件。
在 Kubernetes 1.34 中,kubectl apply 中有兩種可用的修剪模式:
- 基於白名單的修剪:此模式自 kubectl v1.5 以來一直存在,但由於其設計存在可用性、正確性和效能問題,仍處於 Alpha 階段。基於 ApplySet 的模式旨在取代它。
- 基於 ApplySet 的修剪:ApplySet 是一個伺服器端物件(預設是 Secret),kubectl 可以使用它在 apply 操作中準確高效地跟蹤集合成員。此模式在 kubectl v1.27 中作為基於白名單的修剪的替代方案以 Alpha 階段引入。
Kubernetes v1.5 [alpha]
警告
在允許列表模式下將--prune
與 kubectl apply
一起使用時請小心。修剪哪些物件取決於 --prune-allowlist
、--selector
和 --namespace
標誌的值,並且依賴於動態發現範圍內的物件。特別是如果標誌值在呼叫之間發生更改,這可能導致物件意外刪除或保留。要使用基於允許列表的修剪,請在 kubectl apply
呼叫中新增以下標誌:
--prune
:刪除先前應用但不在當前呼叫傳入的集合中的物件。--prune-allowlist
:要考慮修剪的組-版本-種類 (GVK) 列表。此標誌是可選的,但強烈建議使用,因為其預設值是名稱空間和叢集範圍型別的部分列表,這可能導致意外結果。--selector/-l
:使用標籤選擇器來限制選擇用於修剪的物件集合。此標誌是可選的,但強烈建議使用。--all
:代替--selector/-l
使用,以顯式選擇所有已列入允許列表型別的先前應用物件。
基於允許列表的修剪會查詢 API 伺服器,以獲取所有匹配給定標籤(如果有)的允許列表 GVK 物件,並嘗試將返回的即時物件配置與物件清單檔案進行匹配。如果物件與查詢匹配,並且目錄中沒有清單,並且具有 kubectl.kubernetes.io/last-applied-configuration
註解,則會將其刪除。
kubectl apply -f <directory> --prune -l <labels> --prune-allowlist=<gvk-list>
警告
應用修剪只應針對包含物件清單的根目錄執行。如果物件先前已應用、具有給定標籤(如果有)且未出現在子目錄中,則針對子目錄執行可能會導致物件意外刪除。Kubernetes v1.27 [alpha]
注意
kubectl apply --prune --applyset
處於 Alpha 階段,後續版本可能會引入不相容的更改。要使用基於 ApplySet 的修剪,請設定 KUBECTL_APPLYSET=true
環境變數,並在 kubectl apply
呼叫中新增以下標誌:
--prune
:刪除先前應用但不在當前呼叫傳入的集合中的物件。--applyset
:kubectl 可用於在apply
操作中準確高效地跟蹤集合成員的物件名稱。
KUBECTL_APPLYSET=true kubectl apply -f <directory> --prune --applyset=<name>
預設情況下,使用的 ApplySet 父物件的型別是 Secret。但是,也可以使用 ConfigMap,格式為:--applyset=configmaps/<name>
。當使用 Secret 或 ConfigMap 時,如果物件不存在,kubectl 將建立該物件。
還可以使用自定義資源作為 ApplySet 父物件。為此,請用以下標籤標記定義要使用的資源的 Custom Resource Definition (CRD):applyset.kubernetes.io/is-parent-type: true
。然後,建立要用作 ApplySet 父級的物件(kubectl 不會自動為自定義資源執行此操作)。最後,在 applyset 標誌中按如下方式引用該物件:--applyset=<resource>.<group>/<name>
(例如,widgets.custom.example.com/widget-name
)。
透過基於 ApplySet 的修剪,kubectl 在將集合中的每個物件傳送到伺服器之前,為其新增 applyset.kubernetes.io/part-of=<parentID>
標籤。出於效能原因,它還會收集集合中包含的資源型別和名稱空間列表,並將這些資訊作為註解新增到即時父物件中。最後,在 apply 操作結束時,它會查詢 API 伺服器,查詢屬於該集合的、位於這些名稱空間中(或在叢集範圍內,視情況而定)的那些型別物件,這些物件由 applyset.kubernetes.io/part-of=<parentID>
標籤定義。
注意事項和限制
- 每個物件最多隻能是一個集合的成員。
- 當使用任何名稱空間父級(包括預設 Secret)時,需要
--namespace
標誌。這意味著跨多個名稱空間的 ApplySets 必須使用叢集範圍的自定義資源作為父物件。 - 要安全地將基於 ApplySet 的修剪與多個目錄一起使用,請為每個目錄使用唯一的 ApplySet 名稱。
如何檢視物件
您可以使用 kubectl get
配合 -o yaml
檢視即時物件的配置。
kubectl get -f <filename|url> -o yaml
應用如何計算差異併合並更改
注意
補丁(patch)是一種更新操作,它僅限於物件的特定欄位,而不是整個物件。這使得僅更新物件上的特定欄位集而無需先讀取物件成為可能。當 kubectl apply
更新物件的即時配置時,它透過向 API 伺服器傳送一個補丁請求來完成。該補丁定義了針對即時物件配置的特定欄位的更新。kubectl apply
命令使用配置檔案、即時配置以及儲存在即時配置中的 last-applied-configuration
註解來計算此補丁請求。
合併補丁計算
kubectl apply
命令將配置檔案內容寫入 kubectl.kubernetes.io/last-applied-configuration
註解。這用於識別已從配置檔案中移除並需要從即時配置中清除的欄位。以下是用於計算應刪除或設定哪些欄位的步驟:
- 計算要刪除的欄位。這些欄位存在於
last-applied-configuration
中,但配置檔案中缺少。 - 計算要新增或設定的欄位。這些欄位存在於配置檔案中,但其值與即時配置不匹配。
這是一個例子。假設這是一個 Deployment 物件的配置檔案:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.16.1 # update the image
ports:
- containerPort: 80
此外,假設這是同一個 Deployment 物件的即時配置:
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
# ...
# note that the annotation does not contain replicas
# because it was not updated through apply
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"apps/v1","kind":"Deployment",
"metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
"spec":{"minReadySeconds":5,"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
"spec":{"containers":[{"image":"nginx:1.14.2","name":"nginx",
"ports":[{"containerPort":80}]}]}}}}
# ...
spec:
replicas: 2 # written by scale
# ...
minReadySeconds: 5
selector:
matchLabels:
# ...
app: nginx
template:
metadata:
# ...
labels:
app: nginx
spec:
containers:
- image: nginx:1.14.2
# ...
name: nginx
ports:
- containerPort: 80
# ...
以下是 kubectl apply
將執行的合併計算:
- 透過讀取
last-applied-configuration
中的值並將其與配置檔案中的值進行比較來計算要刪除的欄位。無論last-applied-configuration
中是否出現,清除本地物件配置檔案中明確設定為 null 的欄位。在此示例中,minReadySeconds
出現在last-applied-configuration
註解中,但未出現在配置檔案中。操作:從即時配置中清除minReadySeconds
。 - 透過讀取配置檔案中的值並將其與即時配置中的值進行比較來計算要設定的欄位。在此示例中,配置檔案中
image
的值與即時配置中的值不匹配。操作:設定即時配置中image
的值。 - 將
last-applied-configuration
註解設定為與配置檔案值匹配。 - 將 1、2、3 的結果合併為對 API 伺服器的單個補丁請求。
以下是合併後的即時配置:
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
# ...
# The annotation contains the updated image to nginx 1.16.1,
# but does not contain the updated replicas to 2
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"apps/v1","kind":"Deployment",
"metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
"spec":{"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
"spec":{"containers":[{"image":"nginx:1.16.1","name":"nginx",
"ports":[{"containerPort":80}]}]}}}}
# ...
spec:
selector:
matchLabels:
# ...
app: nginx
replicas: 2 # Set by `kubectl scale`. Ignored by `kubectl apply`.
# minReadySeconds cleared by `kubectl apply`
# ...
template:
metadata:
# ...
labels:
app: nginx
spec:
containers:
- image: nginx:1.16.1 # Set by `kubectl apply`
# ...
name: nginx
ports:
- containerPort: 80
# ...
# ...
# ...
# ...
不同型別欄位的合併方式
配置檔案中特定欄位與即時配置的合併方式取決於該欄位的型別。有幾種欄位型別:
原始型別:字串、整數或布林型別的欄位。例如,
image
和replicas
都是原始欄位。操作:替換。對映,也稱為 物件:對映型別或包含子欄位的複雜型別的欄位。例如,
labels
、annotations
、spec
和metadata
都是對映。操作:合併元素或子欄位。列表:包含原始型別或對映的列表的欄位。例如,
containers
、ports
和args
都是列表。操作:因情況而異。
當 kubectl apply
更新對映或列表欄位時,它通常不會替換整個欄位,而是更新單個子元素。例如,在合併 Deployment 上的 spec
時,不會替換整個 spec
。相反,會比較和合並 spec
的子欄位,例如 replicas
。
合併原始欄位的更改
原始欄位被替換或清除。
注意
-
表示“不適用”,因為該值未被使用。物件配置檔案中的欄位 | 即時物件配置中的欄位 | last-applied-configuration 中的欄位 | 行動 |
---|---|---|---|
是 | 是 | - | 將即時配置設定為配置檔案值。 |
是 | 否 | - | 將即時配置設定為本地配置。 |
否 | - | 是 | 從即時配置中清除。 |
否 | - | 否 | 不執行任何操作。保留即時值。 |
合併對映欄位的更改
表示對映的欄位透過比較對映的每個子欄位或元素來合併。
注意
-
表示“不適用”,因為該值未被使用。物件配置檔案中的鍵 | 即時物件配置中的鍵 | last-applied-configuration 中的欄位 | 行動 |
---|---|---|---|
是 | 是 | - | 比較子欄位值。 |
是 | 否 | - | 將即時配置設定為本地配置。 |
否 | - | 是 | 從即時配置中刪除。 |
否 | - | 否 | 不執行任何操作。保留即時值。 |
合併列表型別欄位的更改
合併對列表的更改使用以下三種策略之一:
- 如果列表的所有元素都是原始型別,則替換該列表。
- 合併複雜元素列表中的單個元素。
- 合併原始元素列表。
策略的選擇是針對每個欄位進行的。
如果列表的所有元素都是原始型別,則替換該列表。
將列表視為與原始欄位相同。替換或刪除整個列表。這會保留順序。
示例:使用 kubectl apply
更新 Pod 中容器的 args
欄位。這會將即時配置中 args
的值設定為配置檔案中的值。先前已新增到即時配置中的任何 args
元素都將丟失。配置檔案中定義的 args
元素的順序將在即時配置中保留。
# last-applied-configuration value
args: ["a", "b"]
# configuration file value
args: ["a", "c"]
# live configuration
args: ["a", "b", "d"]
# result after merge
args: ["a", "c"]
解釋:合併使用配置檔案值作為新的列表值。
合併複雜元素列表中的單個元素
將列表視為一個對映,並將每個元素的特定欄位視為鍵。新增、刪除或更新單個元素。這不保留順序。
此合併策略對每個欄位使用一個特殊標籤,稱為 patchMergeKey
。patchMergeKey
在 Kubernetes 原始碼中為每個欄位定義:types.go。當合並對映列表時,為給定元素指定為 patchMergeKey
的欄位將用作該元素的對映鍵。
示例:使用 kubectl apply
更新 PodSpec 的 containers
欄位。這將合併列表,就像它是一個對映,其中每個元素都以 name
為鍵。
# last-applied-configuration value
containers:
- name: nginx
image: nginx:1.16
- name: nginx-helper-a # key: nginx-helper-a; will be deleted in result
image: helper:1.3
- name: nginx-helper-b # key: nginx-helper-b; will be retained
image: helper:1.3
# configuration file value
containers:
- name: nginx
image: nginx:1.16
- name: nginx-helper-b
image: helper:1.3
- name: nginx-helper-c # key: nginx-helper-c; will be added in result
image: helper:1.3
# live configuration
containers:
- name: nginx
image: nginx:1.16
- name: nginx-helper-a
image: helper:1.3
- name: nginx-helper-b
image: helper:1.3
args: ["run"] # Field will be retained
- name: nginx-helper-d # key: nginx-helper-d; will be retained
image: helper:1.3
# result after merge
containers:
- name: nginx
image: nginx:1.16
# Element nginx-helper-a was deleted
- name: nginx-helper-b
image: helper:1.3
args: ["run"] # Field was retained
- name: nginx-helper-c # Element was added
image: helper:1.3
- name: nginx-helper-d # Element was ignored
image: helper:1.3
說明
- 名為 "nginx-helper-a" 的容器被刪除了,因為配置檔案中沒有名為 "nginx-helper-a" 的容器。
- 名為 "nginx-helper-b" 的容器保留了即時配置中
args
的更改。kubectl apply
能夠識別即時配置中的 "nginx-helper-b" 與配置檔案中的 "nginx-helper-b" 是相同的,儘管它們的欄位值不同(配置檔案中沒有args
)。這是因為patchMergeKey
欄位值(name)在兩者中都相同。 - 名為 "nginx-helper-c" 的容器被添加了,因為即時配置中沒有同名容器,但配置檔案中有一個同名容器。
- 名為 "nginx-helper-d" 的容器被保留,因為 last-applied-configuration 中沒有同名元素。
合併原始元素列表
自 Kubernetes 1.5 起,不支援合併原始元素列表。
預設欄位值
如果物件建立時未指定某些欄位,API 伺服器會在即時配置中將其設定為預設值。
這是一個 Deployment 的配置檔案。該檔案未指定 strategy
:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
minReadySeconds: 5
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
使用 kubectl apply
建立物件
kubectl apply -f https://k8s.io/examples/application/simple_deployment.yaml
使用 kubectl get
列印即時配置
kubectl get -f https://k8s.io/examples/application/simple_deployment.yaml -o yaml
輸出顯示 API 伺服器在即時配置中將多個欄位設定為預設值。這些欄位未在配置檔案中指定。
apiVersion: apps/v1
kind: Deployment
# ...
spec:
selector:
matchLabels:
app: nginx
minReadySeconds: 5
replicas: 1 # defaulted by apiserver
strategy:
rollingUpdate: # defaulted by apiserver - derived from strategy.type
maxSurge: 1
maxUnavailable: 1
type: RollingUpdate # defaulted by apiserver
template:
metadata:
creationTimestamp: null
labels:
app: nginx
spec:
containers:
- image: nginx:1.14.2
imagePullPolicy: IfNotPresent # defaulted by apiserver
name: nginx
ports:
- containerPort: 80
protocol: TCP # defaulted by apiserver
resources: {} # defaulted by apiserver
terminationMessagePath: /dev/termination-log # defaulted by apiserver
dnsPolicy: ClusterFirst # defaulted by apiserver
restartPolicy: Always # defaulted by apiserver
securityContext: {} # defaulted by apiserver
terminationGracePeriodSeconds: 30 # defaulted by apiserver
# ...
在補丁請求中,預設欄位不會被重新預設,除非它們作為補丁請求的一部分被明確清除。這可能導致基於其他欄位值預設的欄位出現意外行為。當其他欄位隨後更改時,從中預設的值不會更新,除非它們被明確清除。
因此,建議在配置檔案中明確定義伺服器預設的某些欄位,即使所需值與伺服器預設值匹配。這使得更容易識別不會被伺服器重新預設的衝突值。
示例
# last-applied-configuration
spec:
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
# configuration file
spec:
strategy:
type: Recreate # updated value
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
# live configuration
spec:
strategy:
type: RollingUpdate # defaulted value
rollingUpdate: # defaulted value derived from type
maxSurge : 1
maxUnavailable: 1
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
# result after merge - ERROR!
spec:
strategy:
type: Recreate # updated value: incompatible with rollingUpdate
rollingUpdate: # defaulted value: incompatible with "type: Recreate"
maxSurge : 1
maxUnavailable: 1
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
說明
- 使用者在未定義
strategy.type
的情況下建立了一個 Deployment。 - 伺服器將
strategy.type
預設為RollingUpdate
並預設strategy.rollingUpdate
值。 - 使用者將
strategy.type
更改為Recreate
。strategy.rollingUpdate
值保持其預設值,儘管伺服器期望它們被清除。如果strategy.rollingUpdate
值最初在配置檔案中定義,那麼它們需要被刪除會更清楚。 - 由於
strategy.rollingUpdate
未清除,應用失敗。strategy.rollingupdate
欄位不能與Recreate
的strategy.type
一起定義。
建議:這些欄位應在物件配置檔案中明確定義:
- 工作負載(例如 Deployment、StatefulSet、Job、DaemonSet、ReplicaSet 和 ReplicationController)上的選擇器和 PodTemplate 標籤。
- 部署回滾策略
如何清除伺服器預設欄位或由其他寫入器設定的欄位
未在配置檔案中出現的欄位可以透過將其值設定為 null
然後應用配置檔案來清除。對於伺服器預設的欄位,這將觸發重新預設這些值。
如何在配置檔案和直接命令式寫入器之間更改欄位的所有權
這些是您應該用於更改單個物件欄位的唯一方法:
- 使用
kubectl apply
。 - 直接寫入即時配置,而不修改配置檔案:例如,使用
kubectl scale
。
將所有者從直接命令式寫入器更改為配置檔案
將欄位新增到配置檔案中。對於該欄位,停止對不透過 kubectl apply
的即時配置進行直接更新。
將所有者從配置檔案更改為直接命令式寫入器
自 Kubernetes 1.5 起,將欄位的所有權從配置檔案更改為命令式寫入器需要手動步驟:
- 從配置檔案中刪除該欄位。
- 從即時物件上的
kubectl.kubernetes.io/last-applied-configuration
註解中刪除該欄位。
管理方法變更
Kubernetes 物件應一次只使用一種方法進行管理。從一種方法切換到另一種方法是可能的,但這是一個手動過程。
注意
將命令式刪除與宣告式管理結合使用是可以的。從命令式管理遷移到宣告式物件配置
從命令式管理遷移到宣告式物件配置涉及幾個手動步驟:
將即時物件匯出到本地配置檔案
kubectl get <kind>/<name> -o yaml > <kind>_<name>.yaml
手動從配置檔案中刪除
status
欄位。注意
此步驟是可選的,因為kubectl apply
不會更新 status 欄位,即使它存在於配置檔案中。在物件上設定
kubectl.kubernetes.io/last-applied-configuration
註解kubectl replace --save-config -f <kind>_<name>.yaml
更改流程以獨佔使用
kubectl apply
管理物件。
從命令式物件配置遷移到宣告式物件配置
在物件上設定
kubectl.kubernetes.io/last-applied-configuration
註解kubectl replace --save-config -f <kind>_<name>.yaml
更改流程以獨佔使用
kubectl apply
管理物件。
定義控制器選擇器和 PodTemplate 標籤
警告
強烈不鼓勵更新控制器上的選擇器。推薦的方法是定義一個唯一的、不可變的 PodTemplate 標籤,該標籤僅由控制器選擇器使用,沒有其他語義含義。
示例
selector:
matchLabels:
controller-selector: "apps/v1/deployment/nginx"
template:
metadata:
labels:
controller-selector: "apps/v1/deployment/nginx"