使用 kubectl patch 就地更新 API 物件

使用 kubectl patch 就地更新 Kubernetes API 物件。執行策略性合併修補或 JSON 合併修補。

此任務說明如何使用 kubectl patch 就地更新 API 物件。此任務中的練習示範策略性合併修補與 JSON 合併修補。

準備開始

您需要有一個 Kubernetes 叢集,且必須將 kubectl 命令列工具設定為與您的叢集通訊。建議在至少有兩個節點且未作為控制平面主機的叢集上執行本教學課程。如果您還沒有叢集,可以使用 minikube 建立一個,或者您可以使用下列 Kubernetes Playground 之一

若要檢查版本,請輸入 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,並建立兩個符合更新後 Deployment 規格的新 Pod。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 欄位具有 mergepatchStrategy

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 策略。

建立一個名為 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 鍵。因此,策略性合併 patch 使用預設的 patch 策略,即 replace

type PodSpec struct {
  ...
  Tolerations []Toleration `json:"tolerations,omitempty" protobuf:"bytes,22,opt,name=tolerations"`
  ...
}

使用 JSON 合併 patch 來更新 Deployment

策略性合併 patch 與 JSON 合併 patch 不同。使用 JSON 合併 patch,如果您想要更新清單,則必須指定整個新清單。而新清單會完全取代現有清單。

kubectl patch 命令有一個 type 參數,您可以將其設定為以下值之一

參數值合併類型
jsonJSON Patch,RFC 6902
mergeJSON 合併 Patch,RFC 7386
strategic策略性合併 patch

如需 JSON patch 和 JSON 合併 patch 的比較,請參閱 JSON Patch 和 JSON 合併 Patch

type 參數的預設值為 strategic。因此,在前面的練習中,您執行的是策略性合併 patch。

接下來,在同一個 Deployment 上執行 JSON 合併 patch。建立一個名為 patch-file-2.yaml 的檔案,內容如下:

spec:
  template:
    spec:
      containers:
      - name: patch-demo-ctr-3
        image: gcr.io/google-samples/hello-app:2.0

在您的 patch 命令中,將 type 設定為 merge

kubectl patch deployment patch-demo --type merge --patch-file patch-file-2.yaml

檢視已修補的 Deployment

kubectl get deployment patch-demo --output yaml

您在 patch 中指定的 containers 清單只有一個 Container。輸出顯示您的一個 Container 清單取代了現有的 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 只執行一個 Container。

NAME                          READY     STATUS    RESTARTS   AGE
patch-demo-1307768864-69308   1/1       Running   0          1m
patch-demo-1307768864-c86dc   1/1       Running   0          1m

使用策略性合併 patch,透過 retainKeys 策略更新 Deployment

以下是 Deployment 的組態檔,該 Deployment 使用 RollingUpdate 策略

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

此時,Deployment 已建立並正在使用 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

透過此 patch,我們表明我們只想保留 strategy 物件的 type 鍵。因此,rollingUpdate 將在 patch 操作期間被移除。

使用此新 patch 再次 patch 您的 Deployment

kubectl patch deployment retainkeys-demo --type strategic --patch-file patch-file-retainkeys.yaml

檢查 Deployment 的內容

kubectl get deployment retainkeys-demo --output yaml

輸出顯示 Deployment 中的 strategy 物件不再包含 rollingUpdate

spec:
  strategy:
    type: Recreate
  template:

關於使用 retainKeys 策略的策略性合併 patch 的注意事項

您在前面練習中執行的 patch 稱為具有 retainKeys 策略的策略性合併 patch。此方法引入了一個新的指令 $retainKeys,它具有以下策略

  • 它包含一個字串清單。
  • 所有需要保留的欄位都必須存在於 $retainKeys 清單中。
  • 存在的欄位將與即時物件合併。
  • 所有遺失的欄位將在 patch 時清除。
  • $retainKeys 清單中的所有欄位都必須是 patch 中存在的欄位的超集或相同集合。

retainKeys 策略並非適用於所有物件。它僅在 Kubernetes 原始碼中欄位標籤中的 patchStrategy 鍵值包含 retainKeys 時才有效。例如,DeploymentSpec 結構的 Strategy 欄位具有 retainKeyspatchStrategy

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 作為檔案或直接在命令列上取得。

建立一個名為 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"}]}}}}'

使用 kubectl patch--subresource 更新物件的副本計數

功能狀態: Kubernetes v1.24 [alpha]

旗標 --subresource=[subresource-name] 與 kubectl 命令(如 get、patch、edit 和 replace)搭配使用,以擷取和更新資源的 statusscale 子資源(適用於 kubectl 版本 v1.24 或更高版本)。此旗標與所有具有 statusscale 子資源的 API 資源(內建和 CR)搭配使用。Deployment 是支援這些子資源的範例之一。

以下是具有兩個副本的 Deployment 的 manifest

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] 旗標 patch 該 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 來變更 Deployment 物件的即時組態。您沒有變更最初用於建立 Deployment 物件的組態檔。用於更新 API 物件的其他命令包括 kubectl annotatekubectl editkubectl replacekubectl scalekubectl apply

下一步

上次修改時間:2024 年 6 月 2 日 凌晨 2:43 PST:Modify the image node-hello to hello-app (#46582) (d5b194da5b)