Kubernetes 使用kubectl patch更新API對象

2022-06-13 09:43 更新

使用 kubectl patch 更新 API 對象

這個任務(wù)展示如何使用 ?kubectl patch? 就地更新 API 對象。 這個任務(wù)中的練習(xí)演示了一個策略性合并 patch 和一個 JSON 合并 patch。

在開始之前

你必須擁有一個 Kubernetes 的集群,同時你的 Kubernetes 集群必須帶有 kubectl 命令行工具。 建議在至少有兩個節(jié)點的集群上運行本教程,且這些節(jié)點不作為控制平面主機。 如果你還沒有集群,你可以通過 Minikube 構(gòu)建一個你自己的集群,或者你可以使用下面任意一個 Kubernetes 工具構(gòu)建:

要獲知版本信息,請輸入 ?kubectl version?。

使用策略合并 patch 更新 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

創(chuàng)建 Deployment:

kubectl apply -f https://k8s.io/examples/application/deployment-patch.yaml

查看與 Deployment 相關(guān)的 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 鏡像的容器?,F(xiàn)在假設(shè)你希望每個 Pod 有兩個容器:一個運行 nginx,另一個運行 redis。

創(chuàng)建一個名為 ?patch-file.yaml? 的文件。內(nèi)容如下:

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
  ...

查看與 patch Deployment 相關(guān)的 Pod:

kubectl get pods

輸出顯示正在運行的 Pod 與以前運行的 Pod 有不同的名稱。Deployment 終止了舊的 Pod,并創(chuàng)建了兩個 符合更新的部署規(guī)范的新 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

仔細(xì)查看其中一個 patch-demo Pod:

kubectl get pod <your-pod-name> --output yaml

輸出顯示 Pod 有兩個容器:一個運行 nginx,一個運行 redis:

containers:
- image: redis
  ...
- image: nginx
  ...

策略性合并類的 patch 的說明 

你在前面的練習(xí)中所做的 patch 稱為 ?策略性合并 patch(Strategic Merge Patch)?。 請注意,patch 沒有替換 ?containers ?列表。相反,它向列表中添加了一個新 Container。換句話說, patch 中的列表與現(xiàn)有列表合并。當(dāng)你在列表中使用策略性合并 patch 時,并不總是這樣。 在某些情況下,列表是替換的,而不是合并的。

對于策略性合并 patch,列表可以根據(jù)其 patch 策略進(jìn)行替換或合并。 patch 策略由 Kubernetes 源代碼中字段標(biāo)記中的 ?patchStrategy ?鍵的值指定。 例如,?PodSpec ?結(jié)構(gòu)體的 ?Containers? 字段的 ?patchStrategy ?為 ?merge?:

