使用 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 关联的 Pods

kubectl get pods

输出显示 Deployment 拥有两个 Pods。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

记下正在运行的 Pods 的名称。稍后您将看到这些 Pods 被终止并由新的 Pods 替换。

此时,每个 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 关联的 Pods

kubectl get pods

输出显示正在运行的 Pods 拥有与以前运行的 Pods 不同的名称。Deployment 终止了旧的 Pods,并创建了两个符合更新的 Deployment 规范的新 Pods。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 Patch,RFC 6902
mergeJSON 合并补丁,RFC 7386
strategic策略合并补丁

要比较 JSON Patch 和 JSON 合并补丁,请参阅 JSON Patch 和 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

列出正在运行的 Pods

kubectl get pods

在输出中,您可以看到现有的 Pods 被终止了,并且创建了新的 Pods。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 关联的 Pods

kubectl get pods -l app=nginx

在输出中,您可以看到 Deployment 拥有两个 Pods。例如

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 关联的 Pods

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)