使用 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 并创建了两个符合更新的 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 字段的 patchStrategymerge

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 只有一个容忍度

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 补丁和 JSON 合并补丁

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

此时,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

通过此补丁,我们表明我们只希望保留 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 中的 strategy 对象不再包含 rollingUpdate

spec:
  strategy:
    type: Recreate
  template:

关于使用 retainKeys 策略的策略合并补丁的说明

您在前面练习中执行的补丁称为使用 retainKeys 策略的策略合并补丁。此方法引入了新的指令 $retainKeys,它具有以下策略

  • 它包含一个字符串列表。
  • 所有需要保留的字段都必须出现在 $retainKeys 列表中。
  • 存在的字段将与实时对象合并。
  • 所有缺失的字段将在修补时被清除。
  • $retainKeys 列表中的所有字段必须是补丁中存在的字段的超集或相同。

retainKeys 策略并不适用于所有对象。它仅在 Kubernetes 源代码中字段标记中 patchStrategy 键的值包含 retainKeys 时才有效。例如,DeploymentSpec 结构的 Strategy 字段的 patchStrategyretainKeys

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

使用 kubectl patch--subresource 更新对象的副本数量

功能状态: Kubernetes v1.24 [alpha]

标志 --subresource=[subresource-name] 用于与 kubectl 命令(如 get、patch、edit 和 replace)一起使用,以获取和更新资源的 statusscale 子资源(适用于 kubectl 版本 v1.24 或更高版本)。此标志用于所有具有 statusscale 子资源的 API 资源(内置资源和 CR)。Deployment 是支持这些子资源的示例之一。

这是一个具有两个副本的 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

下一步

上次修改时间:2024 年 6 月 2 日凌晨 2:43 PST:修改图像 node-hello 为 hello-app (#46582) (d5b194da5b)