使用 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)