使用組態檔宣告式管理 Kubernetes 物件
Kubernetes 物件可以透過在目錄中儲存多個物件組態檔,並使用 kubectl apply
遞迴地建立和更新這些物件來建立、更新和刪除,視需要而定。此方法保留對即時物件所做的寫入,而不會將變更合併回物件組態檔。kubectl diff
也可讓您預覽 apply
將進行的變更。
開始之前
安裝 kubectl
。
您需要有一個 Kubernetes 叢集,並且必須設定 kubectl 命令列工具以與您的叢集通訊。建議在至少有兩個節點且不充當控制平面主機的叢集上執行本教學課程。如果您還沒有叢集,可以使用 minikube 建立一個,或者您可以使用以下 Kubernetes playground 之一
若要檢查版本,請輸入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
使用 伺服器端模擬執行,需要在 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
設定檔,將 image 從 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
註解已使用新的 image 更新。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
在物件的 manifest 從本機檔案系統中的目錄移除後,識別要刪除的物件。
在 Kubernetes 1.32 中,kubectl apply
中有兩種可用的修剪模式
- 許可清單式修剪:此模式自 kubectl v1.5 以來就已存在,但由於其設計在可用性、正確性和效能方面存在問題,因此仍處於 alpha 階段。基於 ApplySet 的模式旨在取代它。
- 基於 ApplySet 的修剪:apply set 是一個伺服器端物件(預設情況下為 Secret),kubectl 可以使用它來準確有效地追蹤跨 apply 操作的集合成員資格。此模式在 kubectl v1.27 中以 alpha 階段引入,作為許可清單式修剪的替代方案。
Kubernetes v1.5 [alpha]
警告
在許可清單模式下使用kubectl apply
和 --prune
時請小心。修剪哪些物件取決於 --prune-allowlist
、--selector
和 --namespace
標記的值,並依賴於範圍內物件的動態探索。尤其是在調用之間更改標記值時,可能會導致物件被意外刪除或保留。若要使用許可清單式修剪,請將以下標記添加到您的 kubectl apply
調用中
--prune
:刪除先前已套用但不在傳遞給目前調用的集合中的物件。--prune-allowlist
:要考慮修剪的 group-version-kinds (GVK) 清單。此標記是選用的,但強烈建議使用,因為其預設值是命名空間範圍和叢集範圍類型的不完整清單,這可能會導致令人驚訝的結果。--selector/-l
:使用標籤選擇器來限制為修剪選擇的物件集合。此標記是選用的,但強烈建議使用。--all
:使用此標記代替--selector/-l
以明確選擇所有先前已套用且屬於許可清單類型的物件。
許可清單式修剪會向 API 伺服器查詢所有符合給定標籤(如果有的話)的許可清單 GVK 物件,並嘗試將傳回的即時物件組態與物件 manifest 檔案進行比對。如果物件符合查詢,並且在目錄中沒有 manifest,並且具有 kubectl.kubernetes.io/last-applied-configuration
註解,則會將其刪除。
kubectl apply -f <directory> --prune -l <labels> --prune-allowlist=<gvk-list>
警告
帶有修剪功能的套用應僅針對包含物件 manifest 的根目錄執行。針對子目錄執行可能會導致物件被意外刪除,如果它們先前已套用、具有給定的標籤(如果有的話),並且未出現在子目錄中。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 父物件。若要啟用此功能,請使用以下標籤標記定義您要使用的資源的自訂資源定義 (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>
標籤新增至每個物件。基於效能考量,它還會收集集合包含的資源類型和命名空間清單,並將這些資訊新增至即時父物件上的註解中。最後,在套用操作結束時,它會向 API 伺服器查詢屬於該集合的那些類型、那些命名空間(或在叢集範圍內,如適用)的物件,如 applyset.kubernetes.io/part-of=<parentID>
標籤所定義。
注意事項和限制
- 每個物件最多只能是一個集合的成員。
- 當使用任何命名空間父物件(包括預設的 Secret)時,必須使用
--namespace
標記。這表示跨越多個命名空間的 ApplySet 必須使用叢集範圍的自訂資源作為父物件。 - 為了安全地將基於 ApplySet 的修剪與多個目錄一起使用,請為每個目錄使用唯一的 ApplySet 名稱。
如何檢視物件
您可以使用帶有 -o yaml
的 kubectl get
來檢視即時物件的組態
kubectl get -f <filename|url> -o yaml
apply 如何計算差異並合併變更
注意
patch 是一種更新操作,其範圍限定於物件的特定欄位,而不是整個物件。這使得只需更新物件上的特定欄位集,而無需先讀取物件。當 kubectl apply
更新物件的即時組態時,它是透過向 API 伺服器發送 patch 請求來完成的。patch 定義了範圍限定於即時物件組態的特定欄位的更新。kubectl apply
命令使用設定檔、即時組態和儲存在即時組態中的 last-applied-configuration
註解來計算此 patch 請求。
合併 patch 計算
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
讀取值並將其與設定檔中的值進行比較,來計算要刪除的欄位。清除在本機物件設定檔中明確設定為 null 的欄位,無論它們是否出現在last-applied-configuration
中。在此範例中,minReadySeconds
出現在last-applied-configuration
註解中,但未出現在設定檔中。動作: 從即時組態中清除minReadySeconds
。 - 透過從設定檔讀取值並將其與即時組態中的值進行比較,來計算要設定的欄位。在此範例中,設定檔中
image
的值與即時組態中的值不符。動作: 在即時組態中設定image
的值。 - 將
last-applied-configuration
註解設定為與設定檔的值相符。 - 將步驟 1、2、3 的結果合併到對 API 伺服器的單個 patch 請求中。
這是合併結果的即時組態
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
# ...
# ...
# ...
# ...
不同類型的欄位如何合併
設定檔中的特定欄位如何與即時組態合併取決於欄位的類型。欄位有幾種類型
primitive:字串、整數或布林類型欄位。例如,
image
和replicas
是 primitive 欄位。動作: 取代。map,也稱為 object:map 類型或包含子欄位的複雜類型欄位。例如,
labels
、annotations
、spec
和metadata
都是 map。動作: 合併元素或子欄位。list:包含項目清單的欄位,這些項目可以是 primitive 類型或 map。例如,
containers
、ports
和args
都是 list。動作: 各有不同。
當 kubectl apply
更新 map 或 list 欄位時,它通常不會取代整個欄位,而是更新個別子元素。例如,當合併 Deployment 上的 spec
時,不會取代整個 spec
。而是比較和合併 spec
的子欄位,例如 replicas
。
合併對 primitive 欄位的變更
Primitive 欄位會被取代或清除。
注意
-
用於「不適用」,因為未使用該值。物件設定檔中的欄位 | 即時物件組態中的欄位 | last-applied-configuration 中的欄位 | 動作 |
---|---|---|---|
是 | 是 | - | 將即時值設定為設定檔值。 |
是 | 否 | - | 將即時值設定為本機組態。 |
否 | - | 是 | 從即時組態中清除。 |
否 | - | 否 | 不執行任何動作。保留即時值。 |
合併對 map 欄位的變更
代表 map 的欄位透過比較 map 的每個子欄位或元素來合併
注意
-
用於「不適用」,因為未使用該值。物件設定檔中的鍵 | 即時物件組態中的鍵 | last-applied-configuration 中的欄位 | 動作 |
---|---|---|---|
是 | 是 | - | 比較子欄位值。 |
是 | 否 | - | 將即時值設定為本機組態。 |
否 | - | 是 | 從即時組態中刪除。 |
否 | - | 否 | 不執行任何動作。保留即時值。 |
合併 list 類型欄位的變更
合併 list 的變更使用三種策略之一
- 如果 list 的所有元素都是 primitive,則取代該 list。
- 合併複雜元素 list 中的個別元素。
- 合併 primitive 元素 list。
策略的選擇是根據每個欄位而定。
如果 list 的所有元素都是 primitive,則取代該 list
將 list 視為與 primitive 欄位相同。取代或刪除整個 list。這樣可以保留順序。
範例: 使用 kubectl apply
更新 Pod 中 Container 的 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"]
說明: 合併使用設定檔值作為新的 list 值。
合併複雜元素 list 的個別元素
將 list 視為 map,並將每個元素的特定欄位視為鍵。新增、刪除或更新個別元素。這不會保留順序。
此合併策略在每個欄位上使用一個稱為 patchMergeKey
的特殊標籤。patchMergeKey
在 Kubernetes 原始碼中為每個欄位定義:types.go 當合併 map 的 list 時,指定為給定元素的 patchMergeKey
的欄位會像該元素的 map 鍵一樣使用。
範例: 使用 kubectl apply
更新 PodSpec 的 containers
欄位。這會合併 list,就好像它是一個 map,其中每個元素都以 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」的容器已保留,因為在上次套用的配置中未出現具有該名稱的元素。
合併基本元素列表
從 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
說明
- 使用者建立一個 Deployment,但未定義
strategy.type
。 - 伺服器將
strategy.type
預設為RollingUpdate
,並預設strategy.rollingUpdate
值。 - 使用者將
strategy.type
變更為Recreate
。strategy.rollingUpdate
值仍保持其預設值,儘管伺服器期望它們被清除。如果strategy.rollingUpdate
值最初已在設定檔中定義,則會更清楚地表明它們需要被刪除。 - 套用失敗,因為
strategy.rollingUpdate
未被清除。strategy.rollingupdate
欄位不能與strategy.type
為Recreate
一起定義。
建議:這些欄位應在物件設定檔中明確定義
- 工作負載(例如 Deployment、StatefulSet、Job、DaemonSet、ReplicaSet 和 ReplicationController)上的選取器和 PodTemplate 標籤
- Deployment 部署策略
如何清除伺服器預設欄位或由其他寫入器設定的欄位
設定檔中未出現的欄位可以透過將其值設定為 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
欄位。注意
此步驟為選用步驟,因為即使status
欄位存在於設定檔中,kubectl apply
也不會更新該欄位。在物件上設定
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"