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

可以通过将多个对象配置文件存储在目录中,并使用 kubectl apply 根据需要递归地创建和更新这些对象来创建、更新和删除 Kubernetes 对象。此方法会保留对活动对象所做的写入,而不会将更改合并回对象配置文件。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.32 中,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: 要考虑修剪的 group-version-kinds (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 服务器发送 patch 请求来执行此操作。patch 定义了作用域限定于实时对象配置的特定字段的更新。kubectl apply 命令使用配置文件、实时配置和存储在实时配置中的 last-applied-configuration 注释来计算此 patch 请求。

合并 patch 计算

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 读取值并将它们与配置文件中的值进行比较来计算要删除的字段。无论它们是否出现在 last-applied-configuration 中,都要清除在本地对象配置文件中显式设置为 null 的字段。在此示例中,minReadySeconds 出现在 last-applied-configuration 注释中,但未出现在配置文件中。操作: 从实时配置中清除 minReadySeconds
  2. 通过从配置文件中读取值并将它们与实时配置中的值进行比较来计算要设置的字段。在此示例中,配置文件中的 image 值与实时配置中的值不匹配。操作: 在实时配置中设置 image 的值。
  3. last-applied-configuration 注释设置为与配置文件的值匹配。
  4. 将 1、2、3 的结果合并到发送给 API 服务器的单个 patch 请求中。

以下是合并结果的实时配置

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
        # ...
      # ...
    # ...
  # ...

如何合并不同类型的字段

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

  • 基本类型:类型为 string、integer 或 boolean 的字段。例如,imagereplicas 是基本类型字段。操作: 替换。

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

  • list:包含可以是基本类型或 map 的项列表的字段。例如,containersportsargs 是列表。操作: 各不相同。

kubectl apply 更新 map 或 list 字段时,它通常不会替换整个字段,而是更新各个子元素。例如,在合并 Deployment 上的 spec 时,不会替换整个 spec。相反,会比较和合并 spec 的子字段,例如 replicas

合并对基本类型字段的更改

基本类型字段将被替换或清除。

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

合并对 map 字段的更改

表示 map 的字段通过比较 map 的每个子字段或元素进行合并

对象配置文件中的键实时对象配置中的键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"]

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

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

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

这种合并策略在每个字段上使用一个名为 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 字段值 (name) 在两者中都是相同的。
  • 名为“nginx-helper-c”的容器被添加,因为实时配置中没有出现具有该名称的容器,但在配置文件中出现了一个具有该名称的容器。
  • 名为“nginx-helper-d”的容器被保留,因为在上次应用的配置中没有出现具有该名称的元素。

合并基本元素列表

从 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. 用户创建一个未定义 strategy.type 的 Deployment。
  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:使用 code_sample 短代码而不是 code 短代码 (e8b136c3b3)