使用配置文件声明式管理 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: '{...}' 注解设置为每个对象。该注解包含用于创建对象的对象配置文件的内容。
说明
添加-R 标志以递归处理目录。这是一个对象配置文件的示例
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
说明
diff 使用 服务器端 dry-run,需要在 kube-apiserver 上启用此功能。
由于 diff 以 dry-run 模式执行服务器端 apply 请求,因此需要授予 PATCH、CREATE 和 UPDATE 权限。有关详细信息,请参阅 Dry-Run 授权。
使用 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 更新目录中定义的所有对象,即使这些对象已经存在。这种方法可以实现以下目的
- 将配置文件中出现的字段设置为实时配置中。
- 清除从配置文件中删除的实时配置中的字段。
kubectl diff -f <directory>
kubectl apply -f <directory>
说明
添加-R 标志以递归处理目录。这是一个示例配置文件
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.16.1,从nginx:1.14.2。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 和命令式对象配置命令 create 和 replace 不受支持。这是因为 create 和 replace 不会保留 kubectl apply 用于计算更新的 kubectl.kubernetes.io/last-applied-configuration。如何删除对象
有两种方法可以删除由 kubectl apply 管理的对象。
推荐:kubectl delete -f <filename>
手动删除对象使用命令式命令是推荐的方法,因为它更明确地说明了正在删除的内容,并且不太可能导致用户意外删除某些内容
kubectl delete -f <filename>
替代方案:kubectl apply -f <directory> --prune
作为 kubectl delete 的替代方案,您可以使用 kubectl apply 在从本地文件系统中的目录中删除清单后识别要删除的对象。
在 Kubernetes 1.35 中,kubectl apply 中提供了两种修剪模式
- 允许列表修剪:此模式自 kubectl v1.5 以来一直存在,但由于其设计上的可用性、正确性和性能问题,仍然处于 alpha 阶段。ApplySet-based 模式旨在取代它。
- ApplySet 修剪:apply set 是服务器端对象(默认情况下是 Secret),kubectl 可以使用它来准确有效地跟踪跨 apply 操作的集合成员资格。此模式在 kubectl v1.27 中作为 allowlist-based 修剪的替代方案引入为 alpha 版本。
Kubernetes v1.5 [alpha]警告
在使用--prune 与 kubectl apply 在允许列表模式下时要小心。修剪哪些对象取决于 --prune-allowlist、--selector 和 --namespace 标志的值,并依赖于对范围内的对象的动态发现。尤其是在标志值在调用之间发生变化时,这可能导致对象被意外删除或保留。要使用基于允许列表的修剪,请将以下标志添加到您的 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]注意
kubectl apply --prune --applyset 处于 alpha 阶段,后续版本可能会引入不兼容的更改。要使用基于 ApplySet 的剪枝,请将 KUBECTL_APPLYSET=true 环境变量设置为 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> 标签添加到集合中的每个对象,然后再将其发送到服务器。为了提高性能,它还会收集集合包含的资源类型和命名空间列表,并将这些信息作为实时父对象上的注释添加。最后,在应用操作结束时,它会查询 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 注解。这用于识别从配置文件中删除的字段,并且需要从实时配置中清除这些字段。以下是用于计算应删除或设置的字段的步骤
- 计算要删除的字段。这些是存在于
last-applied-configuration中但配置文件中缺失的字段。 - 计算要添加或设置的字段。这些是存在于配置文件中的字段,其值与实时配置不匹配的字段。
这是一个例子。假设这是 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 将执行的合并计算
- 通过读取
last-applied-configuration中的值并将其与配置文件中的值进行比较来计算要删除的字段。无论它们是否出现在last-applied-configuration中,都清除在本地对象配置文件中显式设置为 null 的字段。在此示例中,minReadySeconds出现在last-applied-configuration注解中,但未出现在配置文件中。操作:从实时配置中清除minReadySeconds。 - 通过读取配置文件中的值并将其与实时配置中的值进行比较来计算要设置的字段。在此示例中,配置文件中
image的值与实时配置中的值不匹配。操作:设置实时配置中的image值。 - 将
last-applied-configuration注解设置为与配置文件的值匹配。 - 将 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
# ...
# ...
# ...
# ...
如何合并不同类型的字段
配置文件中的特定字段如何与实时配置合并取决于该字段的类型。存在几种类型的字段
原始类型:string、integer 或 boolean 类型的字段。例如,
image和replicas是原始字段。操作:替换。map,也称为 object:map 类型或包含子字段的复杂类型。例如,
labels、annotations、spec和metadata都是 map。操作:合并元素或子字段。list:包含可以为原始类型或 map 的项目列表的字段。例如,
containers、ports和args是列表。操作:不一。
当 kubectl apply 更新 map 或 list 字段时,通常不会替换整个字段,而是更新各个子元素。例如,在合并 Deployment 上的 spec 时,不会替换整个 spec。而是比较 spec 的子字段,例如 replicas,并进行合并。
合并原始字段的更改
原始字段被替换或清除。
说明
- 用于“不适用”,因为该值未使用。| 对象配置文件中的字段 | 实时对象配置中的字段 | last-applied-configuration 中的字段 | 操作 |
|---|---|---|---|
| 是 | 是 | - | 将实时配置设置为配置文件值。 |
| 是 | 否 | - | 将实时配置设置为本地配置。 |
| 否 | - | 是 | 从实时配置中清除。 |
| 否 | - | 否 | 不执行任何操作。保留实时值。 |
合并 map 字段的更改
表示 map 的字段通过比较 map 的每个子字段或元素来合并
说明
- 用于“不适用”,因为该值未使用。| 对象配置文件中的键 | 实时对象配置中的键 | last-applied-configuration 中的字段 | 操作 |
|---|---|---|---|
| 是 | 是 | - | 比较子字段值。 |
| 是 | 否 | - | 将实时配置设置为本地配置。 |
| 否 | - | 是 | 从实时配置中删除。 |
| 否 | - | 否 | 不执行任何操作。保留实时值。 |
合并 list 类型的字段的更改
合并 list 的更改使用以下三种策略之一
- 如果其所有元素都是原始类型,则替换 list。
- 合并复杂元素的 list 中的各个元素。
- 合并原始元素的 list。
为每个字段选择策略。
如果其所有元素都是原始类型,则替换 list
将 list 与原始字段相同对待。替换或删除整个 list。这保留了顺序。
示例:使用 kubectl apply 更新 Pod 中 Container 的 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"]
说明:合并使用了配置文件值作为新的 list 值。
合并复杂元素的 list
将 list 视为 map,并将每个元素的特定字段视为该元素的键。添加、删除或更新单个元素。这不会保留顺序。
此合并策略在每个字段上使用一个特殊标签,称为 patchMergeKey。patchMergeKey 在 Kubernetes 源代码中为每个字段定义:types.go 在合并 map 的 list 时,为给定元素指定的 patchMergeKey 字段用作该元素的键。
示例:使用 kubectl apply 更新 PodSpec 的 containers 字段。这会将 list 合并为 if 它是以 name 作为键的 map。
# 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-c”的容器。
- 由于 last-applied-configuration 中没有名为“nginx-helper-d”的元素,因此保留了名为“nginx-helper-d”的容器。
合并原始元素的 list
从 Kubernetes 1.5 开始,不支持合并原始元素的 list。
默认字段值
如果对象创建时未指定某些字段,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
说明
- 用户创建 Deployment 时未定义
strategy.type。 - 服务器将
strategy.type默认设置为RollingUpdate并默认化strategy.rollingUpdate的值。 - 用户将
strategy.type更改为Recreate。strategy.rollingUpdate的值仍然保持其默认值,尽管服务器期望它们被清除。如果strategy.rollingUpdate的值最初在配置文件中定义,那么会更清楚地表明它们需要被删除。 - 应用失败,因为
strategy.rollingUpdate未被清除。strategy.rollingupdate字段不能在strategy.type为Recreate时被定义。
建议:这些字段应在对象配置文件中显式定义
- 工作负载(例如 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 对象应使用一种方法进行管理。从一种方法切换到另一种方法是可能的,但需要手动操作。
说明
使用声明式管理进行命令式删除是可以的。从命令式命令管理迁移到声明式对象配置
从命令式命令管理迁移到声明式对象配置涉及几个手动步骤
将实时对象导出到本地配置文件
kubectl get <kind>/<name> -o yaml > <kind>_<name>.yaml手动从配置文件中删除
status字段。说明
此步骤是可选的,因为kubectl apply即使status字段存在于配置文件中,也不会更新该字段。设置对象上的
kubectl.kubernetes.io/last-applied-configuration注解kubectl replace --save-config -f <kind>_<name>.yaml更改流程以专门使用
kubectl apply来管理对象。
从命令式对象配置迁移到声明式对象配置
设置对象上的
kubectl.kubernetes.io/last-applied-configuration注解kubectl replace --save-config -f <kind>_<name>.yaml更改流程以专门使用
kubectl apply来管理对象。
定义控制器选择器和 PodTemplate 标签
警告
强烈建议不要更新控制器上的选择器。推荐的方法是定义单个、不可变的 PodTemplate 标签,该标签仅由控制器选择器使用,没有其他语义含义。
示例
selector:
matchLabels:
controller-selector: "apps/v1/deployment/nginx"
template:
metadata:
labels:
controller-selector: "apps/v1/deployment/nginx"