使用 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 只有一个 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 补丁和 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

这是一个 Deployment 的配置文件,它使用 RollingUpdate 策略

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=[子资源名称] 标志与 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=[子资源名称] 标志修补该 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)