使用 kubectl patch 就地更新 API 物件
此任務演示如何使用 kubectl patch
就地更新 API 物件。本任務中的練習演示了策略合併補丁和 JSON 合併補丁。
準備工作
你需要擁有一個 Kubernetes 叢集,並且 kubectl 命令列工具已配置為與你的叢集通訊。建議在至少有兩個節點不充當控制平面主機的叢集上執行本教程。如果你還沒有叢集,可以使用 minikube 建立一個,或者使用這些 Kubernetes 操場之一
要檢查版本,請輸入 kubectl version
。
使用策略合併補丁更新 Deployment
這是一個具有兩個副本的 Deployment 的配置檔案。每個副本是一個 Pod,其中有一個容器
apiVersion: apps/v1
kind: Deployment
metadata:
name: patch-demo
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: patch-demo-ctr
image: nginx
tolerations:
- effect: NoSchedule
key: dedicated
value: test-team
建立 Deployment
kubectl apply -f https://k8s.io/examples/application/deployment-patch.yaml
檢視與你的 Deployment 關聯的 Pod
kubectl get pods
輸出顯示 Deployment 有兩個 Pod。1/1
表示每個 Pod 有一個容器
NAME READY STATUS RESTARTS AGE
patch-demo-28633765-670qr 1/1 Running 0 23s
patch-demo-28633765-j5qs3 1/1 Running 0 23s
記下正在執行的 Pod 的名稱。稍後,你將看到這些 Pod 被終止並被新的 Pod 替換。
此時,每個 Pod 都有一個執行 nginx 映象的容器。現在假設你希望每個 Pod 有兩個容器:一個執行 nginx,一個執行 redis。
建立一個名為 patch-file.yaml
的檔案,其內容如下
spec:
template:
spec:
containers:
- name: patch-demo-ctr-2
image: redis
修補你的 Deployment
kubectl patch deployment patch-demo --patch-file patch-file.yaml
檢視已修補的 Deployment
kubectl get deployment patch-demo --output yaml
輸出顯示 Deployment 中的 PodSpec 有兩個容器
containers:
- image: redis
imagePullPolicy: Always
name: patch-demo-ctr-2
...
- image: nginx
imagePullPolicy: Always
name: patch-demo-ctr
...
檢視與你的已修補 Deployment 關聯的 Pod
kubectl get pods
輸出顯示正在執行的 Pod 的名稱與之前執行的 Pod 的名稱不同。Deployment 終止了舊 Pod 並建立了兩個新的 Pod,它們符合更新後的 Deployment 規範。2/2
表示每個 Pod 有兩個容器
NAME READY STATUS RESTARTS AGE
patch-demo-1081991389-2wrn5 2/2 Running 0 1m
patch-demo-1081991389-jmg7b 2/2 Running 0 1m
仔細檢視其中一個 patch-demo Pod
kubectl get pod <your-pod-name> --output yaml
輸出顯示 Pod 有兩個容器:一個執行 nginx,一個執行 redis
containers:
- image: redis
...
- image: nginx
...
關於策略合併補丁的注意事項
你在前面的練習中執行的補丁稱為*策略合併補丁*。請注意,補丁沒有替換 containers
列表。相反,它向列表中添加了一個新的容器。換句話說,補丁中的列表與現有列表合併。當你在列表上使用策略合併補丁時,並非總是如此。在某些情況下,列表被替換,而不是合併。
使用策略合併補丁時,列表是替換還是合併取決於其補丁策略。補丁策略由 Kubernetes 原始碼中欄位標籤中的 patchStrategy
鍵的值指定。例如,PodSpec
結構體的 Containers
欄位具有 merge
的 patchStrategy
type PodSpec struct {
...
Containers []Container `json:"containers" patchStrategy:"merge" patchMergeKey:"name" ...`
...
}
你還可以在 OpenApi 規範 中看到補丁策略
"io.k8s.api.core.v1.PodSpec": {
...,
"containers": {
"description": "List of containers belonging to the pod. ...."
},
"x-kubernetes-patch-merge-key": "name",
"x-kubernetes-patch-strategy": "merge"
}
你還可以在 Kubernetes API 文件 中看到補丁策略。
建立一個名為 patch-file-tolerations.yaml
的檔案,其內容如下
spec:
template:
spec:
tolerations:
- effect: NoSchedule
key: disktype
value: ssd
修補你的 Deployment
kubectl patch deployment patch-demo --patch-file patch-file-tolerations.yaml
檢視已修補的 Deployment
kubectl get deployment patch-demo --output yaml
輸出顯示 Deployment 中的 PodSpec 只有一個容忍度(Toleration)
tolerations:
- effect: NoSchedule
key: disktype
value: ssd
請注意,PodSpec 中的 tolerations
列表被替換,而不是合併。這是因為 PodSpec 的 Tolerations 欄位在其欄位標籤中沒有 patchStrategy
鍵。因此,策略合併補丁使用預設補丁策略,即 replace
。
type PodSpec struct {
...
Tolerations []Toleration `json:"tolerations,omitempty" protobuf:"bytes,22,opt,name=tolerations"`
...
}
使用 JSON 合併補丁更新 Deployment
策略合併補丁不同於 JSON 合併補丁。使用 JSON 合併補丁,如果你想更新列表,你必須指定整個新列表。新列表會完全替換現有列表。
kubectl patch
命令有一個 type
引數,你可以將其設定為以下值之一
引數值 | 合併型別 |
---|---|
json | JSON 補丁,RFC 6902 |
merge | JSON 合併補丁,RFC 7386 |
strategic | 策略合併補丁 |
有關 JSON 補丁和 JSON 合併補丁的比較,請參見 JSON Patch and JSON Merge Patch。
type
引數的預設值為 strategic
。因此在前面的練習中,你執行的是策略合併補丁。
接下來,在你的同一個 Deployment 上執行 JSON 合併補丁。建立一個名為 patch-file-2.yaml
的檔案,其內容如下
spec:
template:
spec:
containers:
- name: patch-demo-ctr-3
image: gcr.io/google-samples/hello-app:2.0
在你的補丁命令中,將 type
設定為 merge
kubectl patch deployment patch-demo --type merge --patch-file patch-file-2.yaml
檢視已修補的 Deployment
kubectl get deployment patch-demo --output yaml
你在補丁中指定的 containers
列表只有一個容器。輸出顯示你的一容器列表替換了現有的 containers
列表。
spec:
containers:
- image: gcr.io/google-samples/hello-app:2.0
...
name: patch-demo-ctr-3
列出正在執行的 Pod
kubectl get pods
在輸出中,你可以看到現有 Pod 已終止,並建立了新的 Pod。1/1
表示每個新 Pod 只執行一個容器。
NAME READY STATUS RESTARTS AGE
patch-demo-1307768864-69308 1/1 Running 0 1m
patch-demo-1307768864-c86dc 1/1 Running 0 1m
使用帶 retainKeys 策略的策略合併補丁更新 Deployment
這是一個使用 RollingUpdate
策略的 Deployment 配置檔案
apiVersion: apps/v1
kind: Deployment
metadata:
name: retainkeys-demo
spec:
selector:
matchLabels:
app: nginx
strategy:
rollingUpdate:
maxSurge: 30%
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: retainkeys-demo-ctr
image: nginx
建立 Deployment
kubectl apply -f https://k8s.io/examples/application/deployment-retainkeys.yaml
此時,部署已建立並正在使用 RollingUpdate
策略。
建立一個名為 patch-file-no-retainkeys.yaml
的檔案,其內容如下
spec:
strategy:
type: Recreate
修補你的 Deployment
kubectl patch deployment retainkeys-demo --type strategic --patch-file patch-file-no-retainkeys.yaml
在輸出中,你可以看到當為 spec.strategy.rollingUpdate
定義了值時,不能將 type
設定為 Recreate
The Deployment "retainkeys-demo" is invalid: spec.strategy.rollingUpdate: Forbidden: may not be specified when strategy `type` is 'Recreate'
更新 type
值時,刪除 spec.strategy.rollingUpdate
值的方法是使用策略合併的 retainKeys
策略。
建立另一個名為 patch-file-retainkeys.yaml
的檔案,其內容如下
spec:
strategy:
$retainKeys:
- type
type: Recreate
透過此補丁,我們表明我們只想保留 strategy
物件的 type
鍵。因此,rollingUpdate
將在補丁操作期間被移除。
再次使用此新補丁修補你的 Deployment
kubectl patch deployment retainkeys-demo --type strategic --patch-file patch-file-retainkeys.yaml
檢查 Deployment 的內容
kubectl get deployment retainkeys-demo --output yaml
輸出顯示 Deployment 中的策略物件不再包含 rollingUpdate
鍵
spec:
strategy:
type: Recreate
template:
關於使用 retainKeys 策略的策略合併補丁的注意事項
你在前面的練習中執行的補丁稱為*帶 retainKeys 策略的策略合併補丁*。此方法引入了一個新的指令 $retainKeys
,它具有以下策略
- 它包含一個字串列表。
- 所有需要保留的欄位都必須存在於
$retainKeys
列表中。 - 存在的欄位將與活動物件合併。
- 修補時,所有缺失的欄位都將被清除。
$retainKeys
列表中的所有欄位必須是補丁中存在的欄位的超集或相同。
retainKeys
策略不適用於所有物件。它只在 Kubernetes 原始碼中欄位標籤中的 patchStrategy
鍵的值包含 retainKeys
時才起作用。例如,DeploymentSpec
結構體的 Strategy
欄位具有 retainKeys
的 patchStrategy
type DeploymentSpec struct {
...
// +patchStrategy=retainKeys
Strategy DeploymentStrategy `json:"strategy,omitempty" patchStrategy:"retainKeys" ...`
...
}
你還可以在 OpenApi 規範 中看到 retainKeys
策略
"io.k8s.api.apps.v1.DeploymentSpec": {
...,
"strategy": {
"$ref": "#/definitions/io.k8s.api.apps.v1.DeploymentStrategy",
"description": "The deployment strategy to use to replace existing pods with new ones.",
"x-kubernetes-patch-strategy": "retainKeys"
},
....
}
你還可以在 Kubernetes API 文件 中看到 retainKeys
策略。
kubectl patch 命令的其他形式
kubectl patch
命令接受 YAML 或 JSON。它既可以接受檔案作為補丁,也可以直接在命令列上接受補丁。
建立一個名為 patch-file.json
的檔案,其內容如下
{
"spec": {
"template": {
"spec": {
"containers": [
{
"name": "patch-demo-ctr-2",
"image": "redis"
}
]
}
}
}
}
以下命令是等效的
kubectl patch deployment patch-demo --patch-file patch-file.yaml
kubectl patch deployment patch-demo --patch 'spec:\n template:\n spec:\n containers:\n - name: patch-demo-ctr-2\n image: redis'
kubectl patch deployment patch-demo --patch-file patch-file.json
kubectl patch deployment patch-demo --patch '{"spec": {"template": {"spec": {"containers": [{"name": "patch-demo-ctr-2","image": "redis"}]}}}}'
使用帶有 --subresource
的 kubectl patch
更新物件的副本計數
--subresource=[subresource-name]
標誌與 kubectl 命令(如 get、patch、edit、apply 和 replace)一起使用,用於獲取和更新你指定的資源的 status
、scale
和 resize
子資源。你可以為任何 Kubernetes API 資源(內建和 CR)指定子資源,這些資源具有 status
、scale
或 resize
子資源。
例如,Deployment 具有 status
子資源和 scale
子資源,因此你可以使用 kubectl
僅獲取或修改 Deployment 的 status
子資源。
這是一個具有兩個副本的 Deployment 的清單
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 2 # tells deployment to run 2 pods matching the template
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
建立 Deployment
kubectl apply -f https://k8s.io/examples/application/deployment.yaml
檢視與你的 Deployment 關聯的 Pod
kubectl get pods -l app=nginx
在輸出中,你可以看到 Deployment 有兩個 Pod。例如
NAME READY STATUS RESTARTS AGE
nginx-deployment-7fb96c846b-22567 1/1 Running 0 47s
nginx-deployment-7fb96c846b-mlgns 1/1 Running 0 47s
現在,使用 --subresource=[subresource-name]
標誌修補該 Deployment
kubectl patch deployment nginx-deployment --subresource='scale' --type='merge' -p '{"spec":{"replicas":3}}'
輸出為:
scale.autoscaling/nginx-deployment patched
檢視與你的已修補 Deployment 關聯的 Pod
kubectl get pods -l app=nginx
在輸出中,你可以看到建立了一個新的 Pod,因此現在你有 3 個正在執行的 Pod。
NAME READY STATUS RESTARTS AGE
nginx-deployment-7fb96c846b-22567 1/1 Running 0 107s
nginx-deployment-7fb96c846b-lxfr2 1/1 Running 0 14s
nginx-deployment-7fb96c846b-mlgns 1/1 Running 0 107s
檢視已修補的 Deployment
kubectl get deployment nginx-deployment -o yaml
...
spec:
replicas: 3
...
status:
...
availableReplicas: 3
readyReplicas: 3
replicas: 3
注意
如果你執行kubectl patch
併為不支援特定子資源的資源指定 --subresource
標誌,API 伺服器將返回 404 Not Found 錯誤。總結
在本練習中,你使用 kubectl patch
更改了 Deployment 物件的即時配置。你沒有更改最初用於建立 Deployment 物件的配置檔案。用於更新 API 物件的其他命令包括 kubectl annotate、kubectl edit、kubectl replace、kubectl scale 和 kubectl apply。