使用配置文件声明式管理 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
在空运行模式下执行服务器端应用请求,因此需要授予 PATCH
、CREATE
和 UPDATE
权限。详细信息请参阅空运行授权。
使用 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.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
与命令式对象配置命令 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.33 中,kubectl apply 中有两种可用的修剪(pruning)模式:
- 基于允许列表(Allowlist-based)的修剪:此模式自 kubectl v1.5 起就已存在,但由于其设计存在可用性、正确性和性能问题,目前仍处于 Alpha 阶段。基于 ApplySet 的模式旨在取代它。
- 基于 ApplySet 的修剪:一个 apply set 是一个服务器端对象(默认为 Secret),kubectl 可以使用它来准确高效地跟踪跨 apply 操作的集合成员关系。此模式在 kubectl v1.27 中作为允许列表修剪的替代方案引入,目前处于 Alpha 阶段。
Kubernetes v1.5 [alpha]
警告
在允许列表模式下使用带有--prune
标志的 kubectl apply
时请注意。哪些对象会被修剪取决于 --prune-allowlist
、--selector
和 --namespace
标志的值,并且依赖于动态发现范围内的对象。特别是如果在两次调用之间更改了标志值,这可能导致对象被意外删除或保留。要使用基于允许列表的修剪,请在你的 kubectl apply
调用中添加以下标志:
--prune
:删除先前应用但不在当前调用所传递集合中的对象。--prune-allowlist
:要考虑进行修剪的 Group-Version-Kind (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>
警告
带有 prune 的 apply 命令只能针对包含对象清单的根目录运行。如果针对子目录运行,则可能导致先前已应用、具有给定标签(如果指定)并且未在子目录中出现的对象被意外删除。Kubernetes v1.27 [alpha]
注意
kubectl apply --prune --applyset
处于 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 父对象。要启用此功能,请使用以下标签标记定义你想要使用的资源的 Custom Resource Definition (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 名称。
如何查看对象
你可以使用带 -o yaml
标志的 kubectl get
命令来查看活动对象的配置:
kubectl get -f <filename|url> -o yaml
Apply 如何计算差异和合并更改
注意
一个 patch 是一个更新操作,其作用范围是对象的特定字段而不是整个对象。这使得仅更新对象上的特定字段集成为可能,而无需先读取对象。当 kubectl apply
更新对象的活动配置时,它通过向 API 服务器发送 patch 请求来实现。该 patch 定义了针对活动对象配置特定字段的更新。kubectl apply
命令使用配置文件、活动配置以及存储在活动配置中的 last-applied-configuration
注解来计算此 patch 请求。
合并 Patch 计算
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 服务器的 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 的字段。例如,
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 的每个子字段或元素来合并:
说明
-
用于表示“不适用”,因为该值未被使用。对象配置文件中的 Key | 活动对象配置中的 Key | last-applied-configuration 中的字段 | 操作 |
---|---|---|---|
是 | 是 | - | 比较子字段值。 |
是 | 否 | - | 将活动字段值设置为本地配置。 |
否 | - | 是 | 从活动配置中删除。 |
否 | - | 否 | 不做任何事。保留活动字段值。 |
合并 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"]
解释:合并使用配置文件中的值作为新的列表值。
合并复杂元素列表中的单个元素
将列表视为 map,并将每个元素的特定字段视为 Key。添加、删除或更新单个元素。这不保留元素的顺序。
这种合并策略在每个字段上使用一个称为 patchMergeKey
的特殊标签。patchMergeKey
在 Kubernetes 源代码中的每个字段中定义:types.go 在合并 map 列表时,指定为给定元素的 patchMergeKey
字段用作该元素的 map Key。
示例:使用 kubectl apply
更新 PodSpec 的 containers
字段。这会合并列表,就像它是一个 map,其中每个元素都以 name
作为 Key。
# 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" 的容器被保留了,因为 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
# ...
在 patch 请求中,除非在 patch 请求中明确清除,否则不会重新设置默认字段值。这可能导致基于其他字段值设置默认值的字段出现意外行为。当其他字段后来发生更改时,从它们推导出的默认值将不会更新,除非被明确清除。
因此,建议在配置文件中明确定义服务器默认的某些字段,即使期望的值与服务器默认值相同。这样更容易识别不会被服务器重新默认的冲突值。
示例
# 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
未被清除。使用Recreate
的strategy.type
不能定义strategy.rollingupdate
字段。
建议:这些字段应在对象配置文件中显式定义
- 工作负载(如 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
字段。说明
此步骤是可选的,因为即使status
字段在配置文件中存在,kubectl apply
也不会更新它。在对象上设置
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"