Kubernetes API 概念

Kubernetes API 是一个基于资源(RESTful)的编程接口,通过 HTTP 提供。它支持通过标准的 HTTP 动词(POST、PUT、PATCH、DELETE、GET)检索、创建、更新和删除主要资源。

对于某些资源,API 包含额外的子资源,这些子资源允许细粒度的授权(例如,Pod 详细信息和日志检索的单独视图),并且可以接受和提供这些资源的不同表示形式,以方便或提高效率。

Kubernetes 支持通过watches 对资源进行高效的变更通知

在 Kubernetes API 中,watch 是一个动词,用于跟踪 Kubernetes 中对象的变化流。它用于有效地检测更改。

Kubernetes 还提供一致的列表操作,以便 API 客户端可以有效地缓存、跟踪和同步资源的状态。

您可以在线查看 API 参考,或继续阅读以了解有关 API 的一般信息。

Kubernetes API 术语

Kubernetes 通常利用常见的 RESTful 术语来描述 API 概念

  • 资源类型是在 URL 中使用的名称(podsnamespacesservices
  • 所有资源类型都有具体的表示形式(其对象模式),称为kind
  • 资源类型实例的列表称为集合
  • 资源类型的一个实例称为资源,通常也代表一个对象
  • 对于某些资源类型,API 包含一个或多个子资源,这些子资源表示为资源下方的 URI 路径

大多数 Kubernetes API 资源类型都是 对象 – 它们代表集群上概念的具体实例,例如 Pod 或命名空间。较少数量的 API 资源类型是虚拟的,因为它们通常代表对象上的操作,而不是对象本身,例如权限检查(使用 POST 和 JSON 编码的主体到 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 内部将这些请求分类为 createupdate,具体取决于现有对象的状态。updatepatch 不同;HTTP 动词为 patch 是 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 以 JSON 序列化 形式返回对象,使用 application/json 媒体类型。虽然 JSON 是默认设置,但客户端可以请求 YAML 响应,或者使用更高效的二进制 Protobuf 表示形式 以提高规模。

Kubernetes API 实现标准的 HTTP 内容类型协商:在 GET 调用中传递 Accept 标头将请求服务器尝试以您首选的媒体类型返回响应。如果您想将 Protobuf 对象发送到服务器进行 PUT 或 POST 请求,则必须相应地设置 Content-Type 请求标头。

如果您请求可用的媒体类型,API 服务器将返回带有合适的 Content-Type 的响应;如果不支持您请求的任何媒体类型,API 服务器将返回 406 Not acceptable 错误消息。所有内置资源类型都支持 application/json 媒体类型。

集合的块编码

对于 JSON 和 Protobuf 编码,Kubernetes 实现自定义编码器,这些编码器逐项写入。此功能不会更改输出,但允许 API 服务器避免将整个 LIST 响应加载到内存中。对于大型资源集合(>100MB),应避免使用其他类型的编码(包括 JSON 的漂亮表示),因为它可能会对性能产生负面影响。

JSON 资源编码

Kubernetes 默认使用 JSON 对 HTTP 消息体进行编码。

例如

  1. 列出集群中的所有 Pod,无需指定首选格式

    GET /api/v1/pods
    
    200 OK
    Content-Type: application/json
    
    … JSON encoded collection of Pods (PodList object)
    
  2. 通过向服务器发送 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 交互。

例如

  1. 以 YAML 格式列出集群中的所有 Pod

    GET /api/v1/pods
    Accept: application/yaml
    
    200 OK
    Content-Type: application/yaml
    
    … YAML encoded collection of Pods (PodList object)
    
  2. 通过发送 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 使用一个包络包装器来编码 Protobuf 响应。该包装器以 4 字节的魔数开头,以帮助识别磁盘或 etcd 中的内容为 Protobuf(而不是 JSON)。4 字节的魔数数据后跟一个 Protobuf 编码的包装器消息,该消息描述了底层对象的编码和类型。在 Protobuf 包装器消息中,内部对象数据使用 Unknown 的 raw 字段记录(有关更多详细信息,请参阅 IDL)。

例如

  1. 以 Protobuf 格式列出集群中的所有 Pod。

    GET /api/v1/pods
    Accept: application/vnd.kubernetes.protobuf
    
    200 OK
    Content-Type: application/vnd.kubernetes.protobuf
    
    … binary encoded collection of Pods (PodList object)
    
  2. 通过发送 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;
  }

您还可以请求表格仅元数据的表示形式的编码。

与 Kubernetes Protobuf 的兼容性

并非所有 API 资源类型都支持 Kubernetes 的 Protobuf 编码;特别是,对于定义为 CustomResourceDefinitions 或通过 聚合层提供的资源,Protobuf 不可用。

作为客户端,如果您可能需要处理扩展类型,您应该在请求的 Accept 标头中指定多个内容类型,以支持回退到 JSON。例如:

Accept: application/vnd.kubernetes.protobuf, application/json

CBOR 资源编码

功能状态: Kubernetes v1.32 [alpha](默认禁用)

启用 CBORServingAndStorage 功能门后,所有内置资源类型以及由 CustomResourceDefinition 定义的所有资源的请求和响应主体都可以编码为 CBOR 二进制数据格式。 CBOR 也受 聚合层的支持,如果它在单个聚合 API 服务器中启用。

客户端应在 Content-Type HTTP 请求标头中指示 IANA 媒体类型 application/cbor,当请求主体包含单个 CBOR 编码数据项时,并在 Accept HTTP 请求标头中指示 IANA 媒体类型 application/cbor,当准备好接受 CBOR 编码数据项作为响应时。 API 服务器将在 Content-Type HTTP 响应标头中使用 application/cbor,当响应主体包含 CBOR 编码的对象时。

如果 API 服务器使用 CBOR 对 watch 请求的响应进行编码,则响应主体将是 CBOR 序列,并且 Content-Type HTTP 响应标头将使用 IANA 媒体类型 application/cbor-seq。序列中的每个条目(如果有)都是单个 CBOR 编码的 watch 事件。

除了用于 YAML 编码的 服务器端应用配置的现有 application/apply-patch+yaml 媒体类型之外,启用 CBOR 的 API 服务器将接受 application/apply-patch+cbor 媒体类型,用于 CBOR 编码的服务器端应用配置。 没有 CBOR 对 application/json-patch+jsonapplication/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 之后发生的的操作结果(例如 createdeleteupdate)。整个 watch 机制允许客户端获取当前状态,然后订阅后续更改,而不会错过任何事件。

如果客户端 watch 断开连接,则该客户端可以从最后返回的 resourceVersion 开始一个新的 watch;客户端也可以执行新的 get / list 请求并重新开始。请参阅 资源版本语义 以获取更多详细信息。

例如

  1. 列出给定命名空间中的所有 Pod。

    GET /api/v1/namespaces/test/pods
    ---
    200 OK
    Content-Type: application/json
    
    {
      "kind": "PodList",
      "apiVersion": "v1",
      "metadata": {"resourceVersion":"10245"},
      "items": [...]
    }
    
  2. 从资源版本 10245 开始,接收有关任何 API 操作(例如 createdeletepatchupdate)的通知,这些操作会影响 test 命名空间中的 Pod。每个更改通知都是一个 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 操作失败,因为该资源的 historical 版本不可用时,客户端必须通过识别状态码 410 Gone、清除其本地缓存、执行新的 getlist 操作以及从返回的 resourceVersion 开始来处理这种情况。

对于订阅集合,Kubernetes 客户端库通常提供某种标准的工具来实现这种 list-then-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](默认启用)

在大型集群上,检索某些资源类型的集合可能会导致控制平面上的资源使用量(主要是 RAM)显著增加。为了减轻影响并简化 list + watch 模式的用户体验,Kubernetes v1.32 将允许将初始状态(以前通过 list 请求请求)作为 watch 请求的一部分请求的功能提升到 beta 版。

在客户端,可以通过在 watch 请求中将 sendInitialEvents=true 指定为查询字符串参数来请求初始状态。如果设置,API 服务器将从合成的 init 事件(类型为 ADDED)开始 watch 流,以构建所有现有对象的状态,然后是 BOOKMARK 事件(如果通过 allowWatchBookmarks=true 选项请求)。书签事件包括同步到的资源版本。发送书签事件后,API 服务器将像任何其他 watch 请求一样继续。

当您在查询字符串中设置 sendInitialEvents=true 时,Kubernetes 还要求您将 resourceVersionMatch 设置为 NotOlderThan 值。如果您在查询字符串中提供了 resourceVersion 而未提供值,或者根本未提供它,则将其解释为对一致读取的请求;当状态至少与请求开始处理时的一致读取同步时,将发送书签事件。如果您指定了 resourceVersion(在查询字符串中),则当状态至少与提供的资源版本同步时,将发送书签事件。

示例

一个例子:您想监视 Pod 的集合。对于该集合,当前的资源版本是 10245,并且有两个 Pod:foobar。然后发送以下请求(通过使用 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 服务器压缩 getlist 请求的响应,从而减少网络带宽并提高大型集群的性能。它自 Kubernetes 1.16 起默认启用,可以通过在 API 服务器的 --feature-gates 标志中包含 APIResponseCompression=false 来禁用。

API 响应压缩可以显著减小响应的大小,特别是对于大型资源或 集合。例如,Pod 的 list 请求可以返回数百千字节甚至兆字节的数据,具体取决于 Pod 的数量及其属性。通过压缩响应,可以节省网络带宽并减少延迟。

为了验证 APIResponseCompression 是否有效,您可以向 API 服务器发送带有 Accept-Encoding 头部的 getlist 请求,并检查响应大小和头部。例如

GET /api/v1/pods
Accept-Encoding: gzip
---
200 OK
Content-Type: application/json
content-encoding: gzip
...

content-encoding 头部指示响应使用 gzip 压缩。

分块检索大型结果集

功能状态: Kubernetes v1.29 [稳定](默认启用)

在大型集群中,检索某些资源类型的集合可能会导致非常大的响应,从而影响服务器和客户端。例如,一个集群可能有数万个 Pod,每个 Pod 大约相当于 2 KiB 的编码 JSON。检索所有命名空间中的所有 Pod 可能会导致非常大的响应(10-20MB)并消耗大量的服务器资源。

Kubernetes API 服务器支持将单个大型集合请求分解为许多较小的块,同时保持总请求的一致性。每个块可以按顺序返回,从而减少请求的总大小,并允许面向用户的客户端逐步显示结果以提高响应速度。

您可以请求 API 服务器通过分页(Kubernetes 称为 chunks)的方式处理 list 请求。要分块检索单个集合,集合上的请求支持两个查询参数 limitcontinue,并且所有 list 操作都在集合的 metadata 字段中返回一个响应字段 continue。客户端应使用 limit 指定希望在每个块中接收的最大结果数,服务器将在结果中返回最多 limit 个资源,并在集合中还有更多资源时包含一个 continue 值。

作为 API 客户端,您可以将此 continue 值传递给 API 服务器的下一个请求,以指示服务器返回下一页(chunk)的结果。通过继续操作,直到服务器返回一个空的 continue 值,您可以检索整个集合。

watch 操作类似,continue token 在短时间内(默认 5 分钟)后将过期,如果无法返回更多结果,则返回 410 Gone。在这种情况下,客户端需要从头开始或省略 limit 参数。

例如,如果集群上有 1,253 个 Pod,并且您希望一次接收 500 个 Pod 的块,请按如下方式请求这些块

  1. 列出集群上的所有 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
    }
    
  2. 继续之前的调用,检索下一组 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
    }
    
  3. 继续之前的调用,检索最后的 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 token 的单独 list 请求。这允许您将大型请求分解为较小的块,然后对完整集合执行 watch 操作,而不会错过任何更新。

remainingItemCount 是集合中未包含在此响应中的后续项目的数量。如果 list 请求包含标签或字段 选择器,则剩余项目的数量未知,API 服务器不会在其响应中包含 remainingItemCount 字段。如果 list 完成(因为没有分块,或者因为这是最后一个块),则没有剩余项目,API 服务器也不会在其响应中包含 remainingItemCount 字段。remainingItemCount 的预期用途是估计集合的大小。

集合

在 Kubernetes 术语中,从 list 获取的响应是一个 collection。但是,Kubernetes 为不同类型的资源集合定义了具体的种类。集合的种类名称与资源的种类名称相同,并附加了 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 中定义了数十种集合类型(例如 PodListServiceListNodeList)。您可以从 Kubernetes API 文档中获取有关每个集合类型的更多信息。

一些工具,例如 kubectl,以与 Kubernetes API 本身略有不同的方式表示 Kubernetes 集合机制。由于 kubectl 的输出可能包括来自多个 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

表格获取

当您运行 kubectl get 时,默认输出格式是特定资源类型的一个或多个实例的简单表格表示形式。过去,客户端需要重现 kubectl 中实现的表格和描述输出才能执行简单的对象列表。该方法的几个限制包括处理某些对象时逻辑复杂。此外,通过 API 聚合或第三方资源提供的类型在编译时是未知的。这意味着必须为客户端无法识别的类型提供通用实现。

为了避免上述潜在限制,客户端可以请求对象的表格表示形式,将特定的打印细节委托给服务器。Kubernetes API 实现了标准 HTTP 内容类型协商:传递包含 application/json;as=Table;g=meta.k8s.io;v=v1 值的 Accept 头部以及 GET 调用将请求服务器以表格内容类型返回对象。

例如,以表格格式列出集群上的所有 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": [
        ...
    ]
}

对于控制平面未知的自定义表格定义 API 资源类型,API 服务器返回默认的表格响应,其中包含资源的 namecreationTimestamp 字段。

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 资源类型都支持表格响应;例如,CustomResourceDefinitions 可能未定义字段到表格的映射,并且 扩展核心 Kubernetes API 的 APIService 可能根本不提供表格响应。如果您正在实现一个使用表格信息并且必须对所有资源类型(包括扩展)起作用的客户端,则应发出在 Accept 头部中指定多个内容类型的请求。例如

Accept: application/json;as=Table;g=meta.k8s.io;v=v1, application/json

如果客户端指示它仅接受 ...;as=Table;g=meta.k8s.io;v=v1,则不支持表格响应的服务器将返回 406 错误代码。

如果希望回退到完整的对象,客户端可以将 ,application/json(或任何其他受支持的编码)添加到其 Accept 头部,并在响应中处理表格或完整对象。

Accept: application/json;as=Table;g=meta.k8s.io;v=v1,application/json`

有关内容类型协商的更多信息,请参阅 MDN 内容协商

仅元数据获取

要请求部分对象元数据,您可以在 Accept 头部中请求仅元数据响应。Kubernetes API 实现了 HTTP 内容类型协商的变体。作为客户端,您可以提供带有所需媒体类型的 Accept 头部,以及指示您仅需要元数据的参数。例如:Accept: application/json;as=PartialObjectMetadata;g=meta.k8s.io;v=v1 用于 JSON。

例如,列出集群中的所有 Pod,跨所有命名空间,但仅返回每个 Pod 的元数据

GET /api/v1/pods
Accept: application/json;as=PartialObjectMetadata;g=meta.k8s.io;v=v1
---
200 OK
Content-Type: application/json

{
    "kind": "PartialObjectMetadataList",
    "apiVersion": "meta.k8s.io/v1",
    "metadata": {
        "resourceVersion": "...",
    },
    "items": [
        {
            "apiVersion": "meta.k8s.io/v1",
            "kind": "PartialObjectMetadata",
            "metadata": {
                "name": "pod-1",
                ...
            }
        },
        {
            "apiVersion": "meta.k8s.io/v1",
            "kind": "PartialObjectMetadata",
            "metadata": {
                "name": "pod-2",
                ...
            }
        }
    ]
}

对于集合的请求,API 服务器返回 PartialObjectMetadataList。对于单个对象的请求,API 服务器返回对象的 PartialObjectMetadata 表示形式。在两种情况下,返回的对象仅包含 metadata 字段。省略了 specstatus 字段。

此功能对于只需要检查对象是否存在或只需要读取其元数据的客户端非常有用。它可以显著减小来自 API 服务器的响应大小。

您可以为所有可用的媒体类型(JSON、YAML、CBOR 和 Kubernetes Protobuf)请求仅元数据获取。对于 Protobuf,Accept 头部将为 application/vnd.kubernetes.protobuf;as=PartialObjectMetadata;g=meta.k8s.io;v=v1

Kubernetes API 服务器支持其所有内置 API 的部分获取。但是,您可以使用 Kubernetes 通过 聚合层 访问其他 API 服务器,这些 API 可能不支持部分获取。

如果客户端使用 Accept 头部 请求响应 ...;as=PartialObjectMetadata;g=meta.k8s.io;v=v1,并访问不支持部分响应的 API,Kubernetes 将返回 406 HTTP 错误。

如果希望回退到完整的对象,客户端可以将 ,application/json(或任何其他受支持的编码)添加到其 Accept 头部,并在响应中处理 PartialObjectMetadata 或完整对象。使用 qquality)参数指定偏好部分响应是一个好主意。例如

Accept: application/json;as=PartialObjectMetadata;g=meta.k8s.io;v=v1, application/json;q=0.9

有关内容类型协商的更多信息,请参阅 MDN 内容协商

资源删除

当您 删除 资源时,这发生在两个阶段。

  1. 最终化
  2. 删除
{
  "kind": "ConfigMap",
  "apiVersion": "v1",
  "metadata": {
    "finalizers": ["url.io/neat-finalization", "other-url.io/my-finalizer"],
    "deletionTimestamp": nil,
  }
}

当客户端首先发送 delete 请求以请求删除资源时,.metadata.deletionTimestamp 设置为当前时间。一旦设置了 .metadata.deletionTimestamp,对 finalizers 起作用的外部控制器就可以随时以任何顺序开始执行其清理工作。

不强制执行 finalizers 之间的顺序,因为这会给 .metadata.finalizers 卡住带来重大风险。

.metadata.finalizers 字段是共享的:任何具有权限的参与者都可以重新排序它。如果按照列表顺序处理 finalizer 列表,则可能导致以下情况:负责列表中第一个 finalizer 的组件正在等待由负责列表中后续 finalizer 的组件产生的某种信号(字段值、外部系统或其他),从而导致死锁。

在没有强制排序的情况下,finalizer 可以在自身之间自由排序,并且不受列表中的排序更改的影响。

一旦删除了最后一个 finalizer,资源就会从 etcd 中实际删除。

强制删除

功能状态: Kubernetes v1.32 [alpha](默认禁用)

通过启用 delete 选项 ignoreStoreReadErrorWithClusterBreakingPotential,用户可以对无法解密/损坏的资源执行不安全的强制 删除 操作。此选项位于 ALPHA 特性门后,默认情况下已禁用。为了使用此选项,集群操作员必须通过设置命令行选项 --feature-gates=AllowUnsafeMalformedObjectDeletion=true 来启用该特性。

如果由于以下原因而无法从存储中成功检索资源,则该资源被认为已损坏:

  • 转换错误(例如:解密失败),或者
  • 对象解码失败。

API 服务器首先尝试正常删除,如果删除失败并出现损坏的资源错误,则会触发强制删除。强制 删除 操作是不安全的,因为它忽略了 finalizer 约束,并跳过了预条件检查。

此选项的默认值为 false,这保持了向后兼容性。对于将 ignoreStoreReadErrorWithClusterBreakingPotential 设置为 true删除 请求,字段 dryRungracePeriodSecondsorphanDependentspreconditionspropagationPolicy 必须保持未设置状态。

单个资源 API

Kubernetes API 动词 getcreateupdatepatchdeleteproxy 仅支持单个资源。这些支持单个资源的动词不支持以有序或无序列表或事务的形式提交多个资源。

当客户端(包括 kubectl)对一组资源执行操作时,客户端会发出一系列单个资源 API 请求,然后在需要时汇总响应。

与此相反,Kubernetes API 动词 listwatch 允许获取多个资源,而 deletecollection 允许删除多个资源。

字段验证

Kubernetes 始终验证字段的类型。例如,如果 API 中的字段定义为数字,则无法将该字段设置为文本值。如果字段定义为字符串数组,则只能提供数组。某些字段允许省略它们,而其他字段是必需的。从 API 请求中省略必需字段是一个错误。

如果您使用一个包含集群控制平面不识别的额外字段的请求,那么 API 服务器的行为会更加复杂。

默认情况下,API 服务器会删除从接收到的输入中(例如,PUT 请求的 JSON 主体)中不识别的字段。

有两种情况会导致 API 服务器删除您在 HTTP 请求中提供的字段。

这些情况是:

  1. 该字段未被识别,因为它不在资源的 OpenAPI schema 中。(一个例外是 CRDs 显式选择不通过 x-kubernetes-preserve-unknown-fields 剪除未知字段)。
  2. 该字段在对象中重复出现。

对未识别或重复字段的验证

特性状态: Kubernetes v1.27 [稳定](默认启用)

从 1.25 开始,对象中未识别或重复的字段通过使用 HTTP 动词(POSTPUTPATCH)提交数据时,服务器上的验证检测到。

忽略
API 服务器将成功处理请求,就像没有设置错误字段一样,删除所有未知和重复的字段,并且不会指示它已这样做。
警告
(默认)API 服务器将成功处理请求,并向客户端报告警告。警告使用 Warning: 响应头发送,为每个未知或重复的字段添加一个警告项。有关警告和 Kubernetes API 的更多信息,请参阅博客文章 警告:有用的警告即将到来
严格
当 API 服务器检测到任何未知或重复的字段时,将拒绝该请求并返回 400 Bad Request 错误。API 服务器的响应消息将指定 API 服务器检测到的所有未知或重复的字段。

字段验证级别由 fieldValidation 查询参数设置。

向服务器提交请求的工具(例如 kubectl)可能会设置自己的默认值,这些默认值与 API 服务器默认使用的 Warn 验证级别不同。

kubectl 工具使用 --validate 标志来设置字段验证级别。它接受 ignorewarnstrict 值,也接受 true(等效于 strict)和 false(等效于 ignore)值。kubectl 的默认验证设置是 --validate=true,这意味着严格的服务器端字段验证。

当 kubectl 无法连接到具有字段验证的 API 服务器时(Kubernetes 1.27 之前的 API 服务器),它将回退到使用客户端验证。客户端验证将在 kubectl 的未来版本中完全删除。

从 v1.33 开始,Kubernetes(包括 v1.35)提供了一种使用声明性标签定义字段验证的方法。这对于为 Kubernetes 本身做出贡献的人来说很有用,并且如果您使用 Kubernetes 库编写自己的 API,它也适用。要了解更多信息,请参阅 声明性 API 验证

Dry-run(模拟运行)

特性状态: Kubernetes v1.19 [稳定](默认启用)

当您使用可以修改资源的 HTTP 动词(POSTPUTPATCHDELETE)时,您可以以dry run 模式提交您的请求。Dry run 模式有助于评估请求,直到将对象持久化到存储为止,包括典型的请求阶段(准入链、验证、合并冲突)。请求的响应主体尽可能接近于非 dry-run 响应。Kubernetes 保证 dry-run 请求不会持久化到存储中,也不会产生任何其他副作用。

发起 dry-run 请求

通过设置 dryRun 查询参数来触发 dry-run。此参数是一个字符串,作为枚举工作,并且唯一接受的值是:

[未设置值]
允许副作用。您可以使用类似于 ?dryRun?dryRun&pretty=true 的查询字符串来请求此操作。响应是最终将被持久化的对象,或者如果请求无法完成则会出错。
全部
每个阶段都像正常一样运行,除了最终存储阶段,该阶段会防止副作用。

当您设置 ?dryRun=All 时,任何相关的 准入控制器 都会运行,验证准入控制器会在 post-mutation 后检查请求,在 PATCH 上执行合并,字段将被默认化,并且会发生 schema 验证。更改不会持久化到底层存储,但最终将被持久化的对象仍然会返回给用户,以及正常的状态码。

如果非 dry-run 版本的请求会触发具有副作用的准入控制器,则请求将失败,而不是冒着产生不希望的副作用的风险。所有内置的准入控制插件都支持 dry-run。此外,准入 webhook 可以在其 配置对象 中声明它们没有副作用,方法是将 sideEffects 字段设置为 None

这是一个使用 ?dryRun=All 的 dry-run 请求示例:

POST /api/v1/namespaces/test/pods?dryRun=All
Content-Type: application/json
Accept: application/json

响应将与非 dry-run 请求相同,但某些生成字段的值可能会有所不同。

生成的值

对象的某些值通常在对象持久化之前生成。重要的是不要依赖于由 dry-run 请求设置的这些字段的值,因为这些值在 dry-run 模式下与实际请求时可能会不同。其中一些字段是

  • name:如果设置了 generateName,则 name 将具有唯一的随机名称
  • creationTimestamp / deletionTimestamp:记录创建/删除的时间
  • UID唯一标识对象,并随机生成(非确定性)
  • resourceVersion:跟踪对象的持久化版本
  • 由 mutating admission controller 设置的任何字段
  • 对于 Service 资源:kube-apiserver 分配给 Service 对象的端口或 IP 地址

Dry-run 授权

Dry-run 请求和非 Dry-run 请求的授权是相同的。因此,要发出 dry-run 请求,您必须被授权发出非 dry-run 请求。

例如,要运行 Deployment 的 dry-run 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 服务器来 patch 现有资源,而不是发送 PUT 请求。Patch 通常适用于客户端想要进行的更改不依赖于现有数据的情况。需要有效检测丢失更新的客户端应考虑使其请求依赖于现有的 resourceVersion(HTTP PUT 或 HTTP PATCH),然后在发生冲突时处理任何重试。

Kubernetes API 支持四种不同的 PATCH 操作,由其相应的 HTTP Content-Type 标头决定

application/apply-patch+yaml
基于 YAML 的 Server Side Apply YAML(Kubernetes 特定的扩展)。所有 JSON 文档都是有效的 YAML,因此您也可以使用此媒体类型提交 JSON。有关更多详细信息,请参阅 Server Side Apply 序列化。对于 Kubernetes 而言,如果对象不存在,则这是一个 创建 操作;如果对象已存在,则是一个 patch 操作。
application/json-patch+json
JSON Patch,如 RFC6902 中定义。JSON patch 是一系列在资源上执行的操作;例如 {"op": "add", "path": "/a/b/c", "value": [ "foo", "bar" ]}。对于 Kubernetes 而言,这是一个 patch 操作。

使用 application/json-patch+jsonpatch 可以包含条件以验证一致性,如果未满足这些条件,则允许操作失败(例如,以避免丢失更新)。

application/merge-patch+json
JSON Merge Patch,如 RFC7386 中定义。JSON Merge Patch 本质上是资源的局部表示。提交的 JSON 与当前资源组合以创建一个新资源,然后保存新资源。对于 Kubernetes 而言,这是一个 patch 操作。
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 的 Server Side Apply 功能允许控制平面跟踪新创建对象的托管字段。Server Side Apply 提供了一种清晰的模式来管理字段冲突,提供服务器端 applyupdate 操作,并取代了 kubectl apply 的客户端功能。

对于 Server-Side Apply,如果对象尚不存在,Kubernetes 将请求视为 创建,否则视为 patch。对于在 HTTP 级别使用 PATCH 的其他请求,逻辑 Kubernetes 操作始终是 patch

有关更多详细信息,请参阅 Server Side Apply

选择更新机制

HTTP PUT 替换现有资源

更新(HTTP PUT)操作易于实现且灵活,但存在缺点

  • 您需要处理 resourceVersion 在客户端读取对象和尝试将其写回之间发生更改时的冲突。Kubernetes 始终检测到冲突,但您作为客户端作者需要实现重试。
  • 如果您在本地解码对象(例如,使用 client-go,您可能会收到客户端不知道如何处理的字段 - 然后在更新过程中删除它们)。
  • 如果对象(甚至只是您尝试编辑的字段或字段集)存在大量争用,您可能难以发送更新。对于较大的对象和具有许多字段的对象,问题会更严重。

使用 JSON Patch 的 HTTP PATCH

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 对象相关。

资源版本

资源版本是标识服务器内部对象版本的字符串。客户端可以使用资源版本来确定对象何时更改,或在获取、列出和监视资源时表达数据一致性要求。资源版本必须未修改地传回服务器。

资源版本字符串可以在相同资源类型的所有类型(由 kube-apiserver 提供服务)内作为单调递增的整数进行排序。这包括内置 API 类型和由自定义资源定义支持的类型。两个资源版本都必须来自相同的 API 组和资源类型。例如,可以比较来自 apps API 组的两个 Deployment 的资源版本,但不能比较 Pod 和 Deployment。

如果您正在使用由扩展 API 服务器提供的 API 资源,则客户端需要检查资源版本字符串是否解析为十进制数(有关更多详细信息,请参见接下来的几段)。如果两个资源版本字符串中的任何一个都无法解析为十进制数,则可以检查这两个字符串是否相等,但您 不能 依赖于排序的比较。

从 Kubernetes 1.35 开始,所有 Kubernetes 类型的资源版本的可排序性包含在 Certified Kubernetes 要求中。基本 API 对象和自定义资源 必须 能够作为任何 1.35+ APIServer 实现的单调递增整数进行排序,才能通过一致性测试。

为了比较两个资源版本字符串

请确保它们满足以下要求

  • 两个资源版本都必须来自上述相同的资源类型
  • 两者都必须以数字 1-9 开头,并且仅包含数字 0-9
  • 资源版本作为任意位大小的十进制整数进行比较

为了在不依赖于固定位大小的情况下比较它们,可以将它们作为字符串进行比较。不应假定位大小为某个固定量。

可以使用如下所示的词法比较代替

  • 如果它们长度不相等,则较长的那个更大(例如,“123” > “23”)
  • 如果它们长度相等,则词法上较大的那个更大(例如,“234” > “123”)

以下是一些应该有效的资源版本比较示例

  • "2345678901234567890123456789012345678901" > "345678901234567890123456789012345678901"
  • "345678901234567890123456789012345678901" == "345678901234567890123456789012345678901"
  • "345678901234567890123456789012345678900" < "345678901234567890123456789012345678901"

client-go 提供了一个辅助方法来执行此比较:client-go

resourceVersion 字段在元数据中

客户端可以在资源中找到资源版本,包括来自 watch 响应流的资源,或在使用 list 枚举资源时。

v1.meta/ObjectMeta - 资源的 metadata.resourceVersion 标识上次修改资源时的资源版本。

v1.meta/ListMeta - 资源集合的 metadata.resourceVersionlist 的响应)标识构建集合时的资源版本。

查询字符串中的 resourceVersion 参数

getlistwatch 操作支持 resourceVersion 参数。从 v1.19 版本开始,Kubernetes API 服务器还支持 list 请求上的 resourceVersionMatch 参数。

API 服务器会根据您请求的操作以及 resourceVersion 的值,以不同的方式解释 resourceVersion 参数。 如果您设置了 resourceVersionMatch,这也会影响匹配的方式。

getlist 的语义

对于 getlistresourceVersion 的语义是

get

resourceVersion 未设置resourceVersion="0"resourceVersion="{其他于 0 的值}"
最新任意不早于

list

从 v1.19 版本开始,Kubernetes API 服务器支持 list 请求上的 resourceVersionMatch 参数。 如果您同时设置了 resourceVersionresourceVersionMatch,则 resourceVersionMatch 参数决定了 API 服务器如何解释 resourceVersion

list 请求上设置 resourceVersion 时,您应该始终设置 resourceVersionMatch 参数。 但是,请做好准备,以应对响应的 API 服务器不知道 resourceVersionMatch 并忽略它的情况。

除非您有严格的一致性要求,否则使用 resourceVersionMatch=NotOlderThan 和已知的 resourceVersion 更好,因为它比不设置 resourceVersionresourceVersionMatch 能够实现更好的集群性能和可扩展性,后者需要 quorum read 来提供服务。

在不设置 resourceVersion 的情况下设置 resourceVersionMatch 参数是无效的。

下表解释了 resourceVersionresourceVersionMatch 的各种组合下 list 请求的行为

list 的 resourceVersionMatch 和分页参数
resourceVersionMatch 参数分页参数resourceVersion 未设置resourceVersion="0"resourceVersion="{其他于 0 的值}"
未设置limit 未设置最新任意不早于
未设置limit=<n>,continue 未设置最新任意精确
未设置limit=<n>,continue=<token>继续继续无效,HTTP 400 Bad Request
resourceVersionMatch=Exactlimit 未设置无效无效精确
resourceVersionMatch=Exactlimit=<n>,continue 未设置无效无效精确
resourceVersionMatch=NotOlderThanlimit 未设置无效任意不早于
resourceVersionMatch=NotOlderThanlimit=<n>,continue 未设置无效任意不早于

getlist 语义的含义是

任意
以任何资源版本返回数据。 优先选择最新的可用资源版本,但不需要强一致性;可以提供任何资源版本的的数据。 在高可用性配置中,由于分区或陈旧缓存,请求可能会返回比客户端之前观察到的版本更早得多的资源版本。 无法容忍这种情况的客户端不应使用此语义。 始终从 watch cache 提供服务,从而提高性能并减少 etcd 负载。
最新
以最新的资源版本返回数据。 返回的数据必须一致(具体来说:通过 quorum read 从 etcd 提供服务)。 对于 etcd v3.4.31+ 和 v3.5.13+,Kubernetes 1.35 从 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 不可用,服务器将响应 HTTP 410 Gone。 对于支持 resourceVersionMatch 参数的服务器上的 list 请求,这保证了集合的 .metadata.resourceVersion 与您在查询字符串中请求的 resourceVersion 相同。 该保证不适用于该集合中任何项目的 .metadata.resourceVersion。 启用 ListFromCacheSnapshot 功能门后,API 服务器将尝试从快照提供响应(如果可用且 resourceVersion 早于请求的版本)。 这提高了性能并减少了 etcd 负载。 API 服务器从不带快照开始,在每次 watch 事件上创建新的快照,并将其保留直到检测到 etcd 被压缩或缓存已满,事件超过 75 秒。 如果提供的 resourceVersion 不可用,服务器将回退到 etcd。
继续
返回分页列表请求的下一页数据,确保与序列中初始请求建立的精确 resourceVersion 一致。 响应带有 limit 的 list 请求,其中包含 continue token,该 token 编码了 resourceVersion 和上次观察到的恢复列表的位置。 如果提供的 continue token 中的 resourceVersion 不可用,服务器将响应 HTTP 410 Gone。 启用 ListFromCacheSnapshot 功能门后,API 服务器将尝试从快照提供响应(如果可用且 resourceVersion 早于请求的版本)。 这提高了性能并减少了 etcd 负载。 API 服务器从不带快照开始,在每次 watch 事件上创建新的快照,并将其保留直到检测到 etcd 被压缩或缓存已满,事件超过 75 秒。 如果提供的 continue token 中的 resourceVersion 不可用,服务器将回退到 etcd。

当使用 resourceVersionMatch=NotOlderThan 并且设置了 limit 时,客户端必须处理 HTTP 410 Gone 响应。 例如,客户端可以重试使用更新的 resourceVersion,或者回退到 resourceVersion=""

当使用 resourceVersionMatch=Exact 并且 limit 未设置时,客户端必须验证集合的 .metadata.resourceVersion 是否与请求的 resourceVersion 匹配,并处理不匹配的情况。 例如,客户端可以回退到设置了 limit 的请求。

watch 的语义

对于 watch,资源版本语义是

watch

watch 的 resourceVersion
resourceVersion 未设置resourceVersion="0"resourceVersion="{其他于 0 的值}"
获取状态并从最新开始获取状态并从任意开始从精确开始

这些 watch 语义的含义是

获取状态并从任意开始
从任何资源版本开始 watch; 优先选择最新的可用资源版本,但不是必需的。 允许任何起始资源版本。 在高可用性配置中,由于分区或陈旧缓存,watch 可能会从客户端之前观察到的版本更早的版本开始。 无法容忍这种明显倒退的客户端不应使用此语义启动 watch。 为了建立初始状态,watch 从所有存在于起始资源版本上的资源实例的合成“Added”事件开始。 之后的所有 watch 事件都是针对在 watch 开始的资源版本之后发生的所有更改。
获取状态并从最新开始
从最新的资源版本开始 watch,必须一致(具体来说:通过 quorum read 从 etcd 提供服务)。 为了建立初始状态,watch 从所有存在于起始资源版本上的资源实例的合成“Added”事件开始。 之后的所有 watch 事件都是针对在 watch 开始的资源版本之后发生的所有更改。
从精确开始
从确切的资源版本开始 watch。 watch 事件是针对提供的资源版本之后发生的所有更改。 与“获取状态并从最新开始”和“获取状态并从任意开始”不同,watch 不会从提供的资源版本的合成“Added”事件开始。 假设客户端已经拥有起始资源版本上的初始状态,因为客户端提供了资源版本。

“410 Gone”响应

服务器不需要提供所有旧的资源版本,如果客户端请求的 resourceVersion 早于服务器保留的版本,则可能会返回 HTTP 410 (Gone) 状态码。 客户端必须能够容忍 410 (Gone) 响应。 有关如何处理监视资源时 410 (Gone) 响应的详细信息,请参阅 高效检测更改

如果您请求的 resourceVersion 超出适用限制,那么,根据请求是从缓存提供服务还是从非缓存提供服务,API 服务器可能会用 410 Gone HTTP 响应回复您。

不可用的资源版本

服务器不需要提供未识别的资源版本。 如果您请求 listget 具有 API 服务器不识别的资源版本,则 API 服务器可能会

  • 短暂等待资源版本可用,然后在提供的资源版本在合理的时间内不可用时,超时并显示 504 (Gateway Timeout)
  • 使用 Retry-After 响应标头进行响应,指示客户端应在重试请求之前等待的秒数。

如果您请求 API 服务器不识别的资源版本,kube-apiserver 还会使用消息 Too large resource version 标识其错误响应。

如果您对未识别的资源版本发出 watch 请求,API 服务器可能会无限期地等待(直到请求超时),直到资源版本可用为止。