使用配置文件声明式管理 Kubernetes 对象

Kubernetes 对象可以通过将多个对象配置文件存储在目录中并使用 kubectl apply 递归地创建和更新这些对象来创建、更新和删除。这种方法保留了对活动对象的写入,而无需将更改合并回对象配置文件。kubectl diff 还提供了对 apply 将进行的更改的预览。

在您开始之前

安装 kubectl

您需要拥有一个 Kubernetes 集群,并且 kubectl 命令行工具必须配置为与您的集群通信。建议在至少有两个节点(不充当控制平面主机)的集群上运行本教程。如果您还没有集群,可以使用 minikube 创建一个集群,或者可以使用以下 Kubernetes 游乐场之一

要检查版本,请输入 kubectl version

权衡取舍

kubectl 工具支持三种类型的对象管理

  • 命令式命令
  • 命令式对象配置
  • 声明式对象配置

有关每种对象管理的优点和缺点的讨论,请参阅 Kubernetes 对象管理

概述

声明式对象配置需要牢固理解 Kubernetes 对象定义和配置。如果您尚未阅读并完成以下文档,请阅读并完成它们

以下是本文档中使用的术语的定义

  • 对象配置文件/配置文件:一个定义 Kubernetes 对象配置的文件。本主题介绍如何将配置文件传递给 kubectl apply。配置文件通常存储在源代码管理中,例如 Git。
  • 活动对象配置/活动配置:由 Kubernetes 集群观察到的对象的活动配置值。这些配置值保存在 Kubernetes 集群存储中,通常是 etcd。
  • 声明式配置编写者/声明式编写者:对活动对象进行更新的人员或软件组件。本主题中提到的活动编写者会对对象配置文件进行更改,并运行 kubectl apply 来写入更改。

如何创建对象

使用 kubectl apply 创建所有对象(除了已存在的对象),这些对象由指定目录中的配置文件定义

kubectl apply -f <directory>

这会将 kubectl.kubernetes.io/last-applied-configuration: '{...}' 注释设置到每个对象上。该注释包含用于创建对象的配置文件的内容。

以下是一个对象配置文件的示例

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  minReadySeconds: 5
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

运行 kubectl diff 以打印将要创建的对象

kubectl diff -f https://k8s.io/examples/application/simple_deployment.yaml

使用 kubectl apply 创建对象

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

使用 kubectl get 打印活动配置

kubectl get -f https://k8s.io/examples/application/simple_deployment.yaml -o yaml

输出显示 kubectl.kubernetes.io/last-applied-configuration 注释已写入活动配置,并且它与配置文件匹配

kind: Deployment
metadata:
  annotations:
    # ...
    # This is the json representation of simple_deployment.yaml
    # It was written by kubectl apply when the object was created
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"apps/v1","kind":"Deployment",
      "metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
      "spec":{"minReadySeconds":5,"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
      "spec":{"containers":[{"image":"nginx:1.14.2","name":"nginx",
      "ports":[{"containerPort":80}]}]}}}}      
  # ...
spec:
  # ...
  minReadySeconds: 5
  selector:
    matchLabels:
      # ...
      app: nginx
  template:
    metadata:
      # ...
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.14.2
        # ...
        name: nginx
        ports:
        - containerPort: 80
        # ...
      # ...
    # ...
  # ...

如何更新对象

您还可以使用 kubectl apply 更新目录中定义的所有对象,即使这些对象已存在。这种方法会实现以下目的

  1. 设置配置文件中显示的字段在活动配置中的值。
  2. 清除配置文件中删除的字段在活动配置中的值。
kubectl diff -f <directory>
kubectl apply -f <directory>

以下是一个配置文件示例

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  minReadySeconds: 5
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

使用 kubectl apply 创建对象

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

使用 kubectl get 打印活动配置

kubectl get -f https://k8s.io/examples/application/simple_deployment.yaml -o yaml

输出显示 kubectl.kubernetes.io/last-applied-configuration 注释已写入活动配置,并且它与配置文件匹配

kind: Deployment
metadata:
  annotations:
    # ...
    # This is the json representation of simple_deployment.yaml
    # It was written by kubectl apply when the object was created
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"apps/v1","kind":"Deployment",
      "metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
      "spec":{"minReadySeconds":5,"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
      "spec":{"containers":[{"image":"nginx:1.14.2","name":"nginx",
      "ports":[{"containerPort":80}]}]}}}}      
  # ...