type PodSpec struct {
  ...
  Containers []Container `json:"containers" patchStrategy:"merge" patchMergeKey:"name" ...`

你還可以在 OpenApi spec 規(guī)范中看到 patch 策略:

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

創(chuàng)建一個名為 ?patch-file-tolerations.yaml? 的文件。內(nèi)容如下:

spec:
  template:
    spec:
      tolerations:
      - effect: NoSchedule
        key: disktype
        value: ssd

對 Deployment 執(zhí)行 patch 操作:

kubectl patch deployment patch-demo --patch-file patch-file-tolerations.yaml

查看修補后的 Deployment:

kubectl get deployment patch-demo --output yaml

輸出結(jié)果顯示 Deployment 中的 PodSpec 只有一個容忍度設(shè)置:

containers:
- image: redis
  imagePullPolicy: Always
  name: patch-demo-ctr-2
  ...
- image: nginx
  imagePullPolicy: Always
  name: patch-demo-ctr
  ...
tolerations:
  - effect: NoSchedule
    key: disktype
    value: ssd

請注意,PodSpec 中的 ?tolerations ?列表被替換,而不是合并。這是因為 PodSpec 的 ?tolerations ?的字段標(biāo)簽中沒有 ?patchStrategy ?鍵。所以策略合并 patch 操作使用默認(rèn)的 patch 策略,也就是 ?replace?。

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

使用 JSON 合并 patch 更新 Deployment 

策略性合并 patch 不同于 JSON 合并 patch。 使用 JSON 合并 patch,如果你想更新列表,你必須指定整個新列表。新的列表完全取代現(xiàn)有的列表。

?kubectl patch? 命令有一個 ?type ?參數(shù),你可以將其設(shè)置為以下值之一:

參數(shù)值 合并類型
json JSON Patch, RFC 6902
merge JSON Merge Patch, RFC 7386
strategic 策略合并 patch

有關(guān) JSON patch 和 JSON 合并 patch 的比較,查看 JSON patch 和 JSON 合并 patch

?type ?參數(shù)的默認(rèn)值是 ?strategic?。在前面的練習(xí)中,我們做了一個策略性的合并 patch。

下一步,在相同的 Deployment 上執(zhí)行 JSON 合并 patch。創(chuàng)建一個名為 ?patch-file-2? 的文件。內(nèi)容如下:

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

在 patch 命令中,將 ?type ?設(shè)置為 ?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。 輸出顯示你所給出的 Contaier 列表替換了現(xiàn)有的 ?containers ?列表。

spec:
  containers:
  - image: gcr.io/google-samples/node-hello:1.0
    ...
    name: patch-demo-ctr-3

列表中運行的 Pod:

kubectl get pods

在輸出中,你可以看到已經(jīng)終止了現(xiàn)有的 Pod,并創(chuàng)建了新的 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 策略的策略合并 patch 更新 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

創(chuàng)建 Deployment:

kubectl apply -f https://k8s.io/examples/application/deployment-retainkeys.yaml

這時,Deployment 被創(chuàng)建,并使用 ?RollingUpdate ?策略。

創(chuàng)建一個名為 ?patch-file-no-retainkeys.yaml? 的文件,內(nèi)容如下:

spec:
  strategy:
    type: Recreate

修補你的 Deployment:

kubectl patch deployment retainkeys-demo --type merge --patch-file patch-file-no-retainkeys.yaml

在輸出中,你可以看到,當(dāng) ?spec.strategy.rollingUpdate? 已經(jīng)擁有取值定義時, 將其 ?type ?設(shè)置為 ?Recreate ?是不可能的。

The Deployment "retainkeys-demo" is invalid: spec.strategy.rollingUpdate: Forbidden: may not be specified when strategy `type` is 'Recreate'

更新 ?type ?取值的同時移除 ?spec.strategy.rollingUpdate? 現(xiàn)有值的方法是 為策略性合并操作設(shè)置 ?retainKeys ?策略:

創(chuàng)建另一個名為 ?patch-file-retainkeys.yaml? 的文件,內(nèi)容如下:

spec:
  strategy:
    $retainKeys:
    - type
    type: Recreate

使用此 patch,我們表達(dá)了希望只保留 ?strategy ?對象的 ?type ?鍵。 這樣,在 patch 操作期間 ?rollingUpdate ?會被刪除。

使用新的 patch 重新修補 Deployment:

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

檢查 Deployment 的內(nèi)容:

kubectl get deployment retainkeys-demo --output yaml

輸出顯示 Deployment 中的 ?strategy ?對象不再包含 ?rollingUpdate ?鍵:

spec:
  strategy:
    type: Recreate
  template:

關(guān)于使用 retainKeys 策略的策略合并 patch 操作的說明 

在前文練習(xí)中所執(zhí)行的稱作 帶 ?retainKeys ?策略的策略合并 patch(Strategic Merge Patch with retainKeys Strategy)。 這種方法引入了一種新的 ?$retainKey? 指令,具有如下策略:

  • 其中包含一個字符串列表;
  • 所有需要被保留的字段必須在 ?$retainKeys? 列表中給出;
  • 對于已有的字段,會和對象上對應(yīng)的內(nèi)容合并;
  • 在修補操作期間,未找到的字段都會被清除;
  • 列表 ?$retainKeys? 中的所有字段必須 patch 操作所給字段的超集,或者與之完全一致。

策略 ?retainKeys ?并不能對所有對象都起作用。它僅對那些 Kubernetes 源碼中 ?patchStrategy ?字段標(biāo)志值包含 ?retainKeys ?的字段有用。 例如 ?DeploymentSpec ?結(jié)構(gòu)的 ?Strategy ?字段就包含了 ?patchStrategy ?為 ?retainKeys ?的標(biāo)志。

type DeploymentSpec struct {
  ...
  // +patchStrategy=retainKeys
  Strategy DeploymentStrategy `json:"strategy,omitempty" patchStrategy:"retainKeys" ...`

你也可以查看 OpenAPI 規(guī)范中的 ?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 文檔中看到 ?retainKey ?策略。

kubectl patch 命令的其他形式 

?kubectl patch? 命令使用 YAML 或 JSON。它可以接受以文件形式提供的補丁,也可以 接受直接在命令行中給出的補丁。

創(chuàng)建一個文件名稱是 ?patch-file.json? 內(nèi)容如下:

{
   "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"}]}}}}'

總結(jié) 

在本練習(xí)中,你使用 ?kubectl patch? 更改了 Deployment 對象的當(dāng)前配置。 你沒有更改最初用于創(chuàng)建 Deployment 對象的配置文件。 用于更新 API 對象的其他命令包括 ?kubectl annotate?、 ?kubectl edit?、 ?kubectl replace?、 ?kubectl scale? 和 ?kubectl apply?。

說明: 定制資源不支持策略性合并 patch。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號