使用 kubectl patch 就地更新 API 物件

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

此任務演示如何使用 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 欄位具有 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-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 引數,你可以將其設定為以下值之一

引數值合併型別
jsonJSON 補丁,RFC 6902
mergeJSON 合併補丁,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 欄位具有 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-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"}]}}}}'

使用帶有 --subresourcekubectl patch 更新物件的副本計數

--subresource=[subresource-name] 標誌與 kubectl 命令(如 get、patch、edit、apply 和 replace)一起使用,用於獲取和更新你指定的資源的 statusscaleresize 子資源。你可以為任何 Kubernetes API 資源(內建和 CR)指定子資源,這些資源具有 statusscaleresize 子資源。

例如,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 更改了 Deployment 物件的即時配置。你沒有更改最初用於建立 Deployment 物件的配置檔案。用於更新 API 物件的其他命令包括 kubectl annotatekubectl editkubectl replacekubectl scalekubectl apply

下一步

最後修改於 2025 年 2 月 19 日太平洋標準時間上午 11:19:更新 kubetl 子資源文件 (ab6b9ae2ed)