spec:
  # ...
  minReadySeconds: 5
  selector:
    matchLabels:
      # ...
      app: nginx
  template:
    metadata:
      # ...
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.14.2
        # ...
        name: nginx
        ports:
        - containerPort: 80
        # ...
      # ...
    # ...
  # ...

使用 kubectl scale 直接更新活动配置中的 replicas 字段。这不会使用 kubectl apply

kubectl scale deployment/nginx-deployment --replicas=2

使用 kubectl get 打印活动配置

kubectl get deployment nginx-deployment -o yaml

输出显示 replicas 字段已设置为 2,last-applied-configuration 注释不包含 replicas 字段

apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    # ...
    # note that the annotation does not contain replicas
    # because it was not updated through apply
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"apps/v1","kind":"Deployment",
      "metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
      "spec":{"minReadySeconds":5,"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
      "spec":{"containers":[{"image":"nginx:1.14.2","name":"nginx",
      "ports":[{"containerPort":80}]}]}}}}      
  # ...
spec:
  replicas: 2 # written by scale
  # ...
  minReadySeconds: 5
  selector:
    matchLabels:
      # ...
      app: nginx
  template:
    metadata:
      # ...
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.14.2
        # ...
        name: nginx
        ports:
        - containerPort: 80
      # ...

更新 simple_deployment.yaml 配置文件以将映像从 nginx:1.14.2 更改为 nginx:1.16.1,并删除 minReadySeconds 字段

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.16.1 # update the image
        ports:
        - containerPort: 80

应用对配置文件所做的更改

kubectl diff -f https://k8s.io/examples/application/update_deployment.yaml
kubectl apply -f https://k8s.io/examples/application/update_deployment.yaml

使用 kubectl get 打印活动配置

kubectl get -f https://k8s.io/examples/application/update_deployment.yaml -o yaml

输出显示对活动配置的以下更改

  • replicas 字段保留由 kubectl scale 设置的值 2。这是因为该字段已从配置文件中省略。
  • image 字段已从 nginx:1.14.2 更新为 nginx:1.16.1
  • last-applied-configuration 注释已使用新的映像更新。
  • minReadySeconds 字段已清除。
  • last-applied-configuration 注释不再包含 minReadySeconds 字段。
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    # ...
    # The annotation contains the updated image to nginx 1.16.1,
    # but does not contain the updated replicas to 2
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"apps/v1","kind":"Deployment",
      "metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
      "spec":{"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
      "spec":{"containers":[{"image":"nginx:1.16.1","name":"nginx",
      "ports":[{"containerPort":80}]}]}}}}      
    # ...
spec:
  replicas: 2 # Set by `kubectl scale`.  Ignored by `kubectl apply`.
  # minReadySeconds cleared by `kubectl apply`
  # ...
  selector:
    matchLabels:
      # ...
      app: nginx
  template:
    metadata:
      # ...
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.16.1 # Set by `kubectl apply`
        # ...
        name: nginx
        ports:
        - containerPort: 80
        # ...
      # ...
    # ...
  # ...

如何删除对象

有两种方法可以删除由 kubectl apply 管理的对象。

使用命令式命令手动删除对象是推荐方法,因为它更明确地说明了要删除的内容,并且不太可能导致用户意外删除内容

kubectl delete -f <filename>

备用方法:kubectl apply -f <directory> --prune

作为 kubectl delete 的替代方法,您可以在将对象清单从本地文件系统中的目录中删除后,使用 kubectl apply 来识别要删除的对象。

在 Kubernetes 1.31 中,kubectl apply 中提供了两种修剪模式

  • 基于允许列表的修剪:这种模式自 kubectl v1.5 起就存在,但由于其设计在可用性、正确性和性能方面存在问题,因此仍处于 Alpha 阶段。基于 ApplySet 的模式旨在替代它。
  • 基于 ApplySet 的修剪:apply set 是一个服务器端对象(默认情况下,是一个 Secret),kubectl 可以使用它在所有 apply 操作中准确高效地跟踪集合成员资格。这种模式是在 kubectl v1.27 中作为 Alpha 版本引入的,用于替代基于允许列表的修剪。

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

