Kubernetes API 概念
Kubernetes API 是通过 HTTP 提供的基于资源(RESTful)的程序化接口。它支持通过标准的 HTTP 动词(POST、PUT、PATCH、DELETE、GET)来获取、创建、更新和删除主要资源。
对于某些资源,API 包含额外的子资源,允许进行细粒度授权(例如,Pod 详情和日志获取的单独视图),并且可以接受和提供不同表示形式的那些资源,以提供便利或提高效率。
Kubernetes 支持通过 watch 来高效地通知资源的变更
在 Kubernetes API 中,watch 是一个动词,用于以流的形式跟踪 Kubernetes 对象的变化。它被用于高效地检测变更。
Kubernetes 还提供一致的列表操作,以便 API 客户端能够有效地缓存、跟踪和同步资源的状态。您可以在线查看 API 参考,或者继续阅读以了解 API 的总体情况。
Kubernetes API 术语
Kubernetes 通常利用常用的 RESTful 术语来描述 API 概念
- 资源类型 (resource type) 是在 URL 中使用的名称(
pods
、namespaces
、services
) - 所有资源类型都有一个具体的表示(它们的对象的 schema),称之为 种类 (kind)
- 资源类型实例的列表被称为 集合 (collection)
- 资源类型的单个实例称为 资源 (resource),通常也表示一个 对象 (object)
- 对于某些资源类型,API 包含一个或多个 子资源 (sub-resources),它们以 URI 路径的形式表示在资源下方
大多数 Kubernetes API 资源类型都是对象——它们代表集群上一个具体概念的实例,例如 Pod 或 Namespace。少数 API 资源类型是 虚拟的,因为它们通常表示对对象的操作,而不是对象本身,例如权限检查(使用 POST 方法将包含 SubjectAccessReview
JSON 编码体发送到 subjectaccessreviews
资源),或者 Pod 的 eviction
子资源(用于触发API 发起的驱逐)。
对象名称
除虚拟资源类型外,所有可以通过 API 创建的对象都具有唯一的对象名称,以便实现幂等创建和获取。虚拟资源类型如果不可获取,或者不依赖幂等性,则可能没有唯一的名称。在命名空间内,给定种类 (kind) 的对象在同一时间只能有一个具有给定名称。但是,如果删除该对象,则可以创建同名的新对象。有些对象不是命名空间范围的(例如:节点),因此它们的名称必须在整个集群中是唯一的。
API 动词
几乎所有对象资源类型都支持标准的 HTTP 动词 - GET、POST、PUT、PATCH 和 DELETE。Kubernetes 也使用自己的动词,通常用小写字母书写以区别于 HTTP 动词。
Kubernetes 使用术语 list 来描述返回资源 集合 的操作,以区别于获取单个资源的动作,后者通常称为 get。如果您发送带有 ?watch
查询参数的 HTTP GET 请求,Kubernetes 将此操作称为 watch 而不是 get(更多细节请参阅 有效检测变更)。
对于 PUT 请求,Kubernetes 内部根据现有对象的状态将其归类为 create 或 update。一个 update 与一个 patch 不同;patch 操作的 HTTP 动词是 PATCH。
资源 URI
所有资源类型都属于集群范围 (/apis/GROUP/VERSION/*
) 或命名空间范围 (/apis/GROUP/VERSION/namespaces/NAMESPACE/*
)。命名空间范围的资源类型在命名空间被删除时也会被删除,并且对该资源类型的访问受到命名空间范围的授权检查控制。
注意:核心资源使用 /api
而不是 /apis
,并省略 GROUP 路径段。
示例
/api/v1/namespaces
/api/v1/pods
/api/v1/namespaces/my-namespace/pods
/apis/apps/v1/deployments
/apis/apps/v1/namespaces/my-namespace/deployments
/apis/apps/v1/namespaces/my-namespace/deployments/my-deployment
您也可以访问资源的集合(例如:列出所有节点)。以下路径用于获取集合和资源
集群范围资源
GET /apis/GROUP/VERSION/RESOURCETYPE
- 返回该资源类型的资源集合GET /apis/GROUP/VERSION/RESOURCETYPE/NAME
- 返回该资源类型下名称为 NAME 的资源
命名空间范围资源
GET /apis/GROUP/VERSION/RESOURCETYPE
- 返回所有命名空间中该资源类型的所有实例集合GET /apis/GROUP/VERSION/namespaces/NAMESPACE/RESOURCETYPE
- 返回命名空间 NAMESPACE 中该资源类型的所有实例集合GET /apis/GROUP/VERSION/namespaces/NAMESPACE/RESOURCETYPE/NAME
- 返回命名空间 NAMESPACE 中名称为 NAME 的该资源类型实例
由于命名空间是集群范围的资源类型,您可以使用 GET /api/v1/namespaces
获取所有命名空间的列表(“集合”),使用 GET /api/v1/namespaces/NAME
获取特定命名空间的详情。
- 集群范围子资源:
GET /apis/GROUP/VERSION/RESOURCETYPE/NAME/SUBRESOURCE
- 命名空间范围子资源:
GET /apis/GROUP/VERSION/namespaces/NAMESPACE/RESOURCETYPE/NAME/SUBRESOURCE
每个子资源支持的动词取决于对象本身 - 更多信息请参阅API 参考。目前无法跨多个资源访问子资源 - 如果有此需求,通常会使用新的虚拟资源类型。
HTTP 媒体类型
通过 HTTP,Kubernetes 支持 JSON 和 Protobuf 线格式编码。
默认情况下,Kubernetes 使用JSON 序列化 返回对象,使用 application/json
媒体类型。尽管 JSON 是默认值,客户端可以请求 YAML 格式的响应,或者使用更高效的二进制Protobuf 格式 以在大型规模下获得更好的性能。
Kubernetes API 实现了标准的 HTTP 内容类型协商:在 GET
调用中传递 Accept
头可以请求服务器尝试返回您首选的媒体类型响应。如果您希望在 PUT
或 POST
请求中向服务器发送 Protobuf 格式的对象,您必须相应地设置 Content-Type
请求头。
如果您请求了可用的媒体类型,API 服务器会返回一个带有合适 Content-Type
的响应;如果您请求的媒体类型均不受支持,API 服务器会返回 406 Not acceptable
错误消息。所有内置资源类型都支持 application/json
媒体类型。
JSON 资源编码
Kubernetes API 默认使用 JSON 对 HTTP 消息体进行编码。
例如
列出集群上的所有 Pod,不指定首选格式
GET /api/v1/pods
200 OK Content-Type: application/json … JSON encoded collection of Pods (PodList object)
通过向服务器发送 JSON 来创建 Pod,请求 JSON 响应。
POST /api/v1/namespaces/test/pods Content-Type: application/json Accept: application/json … JSON encoded Pod object
200 OK Content-Type: application/json { "kind": "Pod", "apiVersion": "v1", … }
YAML 资源编码
Kubernetes 还支持 application/yaml
媒体类型用于请求和响应。YAML
可用于定义 Kubernetes 清单和 API 交互。
例如
以 YAML 格式列出集群上的所有 Pod
GET /api/v1/pods Accept: application/yaml
200 OK Content-Type: application/yaml … YAML encoded collection of Pods (PodList object)
通过向服务器发送 YAML 编码的数据来创建 Pod,请求 YAML 响应
POST /api/v1/namespaces/test/pods Content-Type: application/yaml Accept: application/yaml … YAML encoded Pod object
200 OK Content-Type: application/yaml apiVersion: v1 kind: Pod metadata: name: my-pod …
Kubernetes Protobuf 编码
Kubernetes 使用一个信封封装器 (envelope wrapper) 来编码 Protobuf 响应。该封装器以 4 个字节的魔术数字 (magic number) 开头,以帮助识别磁盘或 etcd 中的内容是 Protobuf(而非 JSON)。这 4 个字节的魔术数字数据后面是一个 Protobuf 编码的封装消息,它描述了底层对象的编码和类型。在 Protobuf 封装消息中,内部对象数据使用 Unknown 的 raw
字段记录(更多细节请参阅 IDL)。
例如
以 Protobuf 格式列出集群上的所有 Pod。
GET /api/v1/pods Accept: application/vnd.kubernetes.protobuf
200 OK Content-Type: application/vnd.kubernetes.protobuf … JSON encoded collection of Pods (PodList object)
通过向服务器发送 Protobuf 编码的数据来创建 Pod,但请求 JSON 响应。
POST /api/v1/namespaces/test/pods Content-Type: application/vnd.kubernetes.protobuf Accept: application/json … binary encoded Pod object
200 OK Content-Type: application/json { "kind": "Pod", "apiVersion": "v1", ... }
您可以将这两种技术结合使用,并使用 Kubernetes 的 Protobuf 编码与任何支持它的 API 进行交互,无论是读取还是写入。只有部分 API 资源类型与 Protobuf 兼容。
封装格式为
A four byte magic number prefix:
Bytes 0-3: "k8s\x00" [0x6b, 0x38, 0x73, 0x00]
An encoded Protobuf message with the following IDL:
message Unknown {
// typeMeta should have the string values for "kind" and "apiVersion" as set on the JSON object
optional TypeMeta typeMeta = 1;
// raw will hold the complete serialized object in protobuf. See the protobuf definitions in the client libraries for a given kind.
optional bytes raw = 2;
// contentEncoding is encoding used for the raw data. Unspecified means no encoding.
optional string contentEncoding = 3;
// contentType is the serialization method used to serialize 'raw'. Unspecified means application/vnd.kubernetes.protobuf and is usually
// omitted.
optional string contentType = 4;
}
message TypeMeta {
// apiVersion is the group/version for this type
optional string apiVersion = 1;
// kind is the name of the object schema. A protobuf definition should exist for this object.
optional string kind = 2;
}
注意
接收到application/vnd.kubernetes.protobuf
响应但与预期前缀不匹配的客户端应拒绝该响应,因为未来版本可能需要以不兼容的方式更改序列化格式,并且会通过更改前缀来实现。与 Kubernetes Protobuf 的兼容性
并非所有 API 资源类型都支持 Kubernetes 的 Protobuf 编码;具体来说,Protobuf 不适用于定义为 自定义资源定义 或通过 聚合层 提供的资源。
作为客户端,如果您可能需要处理扩展类型,则应在请求的 Accept
头中指定多个内容类型以支持回退到 JSON。例如
Accept: application/vnd.kubernetes.protobuf, application/json
CBOR 资源编码
Kubernetes v1.32 [alpha]
(默认禁用)启用 CBORServingAndStorage
特性门控 后,所有内置资源类型以及由 自定义资源定义 定义的所有资源的请求和响应体都可以编码为 CBOR 二进制数据格式。如果在单独的聚合 API 服务器中启用了 CBOR,聚合层 也支持 CBOR。
当请求体包含单个 CBOR 编码数据项 时,客户端应在 Content-Type
HTTP 请求头中指明 IANA 媒体类型 application/cbor
;当准备好接受响应中的 CBOR 编码数据项时,应在 Accept
HTTP 请求头中指明。当响应体包含 CBOR 编码对象时,API 服务器将在 Content-Type
HTTP 响应头中使用 application/cbor
。
如果 API 服务器使用 CBOR 对监听请求的响应进行编码,响应体将是一个 CBOR 序列,并且 Content-Type
HTTP 响应头将使用 IANA 媒体类型 application/cbor-seq
。序列中的每个条目(如果存在)是一个单独的 CBOR 编码的监听事件。
除了现有的用于 YAML 编码的服务端应用配置的 application/apply-patch+yaml
媒体类型外,启用了 CBOR 的 API 服务器将接受用于 CBOR 编码的服务端应用配置的 application/apply-patch+cbor
媒体类型。目前不支持与 application/json-patch+json
、application/merge-patch+json
或 application/strategic-merge-patch+json
对应的 CBOR 格式。
有效检测变更
Kubernetes API 允许客户端对对象或集合进行初始请求,然后跟踪自该初始请求以来的变更:这是一个 watch。客户端可以发送一个 list 或一个 get,然后发起后续的 watch 请求。
为了实现这种变更跟踪,每个 Kubernetes 对象都有一个 resourceVersion
字段,表示该资源在底层持久化存储中的版本。当获取资源集合(无论是命名空间范围还是集群范围)时,API 服务器的响应包含一个 resourceVersion
值。客户端可以使用该 resourceVersion
来向 API 服务器发起一个 watch。
当您发送 watch 请求时,API 服务器会响应一个变更流。这些变更逐条列出在您作为 watch 请求参数指定的 resourceVersion
之后发生的各种操作(例如 create、delete 和 update)的结果。整个 watch 机制允许客户端获取当前状态,然后订阅后续变更,而不会遗漏任何事件。
如果客户端的 watch 断开连接,该客户端可以从上次返回的 resourceVersion
开始新的 watch;客户端也可以执行新的 get / list 请求并重新开始。更多细节请参阅资源版本语义。
例如
列出给定命名空间中的所有 Pod。
GET /api/v1/namespaces/test/pods --- 200 OK Content-Type: application/json { "kind": "PodList", "apiVersion": "v1", "metadata": {"resourceVersion":"10245"}, "items": [...] }
从资源版本 10245 开始,接收影响 test 命名空间中 Pods 的任何 API 操作(例如 create、delete、patch 或 update)的通知。每个变更通知都是一个 JSON 文档。HTTP 响应体(以
application/json
提供)包含一系列 JSON 文档。GET /api/v1/namespaces/test/pods?watch=1&resourceVersion=10245 --- 200 OK Transfer-Encoding: chunked Content-Type: application/json { "type": "ADDED", "object": {"kind": "Pod", "apiVersion": "v1", "metadata": {"resourceVersion": "10596", ...}, ...} } { "type": "MODIFIED", "object": {"kind": "Pod", "apiVersion": "v1", "metadata": {"resourceVersion": "11020", ...}, ...} } ...
给定的 Kubernetes 服务器只会保留有限时间的变更历史记录。默认情况下,使用 etcd 3 的集群保留过去 5 分钟内的变更。当由于该资源的历史版本不可用而导致请求的 watch 操作失败时,客户端必须通过识别状态码 410 Gone
、清除本地缓存、执行新的 get 或 list 操作并从返回的 resourceVersion
开始 watch 来处理这种情况。
对于订阅集合,Kubernetes 客户端库通常会为此 list 然后 watch 的逻辑提供某种标准工具。(在 Go 客户端库中,这被称为 Reflector
,位于 k8s.io/client-go/tools/cache
包中。)
Watch 书签
为了减轻短历史窗口的影响,Kubernetes API 提供了一个名为 BOOKMARK
的监听事件。这是一种特殊类型的事件,用于标记客户端请求的所有变更都已发送到给定的 resourceVersion
。表示 BOOKMARK
事件的文档类型与请求的类型相同,但只包含 .metadata.resourceVersion
字段。例如
GET /api/v1/namespaces/test/pods?watch=1&resourceVersion=10245&allowWatchBookmarks=true
---
200 OK
Transfer-Encoding: chunked
Content-Type: application/json
{
"type": "ADDED",
"object": {"kind": "Pod", "apiVersion": "v1", "metadata": {"resourceVersion": "10596", ...}, ...}
}
...
{
"type": "BOOKMARK",
"object": {"kind": "Pod", "apiVersion": "v1", "metadata": {"resourceVersion": "12746"} }
}
作为客户端,您可以通过将 allowWatchBookmarks=true
查询参数设置为 watch 请求来请求 BOOKMARK
事件,但您不应假定书签会以特定间隔返回,客户端也无法假定 API 服务器会发送任何 BOOKMARK
事件,即使已请求。
流式列表
Kubernetes v1.33 [beta]
(默认禁用)在大型集群上,获取某些资源类型的集合可能会导致资源使用量(主要是内存)显著增加。为了减轻影响并简化 list + watch 模式的用户体验,Kubernetes v1.32 将允许将初始状态(以前通过 list 请求获取)作为 watch 请求的一部分进行请求的功能提升到 Beta 阶段。
在客户端,可以通过在 watch 请求中将 sendInitialEvents=true
指定为查询字符串参数来请求初始状态。如果设置,API 服务器将以合成的初始化事件(类型为 ADDED
)开始监听流,以构建所有现有对象的完整状态,随后是一个 书签事件(如果通过 allowWatchBookmarks=true
选项请求)。书签事件包含与之同步的资源版本。发送书签事件后,API 服务器继续处理,就像处理任何其他 watch 请求一样。
当您在查询字符串中设置 sendInitialEvents=true
时,Kubernetes 还要求您将 resourceVersionMatch
设置为 NotOlderThan
值。如果您在查询字符串中提供了 resourceVersion
但未提供值或根本未提供,则将其解释为请求 一致性读取;当状态至少同步到请求开始处理时的一致性读取时刻时,会发送书签事件。如果您指定了 resourceVersion
(在查询字符串中),则当状态至少同步到所提供的资源版本时,会发送书签事件。
示例
例如:您想监听一个 Pods 集合。对于该集合,当前资源版本是 10245,并且有两个 Pod:foo
和 bar
。那么发送以下请求(通过设置空的资源版本 resourceVersion=
显式请求 一致性读取)可能会导致以下事件序列
GET /api/v1/namespaces/test/pods?watch=1&sendInitialEvents=true&allowWatchBookmarks=true&resourceVersion=&resourceVersionMatch=NotOlderThan
---
200 OK
Transfer-Encoding: chunked
Content-Type: application/json
{
"type": "ADDED",
"object": {"kind": "Pod", "apiVersion": "v1", "metadata": {"resourceVersion": "8467", "name": "foo"}, ...}
}
{
"type": "ADDED",
"object": {"kind": "Pod", "apiVersion": "v1", "metadata": {"resourceVersion": "5726", "name": "bar"}, ...}
}
{
"type": "BOOKMARK",
"object": {"kind": "Pod", "apiVersion": "v1", "metadata": {"resourceVersion": "10245"} }
}
...
<followed by regular watch stream starting from resourceVersion="10245">
响应压缩
Kubernetes v1.16 [beta]
(默认启用)APIResponseCompression
是一个选项,允许 API 服务器压缩 get 和 list 请求的响应,从而减少网络带宽并提高大规模集群的性能。自 Kubernetes 1.16 起默认启用,可以通过在 API 服务器的 --feature-gates
标志中包含 APIResponseCompression=false
来禁用。
API 响应压缩可以显著减小响应大小,特别是对于大型资源或 集合。例如,Pod 的 list 请求可能会返回数百 KB 甚至几 MB 的数据,具体取决于 Pod 的数量及其属性。通过压缩响应,可以节省网络带宽并降低延迟。
为了验证 APIResponseCompression
是否工作正常,您可以向 API 服务器发送带有 Accept-Encoding
头部的 get 或 list 请求,并检查响应大小和头部。例如
GET /api/v1/pods
Accept-Encoding: gzip
---
200 OK
Content-Type: application/json
content-encoding: gzip
...
content-encoding
头部指示响应已使用 gzip
进行压缩。
分块获取大型结果集
Kubernetes v1.29 [stable]
(默认启用)在大型集群上,获取某些资源类型的集合可能会导致非常大的响应,这会影响服务器和客户端。例如,一个集群可能有成千上万个 Pod,每个 Pod 大约相当于 2 KiB 的编码 JSON。获取所有命名空间中的所有 Pod 可能会导致非常大的响应(10-20MB),并消耗大量服务器资源。
Kubernetes API 服务器支持将单个大型集合请求拆分成许多较小的 分块 (chunks),同时保持总请求的一致性。每个分块可以顺序返回,这既减少了请求的总大小,又允许面向用户的客户端逐步显示结果以提高响应速度。
您可以请求 API 服务器通过分页(Kubernetes 称之为 块/分块)来处理单个集合的 list 请求。要分块获取单个集合,在针对集合的请求中支持两个查询参数 limit
和 continue
,并且在所有 list 操作的集合的 metadata
字段中返回一个 continue
响应字段。客户端应使用 limit
指定每个块中希望接收的最大结果数,服务器将在结果中返回最多 limit
个资源,并且如果集合中有更多资源,则会包含一个 continue
值。
作为 API 客户端,您可以在下一个请求中将此 continue
值传递给 API 服务器,以指示服务器返回下一页(块)结果。通过持续请求直到服务器返回空的 continue
值,您可以检索整个集合。
就像 watch 操作一样,continue
令牌会在短时间后(默认 5 分钟)过期,如果无法返回更多结果,则会返回 410 Gone
。在这种情况下,客户端需要重新开始,或者省略 limit
参数。
例如,如果集群上有 1,253 个 Pod,并且您希望每次接收 500 个 Pod 的块,则按如下方式请求这些块
列出集群上的所有 Pod,每次最多获取 500 个 Pod。
GET /api/v1/pods?limit=500 --- 200 OK Content-Type: application/json { "kind": "PodList", "apiVersion": "v1", "metadata": { "resourceVersion":"10245", "continue": "ENCODED_CONTINUE_TOKEN", "remainingItemCount": 753, ... }, "items": [...] // returns pods 1-500 }
继续上一次调用,获取下一组 500 个 Pod。
GET /api/v1/pods?limit=500&continue=ENCODED_CONTINUE_TOKEN --- 200 OK Content-Type: application/json { "kind": "PodList", "apiVersion": "v1", "metadata": { "resourceVersion":"10245", "continue": "ENCODED_CONTINUE_TOKEN_2", "remainingItemCount": 253, ... }, "items": [...] // returns pods 501-1000 }
继续上一次调用,获取最后 253 个 Pod。
GET /api/v1/pods?limit=500&continue=ENCODED_CONTINUE_TOKEN_2 --- 200 OK Content-Type: application/json { "kind": "PodList", "apiVersion": "v1", "metadata": { "resourceVersion":"10245", "continue": "", // continue token is empty because we have reached the end of the list ... }, "items": [...] // returns pods 1001-1253 }
注意,集合的 resourceVersion
在每个请求中保持不变,这表明服务器正在向您展示 Pod 的一致性快照。在版本 10245
之后创建、更新或删除的 Pod 将不会显示,除非您发送不带 continue
令牌的单独 list 请求。这允许您将大型请求分解为较小的块,然后在完整集合上执行 watch 操作而不会遗漏任何更新。
remainingItemCount
是集合中未包含在本次响应中的后续项目数量。如果 list 请求包含 标签 或 字段 选择器,则剩余项目数量未知,API 服务器在其响应中不包含 remainingItemCount
字段。如果 list 已完成(因为它没有分块,或者这是最后一个块),则没有更多剩余项目,API 服务器在其响应中不包含 remainingItemCount
字段。remainingItemCount
的预期用途是估计集合的大小。
集合
在 Kubernetes 术语中,您从 list 请求获得的响应是一个 集合。然而,Kubernetes 为不同类型资源的集合定义了具体的种类 (kinds)。集合的种类名称是资源种类的名称后加上 List
。
当您查询 API 的特定类型时,该查询返回的所有项都属于该类型。例如,当您 list Service 时,集合响应的 kind
被设置为 ServiceList
;该集合中的每个项都表示一个单个 Service。例如
GET /api/v1/services
{
"kind": "ServiceList",
"apiVersion": "v1",
"metadata": {
"resourceVersion": "2947301"
},
"items": [
{
"metadata": {
"name": "kubernetes",
"namespace": "default",
...
"metadata": {
"name": "kube-dns",
"namespace": "kube-system",
...
Kubernetes API 中定义了数十种集合类型(例如 PodList
、ServiceList
和 NodeList
)。您可以从 Kubernetes API 文档中获取每种集合类型的更多信息。
某些工具,例如 kubectl
,对 Kubernetes 集合机制的表示与 Kubernetes API 本身略有不同。由于 kubectl
的输出可能包含多个 API 级别 list 操作的响应,kubectl
使用 kind: List
表示项目列表。例如
kubectl get services -A -o yaml
apiVersion: v1
kind: List
metadata:
resourceVersion: ""
selfLink: ""
items:
- apiVersion: v1
kind: Service
metadata:
creationTimestamp: "2021-06-03T14:54:12Z"
labels:
component: apiserver
provider: kubernetes
name: kubernetes
namespace: default
...
- apiVersion: v1
kind: Service
metadata:
annotations:
prometheus.io/port: "9153"
prometheus.io/scrape: "true"
creationTimestamp: "2021-06-03T14:54:14Z"
labels:
k8s-app: kube-dns
kubernetes.io/cluster-service: "true"
kubernetes.io/name: CoreDNS
name: kube-dns
namespace: kube-system
注意
请记住,Kubernetes API 中没有名为 List
的 kind
。
kind: List
是一个客户端内部实现细节,用于处理可能包含不同种类对象的集合。避免在自动化或其他代码中依赖 kind: List
。
以表格形式接收资源
当您运行 kubectl get
时,默认输出格式是特定资源类型的一个或多个实例的简单表格表示形式。过去,客户端需要复制 kubectl
中实现的表格和描述输出才能执行简单的对象列表操作。这种方法的一些限制包括处理某些对象时逻辑复杂。此外,API 聚合或第三方资源提供的类型在编译时是未知的。这意味着对于客户端无法识别的类型,必须有通用的实现。
为了避免上述潜在的限制,客户端可以请求对象的 表格 (Table) 表示形式,将打印的具体细节委托给服务器。Kubernetes API 实现了标准的 HTTP 内容类型协商:在 GET
调用中传递包含值 application/json;as=Table;g=meta.k8s.io;v=v1
的 Accept
头部,将请求服务器以 Table 内容类型返回对象。
例如,以 Table 格式列出集群上的所有 Pod。
GET /api/v1/pods
Accept: application/json;as=Table;g=meta.k8s.io;v=v1
---
200 OK
Content-Type: application/json
{
"kind": "Table",
"apiVersion": "meta.k8s.io/v1",
...
"columnDefinitions": [
...
]
}
对于控制平面不知道其自定义 Table 定义的 API 资源类型,API 服务器将返回一个默认的 Table 响应,该响应包含资源的 name
和 creationTimestamp
字段。
GET /apis/crd.example.com/v1alpha1/namespaces/default/resources
---
200 OK
Content-Type: application/json
...
{
"kind": "Table",
"apiVersion": "meta.k8s.io/v1",
...
"columnDefinitions": [
{
"name": "Name",
"type": "string",
...
},
{
"name": "Created At",
"type": "date",
...
}
]
}
并非所有 API 资源类型都支持 Table 响应;例如,自定义资源定义 可能未定义字段到表格的映射,而扩展核心 Kubernetes API 的 APIService 可能根本不提供 Table 响应。如果您正在实现一个使用 Table 信息且必须兼容所有资源类型(包括扩展)的客户端,您应该在 Accept
头部指定多个内容类型来发起请求。例如
Accept: application/json;as=Table;g=meta.k8s.io;v=v1, application/json
资源删除
当您 delete 资源时,该过程分两个阶段进行。
- 终结
- 移除
{
"kind": "ConfigMap",
"apiVersion": "v1",
"metadata": {
"finalizers": ["url.io/neat-finalization", "other-url.io/my-finalizer"],
"deletionTimestamp": nil,
}
}
当客户端首次发送 delete 请求以移除资源时,.metadata.deletionTimestamp
被设置为当前时间。一旦 .metadata.deletionTimestamp
被设置,依赖于终结器 (finalizers) 的外部控制器可以在任何时间、以任何顺序开始执行它们的清理工作。
终结器之间的顺序 不 被强制执行,因为这会引入显著的 .metadata.finalizers
阻塞风险。
.metadata.finalizers
字段是共享的:任何有权限的参与者都可以对其重新排序。如果按照列表中的顺序处理终结器,则可能导致以下情况:列表中第一个终结器负责的组件正在等待列表后面终结器负责的组件产生的某个信号(字段值、外部系统等),从而导致死锁。
不强制执行顺序,终结器可以自行安排顺序,并且不受列表中顺序变化的影响。
一旦最后一个终结器被移除,资源就会被从 etcd 中实际删除。
强制删除
Kubernetes v1.32 [alpha]
(默认禁用)注意
如果被强制删除的资源依赖于正常删除流程,则此操作可能会破坏与该资源相关的工作负载,因此可能导致集群中断的后果。通过启用删除选项 ignoreStoreReadErrorWithClusterBreakingPotential
,用户可以对无法解密/损坏的资源执行不安全的强制 delete 操作。此选项由 ALPHA 特性门控制,默认处于禁用状态。要使用此选项,集群操作员必须通过设置命令行选项 --feature-gates=AllowUnsafeMalformedObjectDeletion=true
来启用此特性。
注意
执行强制 delete 操作的用户必须拥有对给定资源执行 delete 和 unsafe-delete-ignore-read-errors 动词操作的权限。资源被视为损坏的情况包括,由于以下原因无法从存储中成功检索到它:
- 转换错误(例如:解密失败),或
- 对象解码失败。
API 服务器首先尝试正常删除,如果由于*资源损坏*错误而失败,则会触发强制删除。强制 delete 操作是不安全的,因为它会忽略 finalizer 约束并跳过前置条件检查。
此选项的默认值为 false
,这保持了向后兼容性。对于将 ignoreStoreReadErrorWithClusterBreakingPotential
设置为 true
的 delete 请求,字段 dryRun
、gracePeriodSeconds
、orphanDependents
、preconditions
和 propagationPolicy
必须保持未设置状态。
注意
如果用户对原本可读的资源发出将ignoreStoreReadErrorWithClusterBreakingPotential
设置为 true
的 delete 请求,API 服务器将终止该请求并返回错误。单一资源 API
Kubernetes API 动词 get、create、update、patch、delete 和 proxy 仅支持单一资源。这些支持单一资源的动词不支持在有序或无序列表或事务中一起提交多个资源。
当客户端(包括 kubectl)操作一组资源时,客户端会发出一系列单一资源 API 请求,然后在需要时汇总响应。
相比之下,Kubernetes API 动词 list 和 watch 允许获取多个资源,而 deletecollection 允许删除多个资源。
字段验证
Kubernetes 总是会验证字段的类型。例如,如果 API 中的一个字段定义为数字,您就不能将该字段设置为文本值。如果一个字段定义为字符串数组,则只能提供一个数组。有些字段可以省略,其他字段是必需的。从 API 请求中省略必需字段会导致错误。
如果您发出带有额外字段的请求,即集群控制平面无法识别的字段,则 API 服务器的行为会更加复杂。
默认情况下,API 服务器会从收到的输入中(例如,PUT
请求的 JSON 请求体)丢弃它不识别的字段。
在以下两种情况下,API 服务器会丢弃您在 HTTP 请求中提供的字段。
这些情况是:
- 字段未被识别,因为它不在资源的 OpenAPI schema 中。(一个例外是 CRD,如果它们通过
x-kubernetes-preserve-unknown-fields
明确选择不修剪未知字段)。 - 字段在对象中重复出现。
未识别或重复字段的验证
Kubernetes v1.27 [稳定]
(默认启用: true)从 1.25 版本起,当您使用可以提交数据(POST
、PUT
和 PATCH
)的 HTTP 动词时,对象中的未识别或重复字段会通过服务器端的验证被检测到。可能的验证级别有 Ignore
、Warn
(默认)和 Strict
。
Ignore
- API 服务器成功处理请求,就像没有设置错误字段一样,丢弃所有未知和重复字段,并且不给出任何指示。
Warn
- (默认)API 服务器成功处理请求,并向客户端报告警告。警告通过
Warning:
响应头发送,为每个未知或重复字段添加一个警告项。有关警告和 Kubernetes API 的更多信息,请参阅博客文章 Warning: Helpful Warnings Ahead。 Strict
- 当 API 服务器检测到任何未知或重复字段时,它会以 400 Bad Request 错误拒绝请求。API 服务器的响应消息会列出它检测到的所有未知或重复字段。
字段验证级别由 fieldValidation
查询参数设置。
注意
如果您提交的请求指定了未识别的字段,并且此请求因其他原因也无效(例如,请求为已知字段提供了字符串值,而 API 期望的是整数),则 API 服务器会以 400 Bad Request 错误响应,但不会提供关于未知或重复字段的任何信息(只会说明它首先遇到了哪个致命错误)。
在这种情况下,无论您请求了哪种字段验证级别,您都会收到错误响应。
向服务器提交请求的工具(例如 kubectl
)可能会设置自己的默认值,这些默认值与 API 服务器默认使用的 Warn
验证级别不同。
kubectl
工具使用 --validate
标志来设置字段验证级别。它接受 ignore
、warn
和 strict
值,同时也接受 true
(等同于 strict
)和 false
(等同于 ignore
)。kubectl 的默认验证设置为 --validate=true
,这意味着严格的服务器端字段验证。
当 kubectl 无法连接到支持字段验证的 API 服务器(即 Kubernetes 1.27 之前的 API 服务器)时,它将回退到使用客户端验证。客户端验证将在未来版本的 kubectl 中完全移除。
注意
在 Kubernetes 1.25 之前,kubectl --validate
作为布尔标志用于开启或关闭客户端验证。模拟运行 (Dry-run)
Kubernetes v1.19 [稳定]
(默认启用: true)当您使用可以修改资源(POST
、PUT
、PATCH
和 DELETE
)的 HTTP 动词时,您可以以*模拟运行*模式提交请求。模拟运行模式有助于通过典型的请求阶段(admission chain、验证、合并冲突)评估请求,直到将对象持久化到存储。请求的响应体应尽可能接近非模拟运行的响应。Kubernetes 保证模拟运行请求不会持久化到存储中,也不会产生任何其他副作用。
发起模拟运行请求
通过设置 dryRun
查询参数来触发模拟运行。此参数是一个字符串,作为一个枚举工作,唯一接受的值是:
- [未设置值]
- 允许副作用。您可以使用查询字符串如
?dryRun
或?dryRun&pretty=true
来请求此模式。响应将是原本会被持久化的最终对象,如果请求无法完成,则返回错误。 All
- 除了阻止副作用的最终存储阶段外,每个阶段都正常运行。
当您设置 ?dryRun=All
时,所有相关的 admission controller 都会运行,校验 admission controller 会检查变异后的请求,PATCH
会执行合并,字段会被赋予默认值,并进行 schema 验证。这些更改不会持久化到底层存储,但原本会被持久化的最终对象仍然会返回给用户,同时带有正常的状态码。
如果请求的非模拟运行版本会触发具有副作用的 admission controller,则该请求将失败,以避免不必要的副作用风险。所有内置的 admission control 插件都支持模拟运行。此外,admission webhook 可以在其配置对象中声明它们不具有副作用,方法是将其 sideEffects
字段设置为 None
。
注意
如果一个 webhook 确实具有副作用,则sideEffects
字段应设置为 "NoneOnDryRun"。这种更改是合适的,前提是该 webhook 也被修改以理解 AdmissionReview 中的 DryRun
字段,并阻止对任何标记为模拟运行的请求产生副作用。以下是使用 ?dryRun=All
的模拟运行请求示例:
POST /api/v1/namespaces/test/pods?dryRun=All
Content-Type: application/json
Accept: application/json
响应看起来与非模拟运行请求相同,但某些生成字段的值可能有所不同。
生成的值
对象的某些值通常在对象持久化之前生成。重要的是不要依赖于模拟运行请求设置的这些字段的值,因为这些值在模拟运行模式下很可能与实际请求发生时不同。其中一些字段包括:
name
:如果设置了generateName
,name
将具有唯一的随机名称creationTimestamp
/deletionTimestamp
:记录创建/删除时间UID
:唯一标识对象,并且是随机生成(非确定性)的resourceVersion
:跟踪对象的持久化版本- 由变异 admission controller 设置的任何字段
- 对于
Service
资源:kube-apiserver 分配给 Service 对象的端口或 IP 地址
模拟运行授权
模拟运行和非模拟运行请求的授权是相同的。因此,要发起模拟运行请求,您必须获得发起非模拟运行请求的授权。
例如,要对 Deployment 执行模拟运行 patch 操作,您必须获得执行该 patch 操作的授权。以下是 Kubernetes RBAC 中允许修补 Deployment 的规则示例:
rules:
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["patch"]
请参阅授权概览。
更新现有资源
Kubernetes 提供了多种方式来更新现有对象。您可以阅读选择更新机制以了解哪种方法最适合您的使用场景。
您可以使用 HTTP PUT 覆盖(更新)现有资源,例如 ConfigMap。对于 PUT 请求,客户端有责任指定 resourceVersion
(从正在更新的对象中获取)。Kubernetes 使用该 resourceVersion
信息,以便 API 服务器能够检测到丢失的更新并拒绝客户端发出的过时请求。如果资源已更改(客户端提供的 resourceVersion
已过时),API 服务器将返回 409 Conflict
错误响应。
客户端可以不发送 PUT 请求,而是向 API 服务器发送指令以**修补**现有资源。如果客户端要进行的更改不依赖于现有数据,**patch** 操作通常是合适的。需要有效检测丢失更新的客户端应考虑将其请求基于现有 resourceVersion
的条件(无论是 HTTP PUT 还是 HTTP PATCH),并在发生冲突时处理所需的任何重试。
Kubernetes API 支持四种不同的 PATCH 操作,这些操作由其相应的 HTTP Content-Type
头确定:
application/apply-patch+yaml
- Server Side Apply YAML(基于 YAML 的 Kubernetes 特有扩展)。所有 JSON 文档都是有效的 YAML,因此您也可以使用此媒体类型提交 JSON。有关更多详细信息,请参阅Server Side Apply 序列化。对于 Kubernetes,如果对象不存在,则这是一次**创建**操作;如果对象已存在,则这是一次**修补**操作。
application/json-patch+json
- JSON Patch,在RFC6902中定义。JSON patch 是在资源上执行的一系列操作;例如
{"op": "add", "path": "/a/b/c", "value": [ "foo", "bar" ]}
。对于 Kubernetes,这是一次**修补**操作。使用
application/json-patch+json
的**修补**可以包含验证一致性的条件,如果这些条件不满足,则允许操作失败(例如,以避免丢失更新)。 application/merge-patch+json
- JSON Merge Patch,在RFC7386中定义。JSON Merge Patch 本质上是资源的部分表示。提交的 JSON 与当前资源合并以创建一个新资源,然后保存新资源。对于 Kubernetes,这是一次**修补**操作。
application/strategic-merge-patch+json
- Strategic Merge Patch(基于 JSON 的 Kubernetes 特有扩展)。Strategic Merge Patch 是 JSON Merge Patch 的定制实现。您只能将 Strategic Merge Patch 用于内置 API 或具有特殊支持的聚合 API 服务器。您不能将
application/strategic-merge-patch+json
用于使用CustomResourceDefinition定义的任何 API。注意
Kubernetes 的*服务器端应用*机制已取代 Strategic Merge Patch。
Kubernetes 的服务器端应用 (Server Side Apply) 特性允许控制平面跟踪新创建对象的托管字段。Server Side Apply 提供了一种清晰的模式来管理字段冲突,提供服务器端的 **apply** 和 **update** 操作,并取代了 kubectl apply
的客户端功能。
对于 Server-Side Apply,如果对象尚不存在,Kubernetes 会将请求视为**创建**操作;否则视为**修补**操作。对于在 HTTP 层面使用 PATCH 的其他请求,逻辑上的 Kubernetes 操作始终是**修补**。
有关更多详细信息,请参阅服务器端应用 (Server Side Apply)。
选择更新机制
使用 HTTP PUT 替换现有资源
**更新** (HTTP PUT
) 操作实现简单且灵活,但存在缺点:
- 您需要处理冲突,即对象在您的客户端读取后尝试写回期间
resourceVersion
发生变化。Kubernetes 总是会检测到冲突,但您作为客户端的开发者需要实现重试逻辑。 - 如果在本地解码对象(例如,使用 client-go),您可能会意外丢弃字段——您可能会收到客户端不知道如何处理的字段,然后在更新过程中丢弃它们。
- 如果对象上存在大量争用(即使是您未尝试编辑的字段或字段集),您可能难以发送更新。对于大型对象和具有许多字段的对象,这个问题会更严重。
使用 JSON Patch 的 HTTP PATCH
**修补**更新很有用,因为:
- 由于您只发送差异,因此在
PATCH
请求中需要发送的数据更少。 - 您可以进行依赖于现有值的更改,例如将特定字段的值复制到注解中。
- 与**更新** (HTTP
PUT
) 不同,即使不相关的字段频繁更改,您的更改也可以立即发生:您通常无需重试。- 如果您希望格外小心以避免丢失更新,您可能仍然需要指定
resourceVersion
(以匹配现有对象) - 在发生错误时编写一些重试逻辑仍然是好的实践。
- 如果您希望格外小心以避免丢失更新,您可能仍然需要指定
- 您可以使用测试条件来精心设计特定的更新条件。例如,如果现有值与您的预期匹配,您可以不读取计数器就对其进行递增。即使自上次写入对象以来它已通过其他方式发生了变化,您也可以这样做而没有丢失更新的风险。(如果测试条件失败,您可以回退到读取当前值,然后写回更改后的数字)。
然而
- 您需要更多的本地(客户端)逻辑来构建 patch;如果您有 JSON Patch 的库实现,甚至有专门针对 Kubernetes 构建 JSON Patch 的实现,将会有很大帮助。
- 作为客户端软件的开发者,在构建 patch(HTTP 请求体)时需要小心,不要丢弃字段(操作顺序很重要)。
使用 Server-Side Apply 的 HTTP PATCH
Server-Side Apply 有一些明显的优势:
- 一次往返:它很少需要先执行
GET
请求。- 而且您仍然可以检测到意外更改的冲突
- 如果合适,您可以选择强制覆盖冲突
- 客户端实现很容易开发。
- 您可以轻松获得原子性的创建或更新操作(类似于某些 SQL 方言中的
UPSERT
)。
然而
- Server-Side Apply 完全不适用于依赖于对象当前值的字段更改。
- 您只能对对象应用更新。Kubernetes HTTP API 中的某些资源不是对象(它们没有
.metadata
字段),Server-Side Apply 仅适用于 Kubernetes 对象。
资源版本
资源版本是标识对象服务器内部版本的字符串。客户端可以使用资源版本来确定对象何时发生变化,或者在获取、列出和监听资源时表达数据一致性要求。资源版本必须被客户端视为不透明值,并未经修改地传递回服务器。
您不得假设资源版本是数字或可排序的。API 客户端只能比较两个资源版本是否相等(这意味着您不得比较资源版本的大小关系)。
metadata 中的 resourceVersion
字段
客户端可以在资源中找到资源版本,包括来自 **watch** 响应流的资源,或者使用 **list** 枚举资源时。
v1.meta/ObjectMeta - 资源实例的 metadata.resourceVersion
标识了该实例最后修改时的资源版本。
v1.meta/ListMeta - 资源集合(**list** 的响应)的 metadata.resourceVersion
标识了该集合构建时的资源版本。
查询字符串中的 resourceVersion
参数
**get**、**list** 和 **watch** 操作支持 resourceVersion
参数。从 v1.19 版本起,Kubernetes API 服务器还在 *list* 请求上支持 resourceVersionMatch
参数。
API 服务器根据您请求的操作以及 resourceVersion
的值以不同方式解释 resourceVersion
参数。如果您设置了 resourceVersionMatch
,这也会影响匹配方式。
**get** 和 **list** 的语义
对于 **get** 和 **list**,resourceVersion
的语义是:
get
resourceVersion 未设置 | resourceVersion="0" | resourceVersion="{除 0 外的其他值}" |
---|---|---|
Most Recent(最新) | Any(任意) | Not older than(不旧于) |
list
从 v1.19 版本起,Kubernetes API 服务器在 *list* 请求上支持 resourceVersionMatch
参数。如果您同时设置了 resourceVersion
和 resourceVersionMatch
,则 resourceVersionMatch
参数决定了 API 服务器如何解释 resourceVersion
。
在对 **list** 请求设置 resourceVersion
时,您应该始终设置 resourceVersionMatch
参数。但是,请准备好处理响应的 API 服务器不识别 resourceVersionMatch
并忽略它的情况。
除非您有严格的一致性要求,否则使用 resourceVersionMatch=NotOlderThan
和一个已知的 resourceVersion
更可取,因为它比将 resourceVersion
和 resourceVersionMatch
保持未设置状态(这需要仲裁读来提供服务)能够实现更好的集群性能和可伸缩性。
在未设置 resourceVersion
的情况下设置 resourceVersionMatch
参数是无效的。
此表解释了 **list** 请求在 resourceVersion
和 resourceVersionMatch
的各种组合下的行为:
resourceVersionMatch 参数 | 分页参数 | resourceVersion 未设置 | resourceVersion="0" | resourceVersion="{除 0 外的其他值}" |
---|---|---|---|---|
未设置 | limit 未设置 | Most Recent(最新) | Any(任意) | Not older than(不旧于) |
未设置 | limit=<n>,continue 未设置 | Most Recent(最新) | Any(任意) | 精确 |
未设置 | limit=<n>,continue=<token> | 续传 | 续传 | 无效,HTTP 400 Bad Request |
resourceVersionMatch=Exact | limit 未设置 | 无效 | 无效 | 精确 |
resourceVersionMatch=Exact | limit=<n>,continue 未设置 | 无效 | 无效 | 精确 |
resourceVersionMatch=NotOlderThan | limit 未设置 | 无效 | Any(任意) | Not older than(不旧于) |
resourceVersionMatch=NotOlderThan | limit=<n>,continue 未设置 | 无效 | Any(任意) | Not older than(不旧于) |
注意
如果您的集群的 API 服务器不遵循resourceVersionMatch
参数,其行为与您未设置此参数时相同。**get** 和 **list** 语义的含义是:
- Any(任意)
- 返回任意资源版本的数据。可用的最新资源版本是首选,但不需要严格一致性;可以提供任意资源版本的数据。由于分区或过时缓存,请求可能返回客户端之前观察到的旧得多的资源版本,特别是在高可用性配置中。不能容忍此情况的客户端不应使用此语义。始终从*watch cache*提供服务,这提高了性能并减少了 etcd 负载。
- Most recent(最新)
- 返回最新资源版本的数据。返回的数据必须一致(具体来说:通过仲裁读从 etcd 提供服务)。对于 etcd v3.4.31+ 和 v3.5.13+,Kubernetes 1.33 版本从*watch cache*提供“最新”读取服务:这是一个 API 服务器内部的内存存储,用于缓存和镜像持久化到 etcd 中的数据状态。Kubernetes 请求进度通知以维护缓存与 etcd 持久层的同步一致性。Kubernetes v1.28 到 v1.30 版本也支持此特性,但作为 Alpha 特性,不推荐用于生产环境,直到 v1.31 版本发布才默认启用。
- Not older than(不旧于)
- 返回至少与提供的
resourceVersion
一样新的数据。可用的最新数据是首选,但不旧于提供的resourceVersion
的任何数据都可以提供。对于遵循resourceVersionMatch
参数的服务器的 **list** 请求,这保证了集合的.metadata.resourceVersion
不旧于请求的resourceVersion
,但不保证该集合中任何项的.metadata.resourceVersion
。始终从*watch cache*提供服务,这提高了性能并减少了 etcd 负载。 - 精确
- 返回所提供的精确资源版本的数据。如果提供的
resourceVersion
不可用,服务器将返回 HTTP410 Gone
。对于遵循resourceVersionMatch
参数的服务器的 **list** 请求,这保证了集合的.metadata.resourceVersion
与您在查询字符串中请求的resourceVersion
相同。该保证不适用于该集合中任何项的.metadata.resourceVersion
。默认从*etcd*提供服务,但如果启用了ListFromCacheSnapshot
特性门,API 服务器将尝试从快照提供响应(如果可用)。这提高了性能并减少了 etcd 负载。缓存快照默认保留 75 秒,因此如果提供的resourceVersion
不可用,服务器将回退到 etcd。 - 续传
- 返回分页 list 请求的下一页数据,确保与序列中初始请求建立的精确
resourceVersion
保持一致。带有 limit 的 **list** 请求的响应包含 *continue token*,该 token 对resourceVersion
和最后观察到的用于恢复 list 的位置进行编码。如果提供的 *continue token* 中的resourceVersion
不可用,服务器将返回 HTTP410 Gone
。默认从*etcd*提供服务,但如果启用了ListFromCacheSnapshot
特性门,API 服务器将尝试从快照提供响应(如果可用)。这提高了性能并减少了 etcd 负载。缓存快照默认保留 75 秒,因此如果提供的 *continue token* 中的resourceVersion
不可用,服务器将回退到 etcd。
注意
当您 **list** 资源并收到集合响应时,响应包含集合的list 元数据以及该集合中每项的对象元数据。对于在集合响应中找到的单个对象,.metadata.resourceVersion
跟踪该对象最后更新的时间,而不是提供服务时对象的最新程度。当使用 resourceVersionMatch=NotOlderThan
并设置了 limit 时,客户端必须处理 HTTP 410 Gone
响应。例如,客户端可以使用更新的 resourceVersion
重试,或回退到 resourceVersion=""
。
当使用 resourceVersionMatch=Exact
且 limit
未设置时,客户端必须验证集合的 .metadata.resourceVersion
是否与请求的 resourceVersion
匹配,并处理不匹配的情况。例如,客户端可以回退到设置了 limit
的请求。
**watch** 的语义
对于 **watch**,资源版本的语义是:
watch
resourceVersion 未设置 | resourceVersion="0" | resourceVersion="{除 0 外的其他值}" |
---|---|---|
Get State and Start at Most Recent(获取状态并从最新版本开始) | Get State and Start at Any(获取状态并从任意版本开始) | Start at Exact(从精确版本开始) |
这些 **watch** 语义的含义是:
- Get State and Start at Any(获取状态并从任意版本开始)
- 从任意资源版本启动一个 **watch**;可用的最新资源版本是首选,但并非必需。允许任意起始资源版本。watch 可能从客户端之前观察到的旧得多的资源版本开始,特别是在高可用性配置中,由于分区或过时缓存。不能容忍这种明显回退的客户端不应使用此语义启动 **watch**。为了建立初始状态,**watch** 会以合成的“Added”事件开始,包含起始资源版本时存在的所有资源实例。所有后续 watch 事件都对应于 **watch** 开始时的资源版本之后发生的所有更改。
注意
以此方式初始化的 **watch** 可能会返回任意过时的数据。在使用此语义之前请审查,并在可能的情况下优先选择其他语义。 - Get State and Start at Most Recent(获取状态并从最新版本开始)
- 从最新资源版本启动一个 **watch**,该版本必须一致(具体来说:通过仲裁读从 etcd 提供服务)。为了建立初始状态,**watch** 会以合成的“Added”事件开始,包含起始资源版本时存在的所有资源实例。所有后续 watch 事件都对应于 **watch** 开始时的资源版本之后发生的所有更改。
- Start at Exact(从精确版本开始)
- 从精确资源版本启动一个 **watch**。watch 事件对应于提供的资源版本之后发生的所有更改。与“获取状态并从最新版本开始”和“获取状态并从任意版本开始”不同,**watch** 不会为提供的资源版本以合成的“Added”事件开始。由于客户端提供了资源版本,因此假定客户端已拥有起始资源版本时的初始状态。
“410 Gone”响应
服务器无需提供所有旧资源版本的数据,如果客户端请求的 resourceVersion
早于服务器保留的版本,服务器可能会返回 HTTP 410 (Gone)
状态码。客户端必须能够容忍 410 (Gone)
响应。有关在监听资源时如何处理 410 (Gone)
响应的详细信息,请参阅有效检测变更。
如果您请求的 resourceVersion
超出了适用限制,则根据请求是否从缓存提供服务,API 服务器可能会回复 HTTP 410 Gone
响应。
不可用的资源版本
服务器无需提供服务未识别的资源版本。如果您请求 **list** 或 **get** 一个 API 服务器不识别的资源版本,则 API 服务器可能:
- 短暂等待资源版本变为可用,如果在合理的时间内提供的资源版本未变为可用,则超时并返回
504 (Gateway Timeout)
; - 返回带有
Retry-After
响应头的响应,指示客户端在重试请求前应等待多少秒。
如果你请求了 API 服务器无法识别的资源版本,kube-apiserver 会额外地在其错误响应中附加消息 Too large resource version
。
如果你对无法识别的资源版本发出 watch 请求,API 服务器可能会无限期地等待(直到请求超时)该资源版本变为可用。