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 概念。
- _资源类型_ 是 URL 中使用的名称(`pods`、`namespaces`、`services`)。
- 所有资源类型都有一个具体的表示(它们的对象模式),称为 _kind_。
- 资源类型的实例列表称为 _集合_。
- 资源类型的单个实例称为 _资源_,通常也表示一个 _对象_。
- 对于某些资源类型,API 包含一个或多个 _子资源_,它们表示为资源下的 URI 路径。
大多数 Kubernetes API 资源类型都是对象——它们表示集群上概念的具体实例,如 Pod 或 Namespace。少数 API 资源类型是_虚拟的_,因为它们通常表示对对象的操作,而不是对象本身,例如权限检查(使用 POST 和 JSON 编码的 `SubjectAccessReview` 主体到 `subjectaccessreviews` 资源),或者 Pod 的 `eviction` 子资源(用于触发API 发起的驱逐)。
对象名称
所有你可以通过 API 创建的对象都有一个唯一的对象名称,以允许幂等创建和检索,但虚拟资源类型可能没有唯一的名称,如果它们不可检索,或者不依赖幂等性。在一个命名空间中,在同一时间,给定类型的只有一个对象可以拥有给定的名称。但是,如果你删除了该对象,你可以使用相同的名称创建一个新对象。一些对象不是命名空间作用域的(例如:节点),因此它们的名称必须在整个集群中唯一。
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、YAML、CBOR 和 Protobuf 有线编码。
默认情况下,Kubernetes 使用 `application/json` 媒体类型以JSON 序列化返回对象。虽然 JSON 是默认值,但客户端可以请求 YAML 格式的响应,或使用更高效的二进制Protobuf 表示以提高大规模性能。
Kubernetes API 实现了标准的 HTTP 内容类型协商:在 `GET` 调用中传递带有 `Accept` 头的请求将要求服务器尝试以你首选的媒体类型返回响应。如果你想在 `PUT` 或 `POST` 请求中以 Protobuf 格式向服务器发送对象,你必须相应地设置 `Content-Type` 请求头。
如果你请求可用的媒体类型,API 服务器将返回一个带有适当 `Content-Type` 的响应;如果你请求的媒体类型都不受支持,API 服务器将返回 `406 Not acceptable` 错误消息。所有内置资源类型都支持 `application/json` 媒体类型。
集合的分块编码
对于 JSON 和 Protobuf 编码,Kubernetes 实现了自定义编码器,逐项写入。此功能不会改变输出,但允许 API 服务器避免将整个 LIST 响应加载到内存中。对于大型资源集合(>100MB),应避免使用其他类型的编码(包括 JSON 的美观表示),因为它可能对性能产生负面影响。
JSON 资源编码
Kubernetes API 默认使用 JSON 对 HTTP 消息体进行编码。
例如
列出集群上的所有 Pod,不指定首选格式。
GET /api/v1/pods200 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 object200 OK Content-Type: application/json { "kind": "Pod", "apiVersion": "v1", … }
YAML 资源编码
Kubernetes 还支持 `application/yaml` 媒体类型,用于请求和响应。`YAML` 可用于定义 Kubernetes 清单和 API 交互。
例如
以 YAML 格式列出集群上的所有 Pod。
GET /api/v1/pods Accept: application/yaml200 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 object200 OK Content-Type: application/yaml apiVersion: v1 kind: Pod metadata: name: my-pod …
Kubernetes Protobuf 编码
Kubernetes 使用信封包装器来编码 Protobuf 响应。该包装器以 4 字节魔术数字开头,以帮助识别磁盘或 etcd 中的内容是 Protobuf(而不是 JSON)。4 字节魔术数字数据后面跟着一个 Protobuf 编码的包装消息,该消息描述了底层对象的编码和类型。在 Protobuf 包装消息中,内部对象数据使用 Unknown 的 `raw` 字段记录(有关详细信息,请参阅IDL)。
例如
以 Protobuf 格式列出集群上的所有 Pod。
GET /api/v1/pods Accept: application/vnd.kubernetes.protobuf200 OK Content-Type: application/vnd.kubernetes.protobuf … binary 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 object200 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 不适用于定义为CustomResourceDefinitions 的资源,或者通过聚合层提供的资源。
作为客户端,如果你可能需要使用扩展类型,你应该在请求 `Accept` 头中指定多个内容类型,以支持回退到 JSON。例如:
Accept: application/vnd.kubernetes.protobuf, application/json
CBOR 资源编码
Kubernetes v1.32 [alpha] (默认禁用)启用 `CBORServingAndStorage` 功能门后,所有内置资源类型以及通过CustomResourceDefinition 定义的所有资源的请求和响应主体都可以编码为 CBOR 二进制数据格式。如果在各个聚合 API 服务器中启用了 CBOR,聚合层也支持 CBOR。
当请求体包含单个 CBOR 编码数据项时,客户端应在 `Content-Type` HTTP 请求头中指示 IANA 媒体类型 `application/cbor`;当准备接受响应中的 CBOR 编码数据项时,应在 `Accept` HTTP 请求头中指示。当响应体包含 CBOR 编码对象时,API 服务器将在 `Content-Type` HTTP 响应头中使用 `application/cbor`。
如果 API 服务器使用 CBOR 对watch 请求的响应进行编码,则响应主体将是 CBOR 序列,并且 `Content-Type` HTTP 响应头将使用 IANA 媒体类型 `application/cbor-seq`。序列中的每个条目(如果有)都是一个 CBOR 编码的 watch 事件。
除了用于 YAML 编码的服务器端应用配置的现有 `application/apply-patch+yaml` 媒体类型外,启用 CBOR 的 API 服务器还将接受用于 CBOR 编码的服务器端应用配置的 `application/apply-patch+cbor` 媒体类型。没有支持的 CBOR 等效项用于 `application/json-patch+json` 或 `application/merge-patch+json`,或 `application/strategic-merge-patch+json`。
高效的变更检测
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_ 命名空间中 Pod 的任何 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` 的 watch 事件。这是一种特殊的事件,用于标记客户端请求的所有变更,直到给定的 `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.34 [beta] (默认启用:true)在大型集群上,检索某些资源类型的集合可能会导致控制平面上的资源使用量(主要是 RAM)显著增加。为了减轻这种影响并简化 **list** + **watch** 模式的用户体验,Kubernetes v1.32 将允许请求初始状态(以前通过 **list** 请求请求)作为 **watch** 请求的一部分的功能提升为 beta 版。
在客户端,可以通过在 **watch** 请求中将 `sendInitialEvents=true` 指定为查询字符串参数来请求初始状态。如果设置,API 服务器将启动 watch 流,其中包含合成的初始事件(类型为 `ADDED`),以构建所有现有对象的完整状态,然后是`BOOKMARK` 事件(如果通过 `allowWatchBookmarks=true` 选项请求)。书签事件包括同步到的资源版本。发送书签事件后,API 服务器会像处理任何其他 **watch** 请求一样继续。
当你在查询字符串中设置 `sendInitialEvents=true` 时,Kubernetes 还要求你将 `resourceVersionMatch` 设置为 `NotOlderThan` 值。如果你在查询字符串中提供了 `resourceVersion` 而没有提供值,或者根本没有提供,这将被解释为请求_一致性读取_;当状态至少同步到请求开始处理时的一致性读取时刻时,将发送书签事件。如果你指定了 `resourceVersion`(在查询字符串中),当状态至少同步到提供的资源版本时,将发送书签事件。
示例
例如:你想监视 Pod 集合。对于该集合,当前资源版本为 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](默认启用:true)APIResponseCompression 选项允许 API 服务器压缩 **get** 和 **list** 请求的响应,从而减少网络带宽并提高大型集群的性能。自 Kubernetes 1.16 起默认启用,可以通过在 API 服务器的 `--feature-gates` 标志中包含 `APIResponseCompression=false` 来禁用。
API 响应压缩可以显著减小响应大小,特别是对于大型资源或集合。例如,对 Pod 的 **list** 请求可以返回数百 KB 甚至数 MB 的数据,具体取决于 Pod 的数量及其属性。通过压缩响应,可以节省网络带宽并减少延迟。
要验证 `APIResponseCompression` 是否正常工作,你可以向 API 服务器发送 **get** 或 **list** 请求,并带上 `Accept-Encoding` 头,然后检查响应大小和头。例如:
GET /api/v1/pods
Accept-Encoding: gzip
---
200 OK
Content-Type: application/json
content-encoding: gzip
...
content-encoding 头表示响应已使用 `gzip` 压缩。
分块检索大量结果集
Kubernetes v1.29 [stable](默认启用:true)在大型集群上,检索某些资源类型集合可能导致非常大的响应,从而影响服务器和客户端。例如,一个集群可能拥有数万个 Pod,每个 Pod 大约相当于 2 KiB 的编码 JSON。检索所有命名空间中的所有 Pod 可能导致非常大的响应(10-20MB),并消耗大量服务器资源。
Kubernetes API 服务器支持将单个大型集合请求分解为许多较小的块,同时保持总请求的一致性。每个块可以顺序返回,这既减少了请求的总大小,又允许面向用户的客户端增量显示结果以提高响应速度。
你可以请求 API 服务器通过分页(Kubernetes 称之为_分块_)来处理 **list**,以提供单个集合。为了分块检索单个集合,在针对集合的请求中支持两个查询参数 `limit` 和 `continue`,并且在集合的 `metadata` 字段中从所有 **list** 操作返回一个响应字段 `continue`。客户端应使用 `limit` 指定它们希望在每个块中接收的最大结果数,服务器将在结果中返回最多 `limit` 个资源,如果集合中还有更多资源,则包含一个 `continue` 值。
作为 API 客户端,你可以将此 `continue` 值传递给下一个请求中的 API 服务器,以指示服务器返回下一页(_块_)结果。通过持续操作直到服务器返回一个空的 `continue` 值,你可以检索整个集合。
与 **watch** 操作一样,`continue` 令牌会在短时间后(默认为 5 分钟)过期,如果无法返回更多结果,则返回 `410 Gone`。在这种情况下,客户端需要从头开始或省略 `limit` 参数。
例如,如果集群上有 1253 个 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 为不同类型资源的集合定义了具体的 kind。集合的 kind 名称是资源 kind,后跟 `List`。
当你查询 API 某个特定类型时,该查询返回的所有项都属于该类型。例如,当你 **list** Services 时,集合响应的 `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 聚合或第三方资源提供的类型在编译时未知。这意味着必须为客户端无法识别的类型提供通用实现。
为了避免上述潜在限制,客户端可以请求对象的表格表示,将打印的具体细节委托给服务器。Kubernetes API 实现了标准的 HTTP 内容类型协商:在 `GET` 调用中传递包含 `application/json;as=Table;g=meta.k8s.io;v=v1` 值的 `Accept` 头将请求服务器以 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 响应;例如,CustomResourceDefinitions 可能没有定义字段到表格的映射,并且扩展核心 Kubernetes API 的 APIService 可能根本不提供 Table 响应。如果你正在实现一个使用 Table 信息并必须处理所有资源类型(包括扩展)的客户端,你应发出在 `Accept` 头中指定多种内容类型的请求。例如:
Accept: application/json;as=Table;g=meta.k8s.io;v=v1, application/json
资源删除
当你**删除**资源时,这会分两个阶段进行。
- 终结化
- 删除
{
"kind": "ConfigMap",
"apiVersion": "v1",
"metadata": {
"finalizers": ["url.io/neat-finalization", "other-url.io/my-finalizer"],
"deletionTimestamp": nil,
}
}
当客户端首次发送 **delete** 请求删除资源时,`.metadata.deletionTimestamp` 被设置为当前时间。一旦 `.metadata.deletionTimestamp` 被设置,作用于 Finalizer 的外部控制器就可以随时以任何顺序开始执行它们的清理工作。
Finalizer 之间不强制执行顺序,因为这会带来 `.metadata.finalizers` 陷入停滞的重大风险。
`.metadata.finalizers` 字段是共享的:任何有权限的参与者都可以对其重新排序。如果 Finalizer 列表按顺序处理,那么这可能导致以下情况:列表中第一个 Finalizer 负责的组件正在等待由列表中较晚 Finalizer 负责的组件产生的一些信号(字段值、外部系统或其他),从而导致死锁。
在不强制排序的情况下,Finalizer 可以自由地自行排序,并且不受列表中排序变更的影响。
一旦最后一个 Finalizer 被移除,资源实际上就会从 etcd 中移除。
强制删除
Kubernetes v1.32 [alpha] (默认禁用)注意
如果被强制删除的资源依赖于正常的删除流程,这可能会破坏与之关联的工作负载,因此可能会产生破坏集群的后果。通过启用删除选项 `ignoreStoreReadErrorWithClusterBreakingPotential`,用户可以对不可解密/损坏的资源执行不安全的强制 **delete** 操作。此选项在 ALPHA 功能门后,默认禁用。为了使用此选项,集群操作员必须通过设置命令行选项 `--feature-gates=AllowUnsafeMalformedObjectDeletion=true` 来启用该功能。
注意
执行强制 **delete** 操作的用户必须具有对给定资源执行 **delete** 和 **unsafe-delete-ignore-read-errors** 动词的权限。如果资源因以下原因无法从存储中成功检索,则被视为损坏:
- 转换错误(例如:解密失败),或
- 对象解码失败。
API 服务器首先尝试正常删除,如果正常删除失败并出现_损坏资源_错误,则触发强制删除。强制 **delete** 操作是不安全的,因为它忽略了终结器约束,并跳过了前置条件检查。
此选项的默认值为 `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 模式中,因此无法识别。(一个例外是 CRD 明确选择不通过 `x-kubernetes-preserve-unknown-fields` 剪除未知字段。)
- 该字段在对象中重复。
未知或重复字段的验证
Kubernetes v1.27 [stable](默认启用:true)从 1.25 版本开始,当您使用可以提交数据的 HTTP 动词(`POST`、`PUT` 和 `PATCH`)时,服务器通过验证检测对象中无法识别或重复的字段。验证级别可能为 `Ignore`、`Warn`(默认)和 `Strict`。
忽略- API 服务器成功处理请求,就像没有设置错误字段一样,删除所有未知和重复字段,并且不给出任何指示。
警告- (默认)API 服务器成功处理请求,并向客户端报告警告。警告通过 `Warning:` 响应头发送,每个未知或重复字段添加一个警告项。有关警告和 Kubernetes API 的更多信息,请参阅博客文章警告:前方有用警告。
严格- 当 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` 用作布尔标志来打开或关闭客户端验证。从 v1.33 开始,Kubernetes(包括 v1.34)提供了一种使用_声明式标签_定义字段验证的方法。这对于 Kubernetes 本身的贡献者很有用,如果你正在使用 Kubernetes 库编写自己的 API,这也相关。要了解更多信息,请参阅声明式 API 验证。
试运行
Kubernetes v1.19 [stable](默认启用:true)当你使用可以修改资源的 HTTP 动词(`POST`、`PUT`、`PATCH` 和 `DELETE`)时,你可以以_试运行_模式提交请求。试运行模式有助于评估请求通过典型的请求阶段(准入链、验证、合并冲突),直到将对象持久化到存储。请求的响应主体尽可能接近非试运行响应。Kubernetes 保证试运行请求不会持久化到存储或产生任何其他副作用。
发起试运行请求
试运行通过设置 `dryRun` 查询参数触发。此参数是一个字符串,作为枚举工作,唯一接受的值是:
- [未设置值]
- 允许副作用。你可以使用 `?dryRun` 或 `?dryRun&pretty=true` 等查询字符串请求。响应将是最终将持久化的对象,如果请求无法完成,则返回错误。
所有- 每个阶段都正常运行,但最终存储阶段除外,在该阶段会阻止副作用。
当你设置 `?dryRun=All` 时,任何相关的准入控制器都会运行,验证准入控制器会检查请求后的变异,`PATCH` 操作会执行合并,字段会进行默认设置,并进行模式验证。变更不会持久化到底层存储,但最终将持久化的对象仍会连同正常的状态码一起返回给用户。
如果请求的非试运行版本会触发具有副作用的准入控制器,则请求将失败,而不是冒不必要的副作用的风险。所有内置的准入控制插件都支持试运行。此外,准入 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:跟踪对象的持久化版本。- 由变异准入控制器设置的任何字段。
- 对于 `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` 错误响应。
客户端可以发送指令给 API 服务器来**修补**现有资源,而不是发送 PUT 请求。如果客户端想要进行的更改不依赖于现有数据,则**修补**通常是合适的。需要有效检测丢失更新的客户端应考虑使其请求以现有 `resourceVersion` 为条件(无论是 HTTP PUT 还是 HTTP PATCH),然后处理在发生冲突时所需的任何重试。
Kubernetes API 支持四种不同的 PATCH 操作,由其相应的 HTTP `Content-Type` 标头决定:
application/apply-patch+yaml- 服务器端应用 YAML(Kubernetes 特定的扩展,基于 YAML)。所有 JSON 文档都是有效的 YAML,因此你也可以使用此媒体类型提交 JSON。有关更多详细信息,请参阅服务器端应用序列化。对于 Kubernetes,如果对象不存在,这是一个 **create** 操作;如果对象已存在,这是一个 **patch** 操作。
application/json-patch+json- JSON Patch,定义在 RFC6902 中。JSON Patch 是在资源上执行的一系列操作;例如 `{"op": "add", "path": "/a/b/c", "value": [ "foo", "bar" ]}`。对于 Kubernetes,这是一个 **patch** 操作。
使用 `application/json-patch+json` 进行的 **patch** 可以包含用于验证一致性的条件,如果这些条件不满足,则允许操作失败(例如,以避免丢失更新)。
application/merge-patch+json- JSON 合并补丁,定义在 RFC7386 中。JSON 合并补丁本质上是资源的部分表示。提交的 JSON 与当前资源合并以创建一个新资源,然后保存新资源。对于 Kubernetes,这是一个 **patch** 操作。
application/strategic-merge-patch+json- 战略合并补丁(Kubernetes 特定的基于 JSON 的扩展)。战略合并补丁是 JSON 合并补丁的自定义实现。你只能将战略合并补丁与内置 API 或具有特殊支持的聚合 API 服务器一起使用。你不能将 `application/strategic-merge-patch+json` 与使用CustomResourceDefinition 定义的任何 API 一起使用。
注意
Kubernetes 的 _服务器端应用_ 机制已取代战略合并补丁。
Kubernetes 的服务器端应用功能允许控制平面跟踪新创建对象的受管理字段。服务器端应用为管理字段冲突提供了清晰的模式,提供了服务器端 **apply** 和 **update** 操作,并取代了 `kubectl apply` 的客户端功能。
对于服务器端应用,如果对象尚不存在,Kubernetes 将请求视为 **create**,否则视为 **patch**。对于在 HTTP 级别使用 PATCH 的其他请求,逻辑 Kubernetes 操作始终是 **patch**。
有关更多详细信息,请参阅服务器端应用。
选择更新机制
HTTP PUT 替换现有资源
**更新** (HTTP `PUT`) 操作实现简单且灵活,但存在以下缺点:
- 你需要处理冲突,即在你客户端读取对象并尝试将其写回之间,对象的 `resourceVersion` 发生更改。Kubernetes 总是会检测到冲突,但作为客户端作者,你需要实现重试。
- 如果你在本地解码对象,你可能会意外地丢失字段(例如,使用 client-go,你可能会收到客户端不知道如何处理的字段,然后在更新时将其丢弃)。
- 如果对象上存在大量争用(即使在您未尝试编辑的字段或一组字段上),您可能会难以发送更新。对于更大的对象和具有许多字段的对象,问题会更严重。
使用 JSON Patch 的 HTTP PATCH
**补丁**更新很有帮助,因为:
- 由于你只发送差异,因此 `PATCH` 请求中要发送的数据量更少。
- 你可以进行依赖现有值的更改,例如将特定字段的值复制到注解中。
- 与 **更新** (HTTP `PUT`) 不同,即使无关字段频繁更改,你的更改也可以立即发生:你通常不需要重试。
- 如果你想额外小心以避免丢失更新,你可能仍然需要指定 `resourceVersion`(以匹配现有对象)。
- 在出现错误时编写一些重试逻辑仍然是良好的实践。
- 你可以使用测试条件精心设计特定的更新条件。例如,如果现有值与你期望的匹配,你可以在不读取它的情况下递增计数器。即使对象自上次写入以来已以其他方式更改,你也可以这样做,而不会丢失更新风险。(如果测试条件失败,你可以回退到读取当前值,然后写回更改后的数字)。
然而,
- 你需要更多的本地(客户端)逻辑来构建补丁;如果你有 JSON Patch 的库实现,甚至专门针对 Kubernetes 制作 JSON Patch 的库,将大有帮助。
- 作为客户端软件的作者,在构建补丁(HTTP 请求体)时,你需要小心不要丢失字段(操作顺序很重要)。
使用服务器端应用的 HTTP PATCH
服务器端应用有一些明显的优势:
- 单次往返:很少需要先发出 `GET` 请求。
- 你仍然可以检测意外更改的冲突。
- 如果合适,你可以选择强制覆盖冲突。
- 客户端实现很容易。
- 您可以轻松获得原子性的创建或更新操作(类似于某些 SQL 方言中的
UPSERT)。
然而,
- Server-Side Apply 完全不适用于依赖对象当前值的字段更改。
- 您只能对对象应用更新。Kubernetes HTTP API 中的某些资源不是对象(它们没有
.metadata字段),Server-Side Apply 仅与 Kubernetes 对象相关。
资源版本
资源版本是标识服务器内部对象版本的字符串。客户端可以使用资源版本来确定对象何时发生更改,或者在获取、列出和监视资源时表达数据一致性要求。客户端必须将资源版本视为不透明,并将其未修改地传回服务器。
您不得假定资源版本是数字或可排序的。API 客户端只能比较两个资源版本的相等性(这意味着您不得比较资源版本的“大于”或“小于”关系)。
元数据中的 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 以外的值}" |
|---|---|---|
| 最新 | 任意 | 不早于 |
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 | 最新 | 任意 | 不早于 |
| 未设置 | limit=<n>, continue 未设置 | 最新 | 任意 | 精确 |
| 未设置 | limit=<n>, continue=<token> | 继续 | 继续 | 无效,HTTP 400 Bad Request |
resourceVersionMatch=Exact | 未设置 limit | 无效 | 无效 | 精确 |
resourceVersionMatch=Exact | limit=<n>, continue 未设置 | 无效 | 无效 | 精确 |
resourceVersionMatch=NotOlderThan | 未设置 limit | 无效 | 任意 | 不早于 |
resourceVersionMatch=NotOlderThan | limit=<n>, continue 未设置 | 无效 | 任意 | 不早于 |
注意
如果您的集群 API 服务器不遵守resourceVersionMatch 参数,则行为与您未设置它时相同。get 和 list 语义的含义是
- 任意
- 返回任意资源版本的数据。首选最新的可用资源版本,但不需要强一致性;可以提供任意资源版本的数据。请求可能会返回比客户端之前观察到的旧得多的资源版本的数据,特别是在高可用性配置中,由于分区或陈旧缓存。不能容忍这种情况的客户端不应使用此语义。始终从 watch cache 提供服务,提高性能并减少 etcd 负载。
- 最新
- 返回最新资源版本的数据。返回的数据必须一致(具体来说:通过仲裁读取从 etcd 提供)。对于 etcd v3.4.31+ 和 v3.5.13+,Kubernetes 1.34 从 watch cache 提供“最新”读取服务:API 服务器内部的内存存储,用于缓存和镜像持久化到 etcd 中的数据状态。Kubernetes 请求进度通知以维护缓存与 etcd 持久层的最新一致性。Kubernetes v1.28 到 v1.30 也支持此功能,尽管作为 Alpha 版不建议用于生产环境,直到 v1.31 版本才默认启用。
- 不早于
- 返回至少与提供的
resourceVersion一样新的数据。首选最新的可用数据,但可以提供不早于提供的resourceVersion的任何数据。对于遵守resourceVersionMatch参数的服务器的 list 请求,这保证了集合的.metadata.resourceVersion不早于请求的resourceVersion,但不对该集合中任何项目的.metadata.resourceVersion做任何保证。始终从 watch cache 提供服务,提高性能并减少 etcd 负载。 - 精确
- 返回提供的精确资源版本的数据。如果提供的
resourceVersion不可用,服务器将响应 HTTP410 Gone。对于遵守resourceVersionMatch参数的服务器的 list 请求,这保证了集合的.metadata.resourceVersion与您在查询字符串中请求的resourceVersion相同。该保证不适用于该集合中任何项目的.metadata.resourceVersion。在默认启用ListFromCacheSnapshot功能门的情况下,API 服务器将尝试从快照提供响应,如果有一个resourceVersion早于请求的快照可用。这提高了性能并减少了 etcd 负载。API 服务器开始时没有快照,在每次 watch 事件时创建新快照,并保留它们直到检测到 etcd 已压缩或缓存已满(事件早于 75 秒)。如果提供的resourceVersion不可用,服务器将回退到 etcd。 - 继续
- 返回分页列表请求的下一页数据,确保与序列中初始请求建立的精确
resourceVersion一致。对带有 limit 的 list 请求的响应包括 continue token,它编码了resourceVersion和上次观察到的位置,以便从中恢复列表。如果提供的 continue token 中的resourceVersion不可用,服务器将响应 HTTP410 Gone。在默认启用ListFromCacheSnapshot功能门的情况下,API 服务器将尝试从快照提供响应,如果有一个resourceVersion早于请求的快照可用。这提高了性能并减少了 etcd 负载。API 服务器开始时没有快照,在每次 watch 事件时创建新快照,并保留它们直到检测到 etcd 已压缩或缓存已满(事件早于 75 秒)。如果提供的 continue token 中的resourceVersion不可用,服务器将回退到 etcd。
注意
当您 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 以外的值}" |
|---|---|---|
| 获取状态并从最新开始 | 获取状态并从任意开始 | 从精确版本开始 |
这些 watch 语义的含义是
- 获取状态并从任意开始
- 从任何资源版本开始 watch;首选可用的最新资源版本,但不是必需的。允许任何起始资源版本。watch 可能会从比客户端之前观察到的旧得多的资源版本开始,特别是在高可用性配置中,由于分区或陈旧缓存。不能容忍这种明显回溯的客户端不应使用此语义开始 watch。为了建立初始状态,watch 以起始资源版本存在的所有资源实例的合成“Added”事件开始。所有后续的 watch 事件都是在 watch 开始的资源版本之后发生的所有更改。
注意
以这种方式初始化的 watches 可能会返回任意陈旧的数据。在使用它之前请仔细审查此语义,并尽可能优先使用其他语义。 - 获取状态并从最新开始
- 从最新资源版本开始 watch,该版本必须一致(具体来说:通过仲裁读取从 etcd 提供)。为了建立初始状态,watch 以起始资源版本存在的所有资源实例的合成“Added”事件开始。所有后续的 watch 事件都是在 watch 开始的资源版本之后发生的所有更改。
- 从精确版本开始
- 从精确资源版本开始 watch。watch 事件是提供的资源版本之后的所有更改。与“获取状态并从最新开始”和“获取状态并从任意开始”不同,watch 不会以提供的资源版本的合成“Added”事件开始。假定客户端已经具有起始资源版本的初始状态,因为客户端提供了资源版本。
“410 Gone”响应
服务器不需要提供所有较旧的资源版本,如果客户端请求的 resourceVersion 比服务器保留的旧,则可能会返回 HTTP 410 (Gone) 状态码。客户端必须能够容忍 410 (Gone) 响应。有关在监视资源时如何处理 410 (Gone) 响应的详细信息,请参阅高效检测更改。
如果您请求超出适用限制的 resourceVersion,那么根据请求是否从缓存提供,API 服务器可能会回复 410 Gone HTTP 响应。
不可用的资源版本
服务器不需要提供无法识别的资源版本。如果您请求 list 或 get 无法识别的资源版本,则 API 服务器可能会
- 短暂等待资源版本变得可用,如果提供的资源版本在合理的时间内未变得可用,则超时并返回
504 (Gateway Timeout); - 使用
Retry-After响应头回复,指示客户端在重试请求之前应等待多少秒。
如果您请求 API 服务器无法识别的资源版本,kube-apiserver 还会用消息 Too large resource version 标识其错误响应。
如果您请求无法识别的资源版本的 watch 请求,API 服务器可能会无限期地等待(直到请求超时)资源版本变得可用。