要使用基于允许列表的修剪,请将以下标志添加到您的 kubectl apply 调用中

  • --prune:删除先前应用的但在当前调用传递的集合中不存在的对象。
  • --prune-allowlist:要考虑用于修剪的组-版本-种类 (GVK) 列表。此标志是可选的,但强烈建议使用,因为其默认值是名称空间类型和集群范围类型的部分列表,这会导致意外结果。
  • --selector/-l:使用标签选择器来约束要选择用于修剪的对象集。此标志是可选的,但强烈建议使用。
  • --all:使用该标志而不是 --selector/-l 以显式地选择所有先前应用的允许列表类型对象。

基于允许列表的修剪会查询 API 服务器以获取所有与给定标签匹配(如果有)的允许列表 GVK 对象,并尝试将返回的活动对象配置与对象清单文件进行匹配。如果对象与查询匹配,并且它在目录中没有清单,并且它具有 kubectl.kubernetes.io/last-applied-configuration 注释,则会将其删除。

kubectl apply -f <directory> --prune -l <labels> --prune-allowlist=<gvk-list>

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

要使用基于 ApplySet 的修剪,请设置 KUBECTL_APPLYSET=true 环境变量,并将以下标志添加到您的 kubectl apply 调用中

  • --prune:删除先前应用的但在当前调用传递的集合中不存在的对象。
  • --applyset:kubectl 可用于在所有 apply 操作中准确高效地跟踪集合成员资格的对象的名称。
KUBECTL_APPLYSET=true kubectl apply -f <directory> --prune --applyset=<name>

默认情况下,使用的 ApplySet 父对象的类型是一个 Secret。但是,也可以使用 ConfigMap,格式为:--applyset=configmaps/<name>。当使用 Secret 或 ConfigMap 时,kubectl 会在该对象不存在时创建该对象。

还可以使用自定义资源作为 ApplySet 父对象。要启用此功能,请为要使用的自定义资源定义 (CRD) 添加以下标签:applyset.kubernetes.io/is-parent-type: true。然后,创建要用作 ApplySet 父对象的该对象(kubectl 不会为自定义资源自动执行此操作)。最后,在 applyset 标志中引用该对象,如下所示:--applyset=<resource>.<group>/<name>(例如,widgets.custom.example.com/widget-name)。

使用 ApplySet 基于修剪功能,kubectl 在将对象发送到服务器之前,会为集合中的每个对象添加 applyset.kubernetes.io/part-of=<parentID> 标签。出于性能考虑,它还会收集集合包含的资源类型和命名空间列表,并在活动父对象上的注释中添加这些信息。最后,在 apply 操作结束时,它会查询 API 服务器以获取那些命名空间(或根据情况在集群范围)中的属于该集合的那些类型的对象,这些对象由 applyset.kubernetes.io/part-of=<parentID> 标签定义。

注意事项和限制

  • 每个对象最多可以是单个集合的成员。
  • 使用任何带命名空间的父对象(包括默认 Secret)时,都需要 --namespace 标志。这意味着跨越多个命名空间的 ApplySet 必须使用集群范围的自定义资源作为父对象。
  • 为了安全地将基于 ApplySet 的修剪与多个目录一起使用,请为每个目录使用唯一的 ApplySet 名称。

如何查看对象

可以使用 kubectl get 加上 -o yaml 来查看活动对象的配置。

kubectl get -f <filename|url> -o yaml

apply 如何计算差异并合并更改

kubectl apply 更新对象的活动配置时,它通过向 API 服务器发送一个补丁请求来实现。补丁定义了作用于活动对象配置特定字段的更新。kubectl apply 命令使用配置文件、活动配置和存储在活动配置中的 last-applied-configuration 注释来计算此补丁请求。

合并补丁计算

kubectl apply 命令将配置文件的内容写入 kubectl.kubernetes.io/last-applied-configuration 注释。这用于识别已从配置文件中删除且需要从活动配置中清除的字段。以下是用于计算应删除或设置哪些字段的步骤:

  1. 计算要删除的字段。这些字段存在于 last-applied-configuration 中,但在配置文件中不存在。
  2. 计算要添加或设置的字段。这些字段存在于配置文件中,其值与活动配置不匹配。

以下是一个示例。假设这是 Deployment 对象的配置文件:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.16.1 # update the image
        ports:
        - containerPort: 80

同样,假设这是同一个 Deployment 对象的活动配置:

apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    # ...
    # note that the annotation does not contain replicas
    # because it was not updated through apply
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"apps/v1","kind":"Deployment",
      "metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
      "spec":{"minReadySeconds":5,"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
      "spec":{"containers":[{"image":"nginx:1.14.2","name":"nginx",
      "ports":[{"containerPort":80}]}]}}}}      
  # ...
spec:
  replicas: 2 # written by scale
  # ...
  minReadySeconds: 5
  selector:
    matchLabels:
      # ...
      app: nginx
  template:
    metadata:
      # ...
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.14.2
        # ...
        name: nginx
        ports:
        - containerPort: 80
      # ...

以下是 kubectl apply 将执行的合并计算:

  1. 通过从 last-applied-configuration 中读取值并将其与配置文件中的值进行比较,来计算要删除的字段。无论本地对象配置文件中显式设置为 null 的字段是否出现在 last-applied-configuration 中,都要将其清除。在本例中,minReadySeconds 出现在 last-applied-configuration 注释中,但未出现在配置文件中。操作: 从活动配置中清除 minReadySeconds
  2. 通过从配置文件中读取值并将其与活动配置中的值进行比较,来计算要设置的字段。在本例中,配置文件中 image 的值与活动配置中的值不匹配。操作: 设置活动配置中 image 的值。
  3. last-applied-configuration 注释设置为与配置文件的值匹配。
  4. 将 1、2、3 的结果合并成单个补丁请求,发送到 API 服务器。

以下是作为合并结果的活动配置:

apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    # ...
    # The annotation contains the updated image to nginx 1.16.1,
    # but does not contain the updated replicas to 2
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"apps/v1","kind":"Deployment",
      "metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
      "spec":{"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
      "spec":{"containers":[{"image":"nginx:1.16.1","name":"nginx",
      "ports":[{"containerPort":80}]}]}}}}      
    # ...
spec:
  selector:
    matchLabels:
      # ...
      app: nginx
  replicas: 2 # Set by `kubectl scale`.  Ignored by `kubectl apply`.
  # minReadySeconds cleared by `kubectl apply`
  # ...
  template:
    metadata:
      # ...
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.16.1 # Set by `kubectl apply`
        # ...
        name: nginx
        ports:
        - containerPort: 80
        # ...
      # ...
    # ...
  # ...

不同类型的字段如何合并

配置文件中的特定字段如何与活动配置合并,取决于该字段的类型。有几种类型的字段:

  • 原始类型:字符串、整数或布尔值类型的字段。例如,imagereplicas 是原始类型字段。操作: 替换。

  • 映射,也称为对象:类型为映射或包含子字段的复杂类型的字段。例如,labelsannotationsspecmetadata 都是映射。操作: 合并元素或子字段。

  • 列表:包含项目的字段,这些项目可以是原始类型或映射。例如,containersportsargs 都是列表。操作: 变化。

kubectl apply 更新映射或列表字段时,它通常不会替换整个字段,而是更新各个子元素。例如,当合并 Deployment 上的 spec 时,不会替换整个 spec。相反,会比较和合并 spec 的子字段(如 replicas)。

合并对原始类型字段的更改

原始类型字段被替换或清除。

对象配置文件中的字段活动对象配置中的字段last-applied-configuration 中的字段操作
-将活动设置为配置文件值。
-将活动设置为本地配置。
-从活动配置中清除。
-不做任何操作。保留活动值。

合并对映射字段的更改

表示映射的字段通过比较映射的每个子字段或元素来合并

对象配置文件中的键活动对象配置中的键last-applied-configuration 中的字段操作
-比较子字段值。
-将活动设置为本地配置。
-从活动配置中删除。
-不做任何操作。保留活动值。

合并对类型为列表的字段的更改

合并对列表的更改使用三种策略之一

  • 如果所有元素都是原始类型,则替换该列表。
  • 合并复杂元素列表中的各个元素。
  • 合并原始元素列表。

策略的选择是在每个字段的基础上进行的。

如果所有元素都是原始类型,则替换该列表

将列表视为原始类型字段。替换或删除整个列表。这会保留顺序。

示例: 使用 kubectl apply 更新 Pod 中容器的 args 字段。这会将活动配置中的 args 值设置为配置文件中的值。之前添加到活动配置中的任何 args 元素都会丢失。配置文件中定义的 args 元素的顺序将保留在活动配置中。

# last-applied-configuration value
    args: ["a", "b"]

# configuration file value
    args: ["a", "c"]

# live configuration
    args: ["a", "b", "d"]

# result after merge
    args: ["a", "c"]

说明: 合并使用配置文件值作为新的列表值。

合并复杂元素列表中的各个元素

将列表视为映射,并将每个元素的特定字段视为键。添加、删除或更新各个元素。这不会保留顺序。

这种合并策略在每个字段上使用一个名为 patchMergeKey 的特殊标签。patchMergeKey 在 Kubernetes 源代码中为每个字段定义:types.go 当合并映射列表时,为给定元素指定的 patchMergeKey 字段值将用作该元素的映射键。

示例: 使用 kubectl apply 更新 PodSpec 的 containers 字段。这会将列表合并,就好像它是一个映射,每个元素都以 name 为键。

# last-applied-configuration value
    containers:
    - name: nginx
      image: nginx:1.16
    - name: nginx-helper-a # key: nginx-helper-a; will be deleted in result
      image: helper:1.3
    - name: nginx-helper-b # key: nginx-helper-b; will be retained
      image: helper:1.3

# configuration file value
    containers:
    - name: nginx
      image: nginx:1.16
    - name: nginx-helper-b
      image: helper:1.3
    - name: nginx-helper-c # key: nginx-helper-c; will be added in result
      image: helper:1.3

# live configuration
    containers:
    - name: nginx
      image: nginx:1.16
    - name: nginx-helper-a
      image: helper:1.3
    - name: nginx-helper-b
      image: helper:1.3
      args: ["run"] # Field will be retained
    - name: nginx-helper-d # key: nginx-helper-d; will be retained
      image: helper:1.3

# result after merge
    containers:
    - name: nginx
      image: nginx:1.16
      # Element nginx-helper-a was deleted
    - name: nginx-helper-b
      image: helper:1.3
      args: ["run"] # Field was retained
    - name: nginx-helper-c # Element was added
      image: helper:1.3
    - name: nginx-helper-d # Element was ignored
      image: helper:1.3

说明

  • 名为“nginx-helper-a”的容器被删除,因为配置文件中没有出现名为“nginx-helper-a”的容器。
  • 名为“nginx-helper-b”的容器保留了活动配置中对 args 的更改。kubectl apply 能够识别出活动配置中的“nginx-helper-b”与配置文件中的“nginx-helper-b”相同,即使它们的字段具有不同的值(配置文件中没有 args)。这是因为 patchMergeKey 字段值(名称)在两者中都相同。
  • 名为“nginx-helper-c”的容器被添加,因为活动配置中没有出现该名称的容器,但配置文件中出现了一个该名称的容器。
  • 名为“nginx-helper-d”的容器被保留,因为 last-applied-configuration 中没有出现该名称的元素。

合并原始元素列表

从 Kubernetes 1.5 开始,不支持合并原始元素列表。

默认字段值

如果创建对象时未指定某些字段,API 服务器会在活动配置中将这些字段设置为默认值。

这是一个 Deployment 的配置文件。该文件没有指定 strategy

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  minReadySeconds: 5
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

使用 kubectl apply 创建对象

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

使用 kubectl get 打印活动配置

kubectl get -f https://k8s.io/examples/application/simple_deployment.yaml -o yaml

输出显示 API 服务器在活动配置中将几个字段设置为默认值。这些字段未在配置文件中指定。

apiVersion: apps/v1
kind: Deployment
# ...
spec:
  selector:
    matchLabels:
      app: nginx
  minReadySeconds: 5
  replicas: 1 # defaulted by apiserver
  strategy:
    rollingUpdate: # defaulted by apiserver - derived from strategy.type
      maxSurge: 1
      maxUnavailable: 1
    type: RollingUpdate # defaulted by apiserver
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.14.2
        imagePullPolicy: IfNotPresent # defaulted by apiserver
        name: nginx
        ports:
        - containerPort: 80
          protocol: TCP # defaulted by apiserver
        resources: {} # defaulted by apiserver
        terminationMessagePath: /dev/termination-log # defaulted by apiserver
      dnsPolicy: ClusterFirst # defaulted by apiserver
      restartPolicy: Always # defaulted by apiserver
      securityContext: {} # defaulted by apiserver
      terminationGracePeriodSeconds: 30 # defaulted by apiserver
# ...

在补丁请求中,不会重新设置默认字段的值,除非它们被显式清除作为补丁请求的一部分。这可能会导致根据其他字段的值设置默认值的字段出现意外行为。当其他字段稍后更改时,从它们设置的默认值不会更新,除非它们被显式清除。

因此,建议在配置文件中显式定义服务器设置默认值的一些字段,即使所需值与服务器默认值匹配。这使识别不会被服务器重新设置默认值的冲突值变得更容易。

示例

# last-applied-configuration
spec:
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

# configuration file
spec:
  strategy:
    type: Recreate # updated value
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

# live configuration
spec:
  strategy:
    type: RollingUpdate # defaulted value
    rollingUpdate: # defaulted value derived from type
      maxSurge : 1
      maxUnavailable: 1
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

# result after merge - ERROR!
spec:
  strategy:
    type: Recreate # updated value: incompatible with rollingUpdate
    rollingUpdate: # defaulted value: incompatible with "type: Recreate"
      maxSurge : 1
      maxUnavailable: 1
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

说明

  1. 用户创建了一个 Deployment,没有定义 strategy.type
  2. 服务器将 strategy.type 的默认值设置为 RollingUpdate,并将 strategy.rollingUpdate 值设置为默认值。
  3. 用户将 strategy.type 更改为 Recreatestrategy.rollingUpdate 值保持其默认值,尽管服务器期望它们被清除。如果 strategy.rollingUpdate 值最初在配置文件中定义,则更清楚地表明它们需要被删除。
  4. Apply 失败,因为 strategy.rollingUpdate 未被清除。strategy.rollingupdate 字段不能与 strategy.typeRecreate 一起定义。

建议:应在对象配置文件中显式定义这些字段

  • 工作负载(如 Deployment、StatefulSet、Job、DaemonSet、ReplicaSet 和 ReplicationController)上的选择器和 PodTemplate 标签
  • Deployment 发布策略

如何清除服务器设置的默认字段或其他写入者设置的字段

可以通过将这些字段的值设置为 null,然后应用配置文件来清除配置文件中未出现的字段。对于服务器设置的默认字段,这会触发重新设置其默认值。

如何更改配置文件和直接命令式写入者之间的字段所有权

以下是你应该用来更改单个对象字段的唯一方法

  • 使用 kubectl apply
  • 直接写入活动配置,而不修改配置文件:例如,使用 kubectl scale

将所有权从直接命令式写入者更改为配置文件

将该字段添加到配置文件中。对于该字段,停止对不经过 kubectl apply 的活动配置进行直接更新。

将所有权从配置文件更改为直接命令式写入者

从 Kubernetes 1.5 开始,将字段的所有权从配置文件更改为命令式写入者需要手动步骤

  • 从配置文件中删除该字段。
  • 从活动对象上的 kubectl.kubernetes.io/last-applied-configuration 注释中删除该字段。

更改管理方法

Kubernetes 对象应一次只使用一种方法进行管理。从一种方法切换到另一种方法是可能的,但这是一个手动过程。

从命令式命令管理迁移到声明式对象配置

从命令式命令管理迁移到声明式对象配置涉及几个手动步骤

  1. 将活动对象导出到本地配置文件

    kubectl get <kind>/<name> -o yaml > <kind>_<name>.yaml
    
  2. 手动从配置文件中删除status字段。

  3. 在对象上设置kubectl.kubernetes.io/last-applied-configuration注释

    kubectl replace --save-config -f <kind>_<name>.yaml
    
  4. 更改流程以专门使用kubectl apply来管理对象。

从命令式对象配置迁移到声明式对象配置

  1. 在对象上设置kubectl.kubernetes.io/last-applied-configuration注释

    kubectl replace --save-config -f <kind>_<name>.yaml
    
  2. 更改流程以专门使用kubectl apply来管理对象。

定义控制器选择器和 PodTemplate 标签

建议的方法是定义一个唯一的、不可变的 PodTemplate 标签,该标签仅由控制器选择器使用,没有任何其他语义含义。

示例

selector:
  matchLabels:
      controller-selector: "apps/v1/deployment/nginx"
template:
  metadata:
    labels:
      controller-selector: "apps/v1/deployment/nginx"

下一步

上次修改时间:2023 年 8 月 24 日下午 6:38 PST: 使用 code_sample 短代码代替 code 短代码 (e8b136c3b3)