diff --git a/content/zh/docs/reference/using-api/api-concepts.md b/content/zh/docs/reference/using-api/api-concepts.md index 4637ef108f..bf31ae7a78 100644 --- a/content/zh/docs/reference/using-api/api-concepts.md +++ b/content/zh/docs/reference/using-api/api-concepts.md @@ -15,70 +15,159 @@ weight: 20 -本页描述 Kubernetes API 的通用概念。 +The Kubernetes API is a resource-based (RESTful) programmatic interface +provided via HTTP. It supports retrieving, creating, updating, and deleting +primary resources via the standard HTTP verbs (POST, PUT, PATCH, DELETE, +GET). - - -Kubernetes API 是基于资源的(RESTful)、通过 HTTP 提供的编程接口。 -API 支持通过标准的 HTTP 动词(POST、PUT、PATCH、DELETE 和 GET) -检视、创建、更新和删除主要资源,为很多允许细粒度权限控制的对象提供子资源 -(如将 Pod 绑定到节点上),并且出于便利性或效率考虑,支持并提供这些资源的 -不同表示形式。 -Kubernetes API 还通过 "watch" 和一致性的列表支持高效的资源变更通知, -从而允许其他组件对资源的状态进行高效的缓存和同步。 +Kubernetes API 是通过 HTTP 提供的基于资源 (RESTful) 的编程接口。 +它支持通过标准 HTTP 动词(POST、PUT、PATCH、DELETE、GET)检索、创建、更新和删除主要资源。 + +对于某些资源,API 包括额外的子资源,允许细粒度授权(例如将 Pod 的查看详细信息与检索其日志分开), +为了方便或者提高效率,可以以不同的表示形式接受和服务这些资源。 -## 标准 API 术语 {#standard-api-terminology} +Kubernetes 支持通过 **watchs** 实现高效的资源变更通知。 +Kubernetes 还提供了一致的列表操作,以便 API 客户端可以有效地缓存、跟踪和同步资源的状态。 +你可以在线查看 [API 参考](/zh/docs/reference/kubernetes-api/), +或继续阅读以了解 API 的一般信息。 + + +## Kubernetes API 术语 {#standard-api-terminology} + +Kubernetes 通常使用常见的 RESTful 术语来描述 API 概念: +* **资源类型(Resource Type)** 是 URL 中使用的名称(`pods`、`namespaces`、`services`) +* 所有资源类型都有一个具体的表示(它们的对象模式),称为 **类别(Kind)** +* 资源实例的列表称为 **集合(Collection)** +* 资源类型的单个实例称为 **资源(Resource)**,通常也表示一个 **对象(Object)** +* 对于某些资源类型,API 包含一个或多个 **子资源(sub-resources)**,这些子资源表示为资源下的 URI 路径 + + 大多数 Kubernetes API 资源类型都是 [对象](/zh/docs/concepts/overview/working-with-objects/kubernetes-objects/#kubernetes-objects): -它们代表的是集群中某一概念的具体实例,例如一个 Pod 或名字空间。 -为数不多的几个 API 资源类型是“虚拟的” - 它们通常代表的是操作而非对象本身, -例如访问权限检查(使用 POST 请求发送一个 JSON 编码的 `SubjectAccessReview` -负载到 `subjectaccessreviews` 资源)。 -所有对象都有一个唯一的名字,以便支持幂等的创建和检视操作,不过如果虚拟资源类型 -不可检视或者不要求幂等,可以不具有唯一的名字。 +它们代表集群上某个概念的具体实例,例如 Pod 或命名空间。 +少数 API 资源类型是 “虚拟的”,它们通常代表的是操作而非对象本身, +例如权限检查(使用带有 JSON 编码的 `SubjectAccessReview` 主体的 POST 到 `subjectaccessreviews` 资源), +或 Pod 的子资源 `eviction`(用于触发 [API-发起的驱逐](/zh/docs/concepts/scheduling-eviction/api-eviction/))。 -Kubernetes 一般会利用标准的 RESTful 术语来描述 API 概念: -* **资源类型(Resource Type)** 是在 URL 中使用的名称(`pods`、`namespaces`、`services`) -* 所有资源类型都有具有一个 JSON 形式(其对象的模式定义)的具体表示,称作**类别(Kind)** -* 某资源类型的实例的列表称作 **集合(Collection)** -* 资源类型的单个实例被称作 **资源(Resource)** +### 对象名字 {#object-names} + +你可以通过 API 创建的所有对象都有一个唯一的{{< glossary_tooltip text="名字" term_id="name" >}}, +以允许幂等创建和检索, +但如果虚拟资源类型不可检索或不依赖幂等性,则它们可能没有唯一名称。 +在{{< glossary_tooltip text="命名空间" term_id="namespace" >}}内, +同一时刻只能有一个给定类别的对象具有给定名称。 +但是,如果你删除该对象,你可以创建一个具有相同名称的新对象。 +有些对象没有命名空间(例如:节点),因此它们的名称在整个集群中必须是唯一的。 +### API 动词 {#api-verbs} + +几乎所有对象资源类型都支持标准 HTTP 动词 - GET、POST、PUT、PATCH 和 DELETE。 +Kubernetes 也使用自己的动词,这些动词通常写成小写,以区别于 HTTP 动词。 + +Kubernetes 使用术语 **list** 来描述返回资源[集合](#collections), +以区别于通常称为 **get** 的单个资源检索。 +如果你发送带有 `?watch` 查询参数的 HTTP GET 请求, +Kubernetes 将其称为 **watch** 而不是 **get**(有关详细信息,请参阅[快速检测更改](#efficient-detection-of-changes))。 + +对于 PUT 请求,Kubernetes 在内部根据现有对象的状态将它们分类为 **create** 或 **update**。 +**update** 不同于 **patch**;**patch** 的 HTTP 动词是 PATCH。 + + +## 资源 URI {#resource-uris} 所有资源类型要么是集群作用域的(`/apis/GROUP/VERSION/*`),要么是名字空间 作用域的(`/apis/GROUP/VERSION/namespaces/NAMESPACE/*`)。 名字空间作用域的资源类型会在其名字空间被删除时也被删除,并且对该资源类型的 访问是由定义在名字空间域中的授权检查来控制的。 -下列路径用来检视集合和资源: + +你还可以访问资源集合(例如:列出所有 Node)。以下路径用于检索集合和资源: + * 集群作用域的资源: * `GET /apis/GROUP/VERSION/RESOURCETYPE` - 返回指定资源类型的资源的集合 @@ -89,54 +178,73 @@ All resource types are either scoped by the cluster (`/apis/GROUP/VERSION/*`) or * `GET /apis/GROUP/VERSION/namespaces/NAMESPACE/RESOURCETYPE/NAME` - 返回名字空间 NAMESPACE 中给定资源类型的名称为 NAME 的实例 由于名字空间本身是一个集群作用域的资源类型,你可以通过 `GET /api/v1/namespaces/` -检视所有名字空间的列表,使用 `GET /api/v1/namespaces/NAME` 查看特定名字空间的 +检视所有名字空间的列表(“集合”),使用 `GET /api/v1/namespaces/NAME` 查看特定名字空间的 详细信息。 -几乎所有对象资源类型都支持标准的 HTTP 动词 - GET、POST、PUT、PATCH 和 DELETE。 -Kubernetes 使用术语 **list** 来描述返回资源集合的操作,以便与返回单个资源的、 -通常称作 **get** 的操作相区分。 - -某些资源类型有一个或多个子资源(Sub-resource),表现为对应资源下面的子路径: - * 集群作用域的子资源:`GET /apis/GROUP/VERSION/RESOURCETYPE/NAME/SUBRESOURCE` * 名字空间作用域的子资源:`GET /apis/GROUP/VERSION/namespaces/NAMESPACE/RESOURCETYPE/NAME/SUBRESOURCE` -取决于对象是什么,每个子资源所支持的动词有所不同 - 参见 API 文档以了解更多信息。 +取决于对象是什么,每个子资源所支持的动词有所不同 - 参见 [API 文档](/zh/docs/reference/kubernetes-api/)以了解更多信息。 跨多个资源来访问其子资源是不可能的 - 如果需要这一能力,则通常意味着需要一种 新的虚拟资源类型了。 ## 高效检测变更 {#efficient-detection-of-changes} -为了使客户端能够构造一个模型来表达集群的当前状态,所有 Kubernetes 对象资源类型 -都需要支持一致的列表和一个称作 **watch** 的增量变更通知信源(feed)。 -每个 Kubernetes 对象都有一个 `resourceVersion` 字段,代表该资源在下层数据库中 -存储的版本。检视资源集合(名字空间作用域或集群作用域)时,服务器返回的响应 -中会包含 `resourceVersion` 值,可用来向服务器发起 watch 请求。 -服务器会返回所提供的 `resourceVersion` 之后发生的所有变更(创建、删除和更新)。 -这使得客户端能够取回当前的状态并监视其变更,且不会错过任何变更事件。 -客户端的监视连接被断开时,可以从最后返回的 `resourceVersion` 重启新的监视连接, -或者执行一个新的集合请求之后从头开始监视操作。 -参阅[资源版本语义](#resource-versions)以了解更多细节。 +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** 请求并重新开始。有关更多详细信息,请参阅[资源版本语义](#resource-versions)。 例如: @@ -159,11 +267,17 @@ For example: ``` -2. 从资源版本 10245 开始,以 JSON 对象的形式接收所有创建、删除或更新操作的通知: +2. 从资源版本 10245 开始,接收影响 _test_ 命名空间中 Pod 的所有 API 操作 + (例如 **create**、**delete**、**apply** 或 **update**)的通知。 + 每个更改通知都是一个 JSON 文档。 + HTTP 响应正文(用作 `application/json`)由一系列 JSON 文档组成。 - ```console + ``` GET /api/v1/namespaces/test/pods?watch=1&resourceVersion=10245 --- 200 OK @@ -182,28 +296,41 @@ For example: ``` 给定的 Kubernetes 服务器只会保留一定的时间内发生的历史变更列表。 使用 etcd3 的集群默认保存过去 5 分钟内发生的变更。 -当所请求的 watch 操作因为资源的历史版本不存在而失败,客户端必须能够处理 -因此而返回的状态代码 `410 Gone`,清空其本地的缓存,重新执行 list 操作, -并基于新的 list 操作所返回的 `resourceVersion` 来开始新的 watch 操作。 -大多数客户端库都能够提供某种形式的、包含此逻辑的工具。 -(在 Go 语言客户端库中,这一设施称作 `Reflector`,位于 -`k8s.io/client-go/cache` 包中。) +当所请求的 **watch** 操作因为资源的历史版本不存在而失败, +客户端必须能够处理因此而返回的状态代码 `410 Gone`,清空其本地的缓存, +重新执行 **get** 或者 **list** 操作, +并基于新返回的 `resourceVersion` 来开始新的 **watch** 操作。 + +对于订阅集合,Kubernetes 客户端库通常会为 **list** -然后- **watch** 的逻辑提供某种形式的标准工具。 +(在 Go 客户端库中,这称为`反射器(Reflector)`,位于 `k8s.io/client-go/tools/cache` 包中。) ### 监视书签 {#Watch-bookmark} -为了处理历史窗口过短的问题,我们引入了 `bookmark(书签)` 监视事件的概念。 -该事件是一种特殊事件,用来标示客户端所请求的、指定的 `resourceVersion` 之前 -的所有变更都以被发送。该事件中返回的对象是所请求的资源类型,但其中仅包含 -`resourceVersion` 字段,例如: +为了减轻短历史窗口的影响,Kubernetes API 提供了一个名为 `BOOKMARK` 的监视事件。 +这是一种特殊的事件,用于标记客户端请求的给定 `resourceVersion` 的所有更改都已发送。 +代表 `BOOKMARK` 事件的文档属于请求所请求的类型,但仅包含一个 `.metadata.resourceVersion` 字段。例如: ```console GET /api/v1/namespaces/test/pods?watch=1&resourceVersion=10245&allowWatchBookmarks=true @@ -224,11 +351,13 @@ Content-Type: application/json ``` -通过在 watch 请求中设置 `allowWatchBookmarks=true` 选项,可以请求 `bookmark` -事件,但是客户端不能假定服务器端会按某特定时间间隔返回书签事件,甚至也不能 -假定服务器一定会发送 `bookmark` 事件。 +作为客户端,你可以在 **watch** 请求中设置 `allowWatchBookmarks=true` 查询参数来请求 `BOOKMARK` 事件, +但你不应假设书签会在任何特定时间间隔返回,即使要求时,客户端也不能假设 API 服务器会发送任何 `BOOKMARK` 事件。 -在较大规模的集群中,检视某些资源类型的集合时可能会返回较大体量的响应数据,对 -服务器和客户端都会造成影响。例如,某集群可能包含数万个 Pod,每个 Pod 的 JSON -编码都有 1-2 KB 的大小。返回所有名字空间的全部 Pod 时,其结果可能体量很大 -(10-20 MB)且耗用大量的服务器资源。 -从 Kubernetes 1.9 开始,服务器支持将单一的大体量集合请求分解成多个小数据块 -同时还保证整个请求的一致性的能力。 -各个数据块可以按顺序返回,进而降低请求的尺寸,允许面向用户的客户端以增量形式 -呈现返回结果,改进系统响应效果。 +在较大规模集群中,检索某些资源类型的集合可能会导致非常大的响应,从而影响服务器和客户端。 +例如,一个集群可能有数万个 Pod,每个 Pod 大约相当于 2 KiB 的编码 JSON。 +跨所有命名空间检索所有 Pod 可能会导致非常大的响应 (10-20MB) 并消耗大量服务器资源。 -为了用分块的形式返回一个列表,集合请求上可以设置两个新的参数 `limit` 和 -`continue`,并且所有 list 操作的返回结果列表的 `metadata` 字段中会包含一个 -新的 `continue` 字段。 -客户端应该将 `limit` 设置为希望在每个数据块中收到的结果个数上限,而服务器则 -会在结果中至多返回 `limit` 个资源并在集合中还有更多资源的时候包含一个 -`continue` 值。客户端在下次请求时则可以将此 `continue` 值传递给服务器, -告知后者要从何处开始返回结果的下一个数据块。 -通过重复这一操作直到服务器端返回空的 `continue` 值,客户端可以受到结果的 -全集。 +如果你没有明确禁用 `APIListChunking` [特性门控](/zh/docs/reference/command-line-tools-reference/feature-gates/), +Kubernetes API 服务器支持将单个大型集合请求分解为许多较小块的能力,同时保持总请求的一致性。 -与 watch 操作类似,`continue` 令牌也会在很短的时间(默认为 5 分钟)内过期, +你可以请求 API 服务器通过使用页(Kubernetes 将其称为“块(Chunk)”)的方式来处理 **list**, +完成单个集合的响应。 +要以块的形式检索单个集合,针对集合的请求支持两个查询参数 `limit` 和 `continue`, +并且从集合元 `metadata` 字段中的所有 **list** 操作返回响应字段 `continue`。 +客户端应该指定他们希望在每个带有 `limit` 的块中接收的条目数上限,如果集合中有更多资源, +服务器将在结果中返回 `limit` 资源并包含一个 `continue` 值。 + + +作为 API 客户端,你可以在下一次请求时将 `continue` 值传递给 API 服务器, +以指示服务器返回下一页(_块_)结果。继续下去直到服务器返回一个空的 `continue` 值, +你可以检索整个集合。 + + +与 **watch** 操作类似,`continue` 令牌也会在很短的时间(默认为 5 分钟)内过期, 并在无法返回更多结果时返回 `410 Gone` 代码。 这时,客户端需要从头开始执行上述检视操作或者忽略 `limit` 参数。 -例如,如果集群上有 1253 个 Pods,客户端希望每次收到包含至多 500 个 Pod 的 +例如,如果集群上有 1253 个 Pod,客户端希望每次收到包含至多 500 个 Pod 的 数据块,它应按下面的步骤来请求数据块: 1. 列举集群中所有 Pod,每次接收至多 500 个 Pods: -```console -GET /api/v1/pods?limit=500 ---- -200 OK -Content-Type: application/json + ```console + GET /api/v1/pods?limit=500 + --- + 200 OK + Content-Type: application/json -{ - "kind": "PodList", - "apiVersion": "v1", - "metadata": { - "resourceVersion":"10245", - "continue": "ENCODED_CONTINUE_TOKEN", - ... - }, - "items": [...] // returns pods 1-500 -} -``` + { + "kind": "PodList", + "apiVersion": "v1", + "metadata": { + "resourceVersion":"10245", + "continue": "ENCODED_CONTINUE_TOKEN", + ... + }, + "items": [...] // returns pods 1-500 + } + ``` 2. 继续前面的调用,返回下一组 500 个 Pods: -```console -GET /api/v1/pods?limit=500&continue=ENCODED_CONTINUE_TOKEN ---- -200 OK -Content-Type: application/json + ```console + 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", - ... - }, - "items": [...] // returns pods 501-1000 -} -``` + { + "kind": "PodList", + "apiVersion": "v1", + "metadata": { + "resourceVersion":"10245", + "continue": "ENCODED_CONTINUE_TOKEN_2", + ... + }, + "items": [...] // returns pods 501-1000 + } + ``` 3. 继续前面的调用,返回最后 253 个 Pods: -```console -GET /api/v1/pods?limit=500&continue=ENCODED_CONTINUE_TOKEN_2 ---- -200 OK -Content-Type: application/json + ```console + 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 将不会显示, +除非你在没有继续令牌的情况下发出单独的 **list** 请求。 +这使你可以将大请求分成更小的块,然后对整个集合执行 **watch** 操作,而不会丢失任何更新。 + + +`remainingItemCount` 是集合中未包含在此响应中的后续项目的数量。 +如果 **list** 请求包含标签或字段{{< glossary_tooltip text="选择器" term_id="selector">}} , +则剩余项目的数量是未知的,并且 API 服务器在其响应中不包含 `remainingItemCount` 字段。 +如果 **list** 是完整的(因为它没有分块,或者因为这是最后一个块),没有更多的剩余项目, +API 服务器在其响应中不包含 `remainingItemCount` 字段。 +`remainingItemCount` 的用途是估计集合的大小。 + + +## 集合 {#collections} + +在 Kubernetes 术语中,你从 **list** 中获得的响应是一个“集合(Collections)”。 +然而,Kubernetes 为不同类型资源的集合定义了具体类型。 +集合的类别名是针对资源类别的,并附加了 `List`。 + +当你查询特定类型的 API 时,该查询返回的所有项目都属于该类型。 +例如,当你 **list** Service 对象时,集合响应的 `kind` 设置为 +[`ServiceList`](/zh/docs/reference/kubernetes-api/service-resources/service-v1/#ServiceList); +该集合中的每个项目都代表一个 Service。例如: + +``` +GET /api/v1/services +``` +```yaml { - "kind": "PodList", + "kind": "ServiceList", "apiVersion": "v1", "metadata": { - "resourceVersion":"10245", - "continue": "", // continue token is empty because we have reached the end of the list - ... + "resourceVersion": "2947301" }, - "items": [...] // returns pods 1001-1253 -} + "items": [ + { + "metadata": { + "name": "kubernetes", + "namespace": "default", +... + "metadata": { + "name": "kube-dns", + "namespace": "kube-system", +... ``` -注意 list 操作的 `resourceVersion` 在每个请求中都设置的是同一个数值, -这表明服务器要向我们展示一个一致的 Pods 快照视图。 -在版本 `10245` 之后创建、更新或删除的 Pods 都不会显示出来,除非用户发出 -list 请求时不指定 `continue` 令牌。 -这一设计使得客户端能够将较大的响应切分为较小的数据块,且能够对较大的集合 -执行监视动作而不会错失任何更新事件。 +Kubernetes API 中定义了数十种集合类型(如 `PodList`、`ServiceList` 和 `NodeList`)。 +你可以从 [Kubernetes API](/zh/docs/reference/kubernetes-api/) 文档中获取有关每种集合类型的更多信息。 + +一些工具,例如 `kubectl`,对于 Kubernetes 集合的表现机制与 Kubernetes API 本身略有不同。 +因为 `kubectl` 的输出可能包含来自 API 级别的多个 **list** 操作的响应, +所以 `kubectl` 使用 `kind: List` 表示项目列表。例如: + +```shell +kubectl get services -A -o yaml +``` +```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 +``` + + +{{< note >}} +请记住,Kubernetes API 没有名为 `List` 的 `kind`。 + +`kind: List` 是一个客户端内部实现细节,用于处理可能属于不同类别的对象的集合。 +在自动化或其他代码中避免依赖 `kind: List`。 +{{< /note >}} ## 以表格形式接收资源 {#receiving-resources-as-tables} -`kubectl get` 命令的输出是一个包含一个或多个资源的简单表格形式。 +当你执行`kubectl get` 时,默认的输出格式是特定资源类型的一个或多个实例的简单表格形式。 过去,客户端需要重复 `kubectl` 中所实现的表格输出和描述输出逻辑,以执行 简单的对象列表操作。 -这一方法在处理某些对象时,需要引入不容忽视的逻辑。 -此外,[API 聚合](/zh/docs/concepts/extend-kubernetes/api-extension/apiserver-aggregation/) -和[定制资源](/zh/docs/concepts/extend-kubernetes/api-extension/custom-resources/) -所提供的资源类型都是编译时不可预知的。这意味着,客户端必须针对无法 -识别的类型提供通用的实现逻辑。 +该方法的一些限制包括处理某些对象时的不可忽视逻辑。 +此外,API 聚合或第三方资源提供的类型在编译时是未知的。 +这意味着必须为客户端无法识别的类型提供通用实现。 为了避免上述各种潜在的局限性,客户端可以请求服务器端返回对象的表格(Table) 表现形式,从而将打印输出的特定细节委托给服务器。 Kubernetes API 实现标准的 HTTP 内容类型(Content Type)协商:为 `GET` 调用 -传入一个值为 `application/json;as=Table;g=meta.k8s.io;v=v1beta1` 的 `Accept` +传入一个值为 `application/json;as=Table;g=meta.k8s.io;v=v1` 的 `Accept` 头部即可请求服务器以 Table 的内容类型返回对象。 例如,以 Table 格式列举集群中所有 Pods: ```console GET /api/v1/pods -Accept: application/json;as=Table;g=meta.k8s.io;v=v1beta1 +Accept: application/json;as=Table;g=meta.k8s.io;v=v1 --- 200 OK Content-Type: application/json { "kind": "Table", - "apiVersion": "meta.k8s.io/v1beta1", + "apiVersion": "meta.k8s.io/v1", ... "columnDefinitions": [ ... @@ -409,11 +703,11 @@ Content-Type: application/json ``` -对于在服务器上不存在定制的 Table 定义的 API 资源类型而言,服务器会返回 +对于在控制平面上不存在定制的 Table 定义的 API 资源类型而言,服务器会返回 一个默认的 Table 响应,其中包含资源的 `name` 和 `creationTimestamp` 字段。 ```console @@ -425,7 +719,7 @@ Content-Type: application/json { "kind": "Table", - "apiVersion": "meta.k8s.io/v1beta1", + "apiVersion": "meta.k8s.io/v1", ... "columnDefinitions": [ { @@ -443,45 +737,65 @@ Content-Type: application/json ``` -`kube-apiserver` 从 1.10 版本开始提供 Table 响应。 -因此,并非所有 API 资源类型都支持 Table 响应,尤其是使用客户端访问较老的集群时。 -如果客户端需要能够处理所有资源类型,或者有可能需要与较老的集群交互, -则需要在其 `Accept` 头部设定多个内容类型值,以便可以回退到非表格形式的 JSON -表示。 +并非所有 API 资源类型都支持 Table 响应; +例如,{{< glossary_tooltip term_id="CustomResourceDefinition" text="CustomResourceDefinitions" >}} 可能没有定义字段到表的映射, +[扩展核心 Kubernetes API](/zh/docs/concepts/extend-kubernetes/api-extension/apiserver-aggregation/) +的 APIService 可能根本不提供 Table 响应。 +如果你正在实现使用 Table 信息并且必须针对所有资源类型(包括扩展)工作的客户端, +你应该在 `Accept` 请求头中指定多种内容类型的请求。例如: ``` -Accept: application/json;as=Table;g=meta.k8s.io;v=v1beta1, application/json +Accept: application/json;as=Table;g=meta.k8s.io;v=v1, application/json ``` ## 资源的其他表示形式 {#alternate-representations-of-resources} -默认情况下,Kubernetes 返回 JSON 序列化的的对象并设定内容类型为 -`application/json`。这是 API 的默认序列化格式。 -不过,客户端也可出于大规模环境中更佳性能的需求而请求对象的更为高效的 Protobuf -表现形式。 -Kubernetes API 实现了标准的 HTTP 内容类型协商:为 `GET` 调用传递一个 `Accept` -头部来请求服务器以所指定的内容类型返回对象,同时在通过 `PUT` 或 `POST` 调用 -向服务器发送 Protobuf 格式的对象时提供 `Content-Type` 头部。 -服务器会能够支持所请求的格式时返回 `Content-Type` 头部,并在所提供的内容类型 -不合法时返回 `406 Not acceptable(无法接受)` 错误。 +默认情况下,Kubernetes 返回序列化为 JSON 的对象,内容类型为 `application/json`。 +这是 API 的默认序列化格式。 +但是,客户端可能会使用更有效的 [Protobuf 表示](#protobuf-encoding) 请求这些对象, +以获得更好的大规模性能。 Kubernetes API 实现标准的 HTTP 内容类型协商: +带有 `Accept` 请求头部的 `GET` 调用会请求服务器尝试以你的首选媒体类型返回响应, +而将 Protobuf 中的对象发送到服务器以进行 `PUT` 或 `POST` 调用意味着你必须适当地设置 +`Content-Type` 请求头。 -请参阅 API 文档了解每个 API 所支持的内容类型。 + +如果支持请求的格式,服务器将返回带有 `Content-Type` 标头的响应, +如果不支持你请求的媒体类型,则返回 `406 Not Acceptable` 错误。 +所有内置资源类型都支持 `application/json` 媒体类型。 + +有关每个 API 支持的内容类型列表,请参阅 Kubernetes [API 参考](/zh/docs/reference/kubernetes-api/)。 例如: @@ -490,59 +804,68 @@ Kubernetes API 实现了标准的 HTTP 内容类型协商:为 `GET` 调用传 --> 1. 以 Protobuf 格式列举集群上的所有 Pods: -```console -GET /api/v1/pods -Accept: application/vnd.kubernetes.protobuf ---- -200 OK -Content-Type: application/vnd.kubernetes.protobuf + ```console + GET /api/v1/pods + Accept: application/vnd.kubernetes.protobuf + --- + 200 OK + Content-Type: application/vnd.kubernetes.protobuf -... binary encoded PodList object -``` + ... binary encoded PodList object + ``` 2. 通过向服务器发送 Protobuf 编码的数据创建 Pod,但请求以 JSON 形式接收响应: -```console -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 + ```console + 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", - ... -} -``` + { + "kind": "Pod", + "apiVersion": "v1", + ... + } + ``` -并非所有 API 资源类型都支持 Protobuf,尤其是那些通过定制资源定义(CRD)或通过 -API 扩展而加入的资源。如果客户端必须能够处理所有资源类型,则应在其 `Accept` -头部指定多种内容类型以便可以回退到 JSON 格式: +并非所有 API 资源类型都支持 Protobuf;具体来说, +Protobuf 不适用于定义为 {{< glossary_tooltip term_id="CustomResourceDefinition" text="CustomResourceDefinitions" >}} +或通过{{< glossary_tooltip text="聚合层" term_id="aggregation-layer" >}}提供服务的资源。 +作为客户端,如果你可能需要使用扩展类型,则应在请求 `Accept` 请求头中指定多种内容类型以支持回退到 JSON。 +例如: ```console Accept: application/vnd.kubernetes.protobuf, application/json ``` -### Protobuf encoding +### Kubernetes Protobuf encoding {#protobuf-encoding} Kubernetes 使用封套形式来对 Protobuf 响应进行编码。 封套外层由 4 个字节的特殊数字开头,便于从磁盘文件或 etcd 中辩识 Protobuf @@ -612,22 +935,34 @@ An encoded Protobuf message with the following IDL: ``` +{{< note >}} 收到 `application/vnd.kubernetes.protobuf` 格式响应的客户端在响应与预期的前缀 不匹配时应该拒绝响应,因为将来的版本可能需要以某种不兼容的方式更改序列化格式, 并且这种更改是通过变更前缀完成的。 +{{< /note >}} ## 资源删除 {#resource-deletion} -资源删除要经过两个阶段:1) 终止(finalization),和 2)去除。 +当你 **delete** 资源时,操作将分两个阶段进行。 -```json +1. 终结(finalization) +2. 移除 + + +```yaml { "kind": "ConfigMap", "apiVersion": "v1", @@ -639,56 +974,63 @@ Resources are deleted in two phases: 1) finalization, and 2) removal. ``` -当客户端首先删除某资源时,其 `.metadata.deletionTimestamp` 会被设置为当前时间。 -一旦 `.metadata.deletionTimestamp` 被设置,则对终结器(finalizers)执行动作 -的外部控制器就可以在任何时候、以任何顺序执行其清理工作。 -这里不强调顺序是因为很可能带来 `.metadata.finalizers` 被锁定的风险。 -`.metadata.finalizers` 是一个共享的字段,任何具有相关权限的主体都可以对其 -执行重排序的操作。如果终结器列表要按顺序处理,则很可能导致负责列表中第一个 -终结器的组件要等待负责列表中排序靠后的终结器的组件的信号(可能是字段值变更、 -外部系统或者其他形式),从而导致死锁行为。 -在不对终结器顺序作强制要求的情况下,终结器可以自行排序,且不会因为其在列表 -中的顺序而引入任何不稳定因素。 +当客户端第一次发送 **delete** 请求删除资源时,`.metadata.deletionTimestamp` 设置为当前时间。 +一旦设置了 `.metadata.deletionTimestamp`, +作用于终结器的外部控制器可以在任何时间以任何顺序开始执行它们的清理工作。 + +终结器之间 **不存在** 强制的执行顺序,因为这会带来卡住 `.metadata.finalizers` 的重大风险。 + +`.metadata.finalizers` 字段是共享的:任何有权限的参与者都可以重新排序。 +如果终结器列表是按顺序处理的,那么这可能会导致这样一种情况: +在列表中负责第一个终结器的组件正在等待列表中稍后负责终结器的组件产生的某些信号 +(字段值、外部系统或其他),从而导致死锁。 + +如果没有强制排序,终结者可以在它们之间自由排序,并且不易受到列表中排序变化的影响。 当最后一个终结器也被移除时,资源才真正从 etcd 中移除。 ## 单个资源 API {#single-resource-api} -API 动词 GET、CREATE、UPDATE、PATCH、DELETE 和 PROXY 仅支持单个资源。 -这些支持单一资源的动词不支持以有序或无序列表甚或事务的形式同时提交给 -多个资源。 -包括 kubectl 在内的客户端将解析资源的列表,并执行单一资源的 API 请求。 +Kubernetes API 动词 **get**、**create**、**apply**、**update**、**patch**、**delete** 和 **proxy** 仅支持单一资源。 +这些具有单一资源支持的动词不支持在有序或无序列表或事务中一起提交多个资源。 -API 动词 LIST 和 WATCH 支持获取多个资源,而 DELETECOLLECTION 支持删除多个 -资源。 +当客户端(包括 kubectl)对一组资源进行操作时,客户端会发出一系列单资源 API 请求, +然后在需要时聚合响应。 + +相比之下,Kubernetes API 动词 **list** 和 **watch** 允许获取多个资源, +而 **deletecollection** 允许删除多个资源。 -修改性质的动词(`POST`、`PUT`、`PATCH` 和 `DELETE`)可以支持 _试运行(dry -run)_ 模式的请求。试运行模式可帮助通过典型的请求阶段(准入控制链、合法性 -检查、合并冲突)来评估请求,只是最终的对象不会写入存储。请求的响应主体与 -非试运行模式下的响应尽可能接近。系统会保证试运行模式的请求不会被写入到存储 -中,也不会产生其他副作用。 +当你使用可以修改资源的 HTTP 动词(`POST`、`PUT`、`PATCH` 和 `DELETE`)时, +你可以在 _试运行(dry run)_ 模式下提交你的请求。 +试运行模式有助于通过典型的请求阶段(准入链、验证、合并冲突)评估请求,直到将对象持久化到存储中。 +请求的响应正文尽可能接近非试运行响应。Kubernetes 保证试运行请求不会被持久化存储或产生任何其他副作用。 ### 发起试运行请求 {#make-a-dry-run-request} -通过设置 `dryRun` 查询参数可以触发试运行模式。此参数是一个字符串,以枚举值 -的形式工作且可接受的值只有: +通过设置 `dryRun` 查询参数触发试运行。此参数是一个字符串,用作枚举,唯一可接受的值是: -* `All`:每个阶段被会正常运行,除了最后的存储阶段。准入控制器会被运行来检查请求 - 是否合法,变更性(Mutating)控制器会变更请求,`PATCH` 请求也会触发合并操作, - 对象字段的默认值也会被设置,且基于模式定义的合法性检查也会被执行。 - 所生成的变更不会被写入到下层的持久性存储中,但本来会写入到数据库中的最终对象 - 会和正常的状态代码一起被返回给用户。如果请求会触发准入控制器而该准入控制器 - 带有一定的副作用,则请求会失败而不是冒险产生不希望的副作用。 - 所有的内置准入控制器插件都支持试运行模式。此外,准入控制 Webhook 也可在其 - [配置对象](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#webhook-v1beta1-admissionregistration-k8s-io) - 中通过将 `sideEffects` 字段设置为 "None" 来声明自身不会产生副作用。 - 如果某 Webhook 确实会产生副作用,那么 `sideEffects` 字段应该设置为 "NoneOnDryRun", - 并且 Webhook 应该被更改以支持 AdmissionReview 中的 `dryRun` 字段,从而避免 - 在试运行时产生副作用。 +[未设置值] +: 允许副作用。你可以使用 `?dryRun` 或 `?dryRun&pretty=true` 之类的查询字符串请求此操作。 + 响应是最终会被持久化的对象,或者如果请求不能被满足则会出现一个错误。 -* 空字符串(也即默认值):保留默认的修改行为。 +`All` +: 每个阶段都正常运行,除了防止副作用的最终存储阶段。 -例如: + +当你设置 `?dryRun=All` 时,将运行任何相关的{{< glossary_tooltip text="准入控制器" term_id="admission-controller" >}}, +验证准入控制器检查经过变更的请求,针对 `PATCH` 请求执行合并、设置字段默认值等操作,并进行模式验证。 +更改不会持久化到底层存储,但本应持久化的最终对象仍会与正常状态代码一起返回给用户。 + + +如果请求的非试运行版本会触发具有副作用的准入控制器,则该请求将失败,而不是冒不希望的副作用的风险。 +所有内置准入控制插件都支持试运行。 +此外,准入 Webhook 还可以设置[配置对象](/zh/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#webhook-v1beta1-admissionregistration-k8s-io) +的 `sideEffects` 字段为 `None`,借此声明它们没有副作用。 + + +{{< note >}} +如果 webhook 确实有副作用,则应该将 `sideEffects` 字段设置为 “NoneOnDryRun”。 +如果还修改了 webhook 以理解 AdmissionReview 中的 DryRun 字段, +并防止对标记为试运行的任何请求产生副作用,则该更改是适当的。 +{{< /note >}} + + +这是一个使用 `?dryRun=All` 的试运行请求的示例: ```console POST /api/v1/namespaces/test/pods?dryRun=All @@ -745,26 +1129,54 @@ Accept: application/json ``` 响应会与非试运行模式请求的响应看起来相同,只是某些生成字段的值可能会不同。 + +### 生成值 {#generated-values} + +对象的某些值通常是在对象被写入数据库之前生成的。很重要的一点是不要依赖试运行 +请求为这些字段所设置的值,因为试运行模式下所得到的这些值与真实请求所获得的 +值很可能不同。这类字段有: + +* `name`:如果设置了 `generateName` 字段,则 `name` 会获得一个唯一的随机名称 +* `creationTimestamp`/`deletionTimestamp`:记录对象的创建/删除时间 +* `UID`:唯一性标识对象,取值随机生成(非确定性) +* `resourceVersion`: 跟踪对象的持久化(存储)版本 +* 变更性准入控制器所设置的字段 +* 对于 `Service` 资源:`kube-apiserver` 为 `v1.Service` 对象分配的端口和 IP + ### 试运行的授权 {#dry-run-authorization} -试运行和非试运行请求的鉴权是完全相同的。因此,要发起一个试运行请求,用户必须 -被授权执行非试运行请求。 +试运行和非试运行请求的鉴权是完全相同的。因此,要发起一个试运行请求, +你必须被授权执行非试运行请求。 -例如,要在 Deployment 对象上试运行 `PATCH` 操作,你必须具有对 Deployment 执行 -`PATCH` 操作的访问权限,如下面的 RBAC 规则所示: +例如,要在 Deployment 对象上试运行 **patch** 操作,你必须具有对 Deployment 执行 **patch** 操作的访问权限, +如下面的 {{< glossary_tooltip text="RBAC" term_id="rbac">}} 规则所示: ```yaml rules: @@ -778,176 +1190,165 @@ See [Authorization Overview](/docs/reference/access-authn-authz/authorization/). --> 参阅[鉴权概述](/zh/docs/reference/access-authn-authz/authorization/)以了解鉴权细节。 - -### 生成的值 {#generated-values} - -对象的某些值通常是在对象被写入数据库之前生成的。很重要的一点是不要依赖试运行 -请求为这些字段所设置的值,因为试运行模式下所得到的这些值与真实请求所获得的 -值很可能不同。这类字段有: - -* `name`:如果设置了 `generateName` 字段,则 `name` 会获得一个唯一的随机名称 -* `creationTimestamp`/`deletionTimestamp`:记录对象的创建/删除时间 -* `UID`:唯一性标识对象,取值随机生成(非确定性) -* `resourceVersion`: 跟踪对象的持久化(存储)版本 -* 变更性准入控制器所设置的字段 -* 对于 `Service` 资源:`kube-apiserver` 为 `v1.Service` 对象分配的端口和 IP - ## 服务器端应用 {#server-side-apply} -{{< feature-state for_k8s_version="v1.16" state="beta" >}} - -从 Kubernetes v1.18 开始,可以启用[服务器端应用](/zh/docs/reference/using-api/server-side-apply/)功能 -特性,启用该特性后,控制面会跟踪所有新创建的对象的托管字段。服务器端应用提供了一种简洁的模式来管理字段冲突,提供服务器端的 `Apply` 和 `Update` 操作,并取代了 -`kubectl apply` 的客户端功能。有关该特性的详细描述,请参见[服务器端应用](/zh/docs/reference/using-api/server-side-apply/)章节 +Kubernetes 的[服务器端应用](/zh/docs/reference/using-api/server-side-apply/)功能允许控制平面跟踪新创建对象的托管字段。 +服务端应用为管理字段冲突提供了清晰的模式,提供了服务器端 `Apply` 和 `Update` 操作, +并替换了 `kubectl apply` 的客户端功能。 + +服务端应用的 API 动词是 **apply**。有关详细信息, +请参阅[服务器端应用](/zh/docs/reference/using-api/server-side-apply/)。 ## 资源版本 {#resource-versions} -资源版本采用字符串来表达,用来标示对象的服务器端内部版本。 -客户端可以使用资源版本来判定对象是否被更改,或者在读取、列举或监视资源时 -用来表达数据一致性需求。 -客户端必需将资源版本视为不透明的对象,将其原封不动地传递回服务器端。 -例如,客户端一定不能假定资源版本是某种数值标识,也不可以对两个资源版本值 -进行比较看其是否相同(也就是不可以比较两个版本值以判断其中一个比另一个 -大或小)。 +资源版本是标识服务器内部对象版本的字符串。 +客户端可以使用资源版本来确定对象何时更改, +或者在获取、列出和监视资源时表达数据一致性要求。 +资源版本必须被客户端视为不透明的,并且未经修改地传回服务器。 + +你不能假设资源版本是数字的或可排序的。 +API 客户端只能比较两个资源版本的相等性(这意味着你不能比较资源版本的大于或小于关系)。 -### `metadata` 中的 `resourceVersion` {#resourceVersion-in-metadata} +### metadata 中的 `resourceVersion` {#resourceVersion-in-metadata} -客户端可以在资源中看到资源版本信息,这里的资源包括从服务器返回的 Watch 事件 -以及 list 操作响应: +客户端在资源中查找资源版本,这些资源包括来自用于 **watch** 的响应流资源,或者使用 **list** 枚举的资源。 [v1.meta/ObjectMeta](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#objectmeta-v1-meta) - 资源 的 `metadata.resourceVersion` 值标明该实例上次被更改时的资源版本。 [v1.meta/ListMeta](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#listmeta-v1-meta) - 资源集合 -(即 list 操作的响应)的 `metadata.resourceVersion` 所标明的是 list 响应被构造 -时的资源版本。 +即 **list** 操作的响应)的 `metadata.resourceVersion` 所标明的是 list +响应被构造时的资源版本。 -### `resourceVersion` 参数 {#the-resourceversion-parameter} +### 查询字符串中的 `resourceVersion` 参数 {#the-resourceversion-parameter} -GET、LIST 和 WATCH 操作都支持 `resourceVersion` 参数。 +**get**、**list** 和 **watch** 操作支持 `resourceVersion` 参数。 +从 v1.19 版本开始,Kubernetes API 服务器支持 **list** 请求的 `resourceVersionMatch` 参数。 -参数的具体含义取决于所执行的操作和所给的 `resourceVersion` 值: +API 服务器根据你请求的操作和 `resourceVersion` 的值对 `resourceVersion` 参数进行不同的解释。 +如果你设置 `resourceVersionMatch` 那么这也会影响匹配发生的方式。 -对于 GET 和 LIST 而言,资源版本的语义为: -**GET:** + +### **get** 和 **list** 语义 + +对于 **get** 和 **list** 而言,`resourceVersion`的语义为: + +**get:** | resourceVersion 未设置 | resourceVersion="0" | resourceVersion="\<非零值\>" | -|------------------------|---------------------|----------------------------------------| +|-----------------------|---------------------|----------------------------------------| | 最新版本 | 任何版本 | 不老于给定版本 | -**LIST:** +**list:** -v1.19 及以上版本的 API 服务器支持 `resourceVersionMatch` 参数,用以确定如何对 -LIST 调用应用 resourceVersion 值。 -强烈建议在为 LIST 调用设置了 `resourceVersion` 时也设置 `resourceVersionMatch`。 -如果 `resourceVersion` 未设置,则 `resourceVersionMatch` 是不允许设置的。 -为了向后兼容,客户端必须能够容忍服务器在某些场景下忽略 `resourceVersionMatch` 的行为: +从 v1.19 版本开始,Kubernetes API 服务器支持 **list** 请求的 `resourceVersionMatch` 参数。 +如果同时设置 `resourceVersion` 和 `resourceVersionMatch`, +则 `resourceVersionMatch` 参数确定 API 服务器如何解释 `resourceVersion`。 - -- 当设置 `resourceVersionMatch=NotOlderThan` 且指定了 `limit` 时,客户端必须能够 - 处理 HTTP 410 "Gone" 响应。例如,客户端可以使用更新一点的 `resourceVersion` - 来重试,或者回退到 `resourceVersion=""` (即允许返回任何版本)。 - -- 当设置了 `resourceVersionMatch=Exact` 且未指定 `limit` 时,客户端必须验证 - 响应数据中 `ListMeta` 的 `resourceVersion` 与所请求的 `resourceVersion` 匹配, - 并处理二者可能不匹配的情况。例如,客户端可以重试设置了 `limit` 的请求。 +在 **list** 请求上设置 `resourceVersion` 时,你应该始终设置 `resourceVersionMatch` 参数。 +但是,请准备好处理响应的 API 服务器不知道 `resourceVersionMatch` 并忽略它的情况。 除非你对一致性有着非常强烈的需求,使用 `resourceVersionMatch=NotOlderThan` 同时为 `resourceVersion` 设定一个已知值是优选的交互方式,因为与不设置 `resourceVersion` 和 `resourceVersionMatch` 相比,这种配置可以取得更好的 集群性能和可扩缩性。后者需要提供带票选能力的读操作。 +设置 `resourceVersionMatch` 参数而不设置 `resourceVersion` 参数是不合法的。 + +下表解释了具有各种 `resourceVersion` 和 `resourceVersionMatch` 组合的 **list** 请求的行为: +{{< note >}} +如果你的集群的 API 服务器不支持 `resourceVersionMatch` 参数, +则行为与你未设置它时相同。 +{{< /note >}} +**get** 和 **list** 的语义是: -- **Most Recent:** Return data at the most recent resource version. The returned data must be - consistent (i.e. served from etcd via a quorum read). -- **Any:** Return data at any resource version. The newest available resource version is preferred, + -GET 和 LIST 操作的语义含义如下: +任意版本 +: 返回任何资源版本的数据。最新可用资源版本优先,但不需要强一致性; + 可以提供任何资源版本的数据。由于分区或过时的缓存, + 请求可能返回客户端先前观察到的更旧资源版本的数据,特别是在高可用性配置中。 + 不能容忍这种情况的客户不应该使用这种语义。 -- **最新版本:** 返回资源版本为最新的数据。所返回的数据必须一致 - (通过票选读操作从 etcd 中取出)。 -- **任意版本:** 返回任意资源版本的数据。优选最新可用的资源版本,不过不能保证 - 强一致性;返回的数据可能是任何资源版本的。请求返回的数据有可能是客户端以前 - 看到过的很老的资源版本。尤其在某些高可用配置环境中,网络分区或者高速缓存 - 未被更新等状态都可能导致这种状况。不能容忍这种不一致性的客户端不应采用此 - 语义。 - -- **不老于指定版本:** 返回至少比所提供的 `resourceVersion` 还要新的数据。 - 优选最新的可用数据,不过最终提供的可能是不老于所给 `resourceVersion` 的任何版本。 - 对于发给能够正确处理 `resourceVersionMatch` 参数的服务器的 LIST 请求,此语义 - 保证 `ListMeta` 中的 `resourceVersion` 不老于请求的 `resourceVersion`,不过 - 不对列表条目之 `ObjectMeta` 的 `resourceVersion` 提供任何保证。 - 这是因为 `ObjectMeta.resourceVersion` 所跟踪的是列表条目对象上次更新的时间, - 而不是对象被返回时是否是最新。 +最新版本 +: 返回最新资源版本的数据。 + 返回的数据必须一致(详细说明:通过仲裁读取从 etcd 提供)。 -- **确定版本:** 返回精确匹配所给资源版本的数据。如果所指定的 resourceVersion - 的数据不可用,服务器会响应 HTTP 410 "Gone"。 - 对于发送给能够正确处理 `resourceVersionMatch` 参数的服务器的 LIST 请求而言, - 此语义会保证 ListMeta 中的 `resourceVersion` 与所请求的 `resourceVersion` - 匹配, 不过不对列表条目之 `ObjectMeta` 的 `resourceVersion` 提供任何保证。 - 这是因为 `ObjectMeta.resourceVersion` 所跟踪的是列表条目对象上次更新的时间, - 而不是对象被返回时是否是最新。 - -- **Continue 令牌、精确匹配:** 返回原先带分页参数的 LIST 调用中指定的资源版本的数据。 - 在最初的带分页参数的 LIST 调用之后,所有分页式的 LIST 调用都使用所返回的 Continue - 令牌来跟踪最初提供的资源版本, + +不老于指定版本 +: 返回数据至少与提供的 `resourceVersion` 一样新。 + 最新的可用数据是首选,但可以提供不早于提供的 `resourceVersion` 的任何数据。 + 对于对遵守 `resourceVersionMatch` 参数的服务器的 **list** 请求, + 这保证了集合的 `.metadata.resourceVersion` 不早于请求的 `resourceVersion`, + 但不保证该集合中任何项目的 `.metadata.resourceVersion`。 + + + +精确匹配 +: 以提供的确切资源版本返回数据。如果提供的 `resourceVersion` 不可用, + 则服务器以 HTTP 410 “Gone”响应。对于对支持 `resourceVersionMatch` 参数的服务器的 **list** 请求, + 这可以保证集合的 `.metadata.resourceVersion` 与你在查询字符串中请求的 `resourceVersion` 相同。 + 该保证不适用于该集合中任何项目的 `.metadata.resourceVersion`。 + +从 token 开始、精确匹配 +: 返回初始分页 **list** 调用的资源版本的数据。 + 返回的 _Continue 令牌_ 负责跟踪最初提供的资源版本,最初提供的资源版本用于在初始分页 **list** 之后的所有分页 **list** 中。 + + + +{{< note >}} +当你 **list** 资源并收到集合响应时, +响应包括集合的[元数据](/zh/docs/reference/generated/kubernetes-api/v1.21/#listmeta-v1-meta) +以及该集合中每个项目的[对象元数据](/zh/docs/reference/generated/kubernetes-api/v1.21/#listmeta-v1-meta)。 +对于在集合响应中找到的单个对象,`.metadata.resourceVersion` 跟踪该对象的最后更新时间, +而不是对象在服务时的最新程度。 +{{< /note >}} + + + +当使用 `resourceVersionMatch=NotOlderThan` 并设置了限制时, +客户端必须处理 HTTP 410 “Gone” 响应。 +例如,客户端可能会使用更新的 `resourceVersion` 重试或回退到 `resourceVersion=""`。 + +当使用 `resourceVersionMatch=Exact` 并且未设置限制时, +客户端必须验证集合的 `.metadata.resourceVersion` 是否与请求的 `resourceVersion` 匹配, +并处理不匹配的情况。例如,客户端可能会退回到设置了限制的请求。 + + + -对于 WATCH 操作而言,资源版本的语义如下: +### **watch** 语义 -**WATCH:** +对于 watch 操作而言,资源版本的语义如下: + +**watch:** -WATCH 操作语义的含义如下: +**watch** 操作语义的含义如下: -- **读取状态并从最新版本开始:** 从最新的资源版本开始 WATCH 操作。这里的 - 最新版本必须是一致的(即通过票选读操作从 etcd 中取出)。为了建立初始状态, - WATCH 首先会处理一组合成的 "Added" 事件,这些事件涵盖在初始资源版本中存在 - 的所有资源实例。 - 所有后续的 WATCH 事件都是关于 WATCH 开始时所处资源版本之后发生的变更。 +读取状态并从任意版本开始 +: {{< caution >}} + 以这种方式初始化的监视可能会返回任意陈旧的数据。 + 请在使用之前查看此语义,并尽可能支持其他语义。 + {{< /caution >}} + 在任何资源版本开始 **watch**;首选可用的最新资源版本,但不是必需的。允许任何起始资源版本。 + 由于分区或过时的缓存,**watch** 可能从客户端之前观察到的更旧的资源版本开始, + 特别是在高可用性配置中。不能容忍这种明显倒带的客户不应该用这种语义启动 **watch**。 + 为了建立初始状态,**watch** 从起始资源版本中存在的所有资源实例的合成 “添加” 事件开始。 + 以下所有监视事件都针对在 **watch** 开始的资源版本之后发生的所有更改。 -- **读取状态并从任意版本开始:** 警告:通过这种方式初始化的 WATCH 操作可能会 - 返回任何状态的停滞数据。请在使用此语义之前执行复核,并在可能的情况下采用其他 - 语义。此语义会从任意资源版本开始执行 WATCH 操作,优选最新的可用的资源版本, - 不过不是必须的;采用任何资源版本作为起始版本都是被允许的。 - WATCH 操作有可能起始于客户端已经观测到的很老的版本。在高可用配置环境中,因为 - 网络分裂或者高速缓存未及时更新的原因都会造成此现象。 - 如果客户端不能容忍这种不一致性,就不要使用此语义来启动 WATCH 操作。 - 为了建立初始状态,WATCH 首先会处理一组合成的 "Added" 事件,这些事件涵盖在 - 初始资源版本中存在的所有资源实例。 - 所有后续的 WATCH 事件都是关于 WATCH 开始时所处资源版本之后发生的变更。 +读取状态并从最新版本开始 +: 从最近的资源版本开始 **watch**, + 它必须是一致的(详细说明:通过仲裁读取从 etcd 提供服务)。 + 为了建立初始状态,**watch** 从起始资源版本中存在的所有资源实例的合成 “添加” 事件开始。 + 以下所有监视事件都针对在 **watch** 开始的资源版本之后发生的所有更改。 -- **从指定版本开始:** 从某确切资源版本开始执行 WATCH 操作。WATCH 事件都是 - 关于 WATCH 开始时所处资源版本之后发生的变更。与前面两种语义不同,WATCH 操作 - 开始的时候不会生成或处理为所提供资源版本合成的 "Added" 事件。 - 我们假定客户端既然能够提供确切资源版本,就应该已经拥有了起始资源版本对应的初始状态。 +从指定版本开始 +: 以确切的资源版本开始 **watcH**。监视事件适用于提供的资源版本之后的所有更改。 + 与 “Get State and Start at Most Recent” 和 “Get State and Start at Any” 不同, + **watch** 不会以所提供资源版本的合成 “添加” 事件启动。 + 由于客户端提供了资源版本,因此假定客户端已经具有起始资源版本的初始状态。 ### "410 Gone" 响应 {#410-gone-responses} @@ -1142,15 +1603,36 @@ reply with a `410 Gone` HTTP response. ### 不可用的资源版本 {#unavailable-resource-versions} -服务器不必未无法识别的资源版本提供服务。针对无法识别的资源版本的 LIST 和 GET 请求 -可能会短暂等待,以期资源版本可用。如果所给的资源版本在一定的时间段内仍未变得 -可用,服务器应该超时并返回 `504 (Gateway Timeout)`,且可在响应中添加 -`Retry-After` 响应头部字段,标明客户端在再次尝试之前应该等待多少秒钟。 -目前,`kube-apiserver` 也能使用 `Too large resource version(资源版本过高)` -消息来标识这类响应。针对某无法识别的资源版本的 WATCH 操作可能会无限期 -(直到请求超时)地等待下去,直到资源版本可用。 +服务器不需要提供无法识别的资源版本。 +如果你请求了 **list** 或 **get** API 服务器无法识别的资源版本,则 API 服务器可能会: +* 短暂等待资源版本可用,如果提供的资源版本在合理的时间内仍不可用, + 则应超时并返回 `504 (Gateway Timeout)`; +* 使用 `Retry-After` 响应标头进行响应,指示客户端在重试请求之前应等待多少秒。 + + +如果你请求 API 服务器无法识别的资源版本, +kube-apiserver 还会使用 “Too large resource version” 消息额外标识其错误响应。 + +如果你对无法识别的资源版本发出 **watch** 请求, +API 服务器可能会无限期地等待(直到请求超时)资源版本变为可用。