回忆KubernetesApi
Kubernetes API 是通过 HTTP 提供的基于资源 (RESTful) 的编程接口。 它支持通过标准 HTTP 动词(POST、PUT、PATCH、DELETE、GET)检索、创建、更新和删除主要资源。对于某些资源,API 包括额外的子资源,允许细粒度授权(例如:将 Pod 的详细信息与检索日志分开), 为了方便或者提高效率,可以以不同的表示形式接受和服务这些资源。
Kubernetes 支持通过 watch 实现高效的资源变更通知。 Kubernetes 还提供了一致的列表操作,以便 API 客户端可以有效地缓存、跟踪和同步资源的状态
先要明确API资源
- 资源类型(Resource Type) 是 URL 中使用的名称(
pods、namespaces、services) - 所有资源类型都有一个具体的表示(它们的对象模式),称为 类别(Kind)
- 资源实例的列表称为 集合(Collection)
- 资源类型的单个实例称为 资源(Resource) ,通常也表示一个 对象(Object)
- 对于某些资源类型,API 包含一个或多个 子资源(sub-resources) ,这些子资源表示为资源下的 URI 路径
再明确资源URL的规则
-
/api前缀是kubernetes核心对象的URL,例如pod,configmap,service等,这些对象都是属于core包中的。例如:
/api/v1/pods,/api/v1/configmaps -
/apis前缀属于拓展资源的URL,例如deployment,deamonset等其URL按照:
- 集群范围资源:
/apis/GROUP/VERSION/RESOURCETYPE - 命名空间范围资源:
/apis/GROUP/VERSION/namespaces/NAMESPACE/RESOURCETYPE
- 集群范围资源:
再明确资源版本resourceVersion
资源版本是标识服务器内部对象版本的字符串。 客户端可以使用资源版本来确定对象何时更改, 或者在获取、列出和监视资源时表达数据一致性要求。 资源版本必须被客户端视为不透明的,并且未经修改地传回服务器。
你不能假设资源版本是数字的或可排序的。 API 客户端只能比较两个资源版本的相等性(这意味着你不能比较资源版本的大于或小于关系)。
-
metadata 中的
resourceVersion客户端在资源中查找资源版本,这些资源包括来自用于 watch 的响应流资源,或者使用 list 枚举的资源。
-
v1.meta/ObjectMeta - 资源的
metadata.resourceVersion值标明该实例上次被更改时的资源版本。 -
v1.meta/ListMeta - 资源集合即 list 操作的响应)的
metadata.resourceVersion所标明的是 list 响应被构造时的资源版本。
一个是资源被修改时的resourceVersion
一个是在我们构造list请求时的resourceVersion
-
-
查询字符串中的
resourceVersion参数get、list 和 watch 操作支持
resourceVersion参数。API 服务器根据你请求的操作和resourceVersion的值对resourceVersion参数进行不同的解释。 如果你设置resourceVersionMatch那么这也会影响匹配发生的方式。
1.检测资源
Kubernetes API 允许客户端对对象或集合发出初始请求,然后跟踪自该初始请求以来的更改:watch。 客户端可以发送 list 或者 get 请求,然后发出后续 watch 请求。
为了使这种更改跟踪成为可能,每个 Kubernetes 对象都有一个 resourceVersion 字段, 表示存储在底层持久层中的该资源的版本。在检索资源集合(命名空间或集群范围)时, 来自 API 服务器的响应包含一个 resourceVersion 值。 客户端可以使用该 resourceVersion 来启动对 API 服务器的 watch。
当你发送 watch 请求时,API 服务器会响应更改流。 这些更改逐项列出了在你指定为 watch 请求参数的 resourceVersion 之后发生的操作(例如 create、delete 和 update)的结果。 整个 watch 机制允许客户端获取当前状态,然后订阅后续更改,而不会丢失任何事件。
我们可以通过list请求获取资源信息,进行第一步的全局同步全量更新,后续根据resourceVersion进行watch监听,以进行后续的资源增量更新。我们后续学习的client-go大量用到list+watch特性,这个我们后续再进行深度介绍。
有了解过ETCD的同学应该清楚
revision,其实resourceVersion就是利用了ETCD中revision + watch特性,每当资源进行变更,则服务端则会发送一个对应的事件event告知客户端。如果客户端 watch 连接断开,则该客户端可以从最后返回的resourceVersion开始新的 watch 请求; 客户端还可以执行新的 get/list 请求并重新开始。
1.1 List/Watch
# list操作
# 获取default命名空间下的service
# 注: $KUBEAPI是我个人设置的kube api地址
$ curl $KUBEAPI/api/v1/namespaces/default/services
# ------
# 输出如下:
# 其中resourceVersion就是资源版本 全局单调递增
#{
# "kind": "PodList",
# "apiVersion": "v1",
# "metadata": {"resourceVersion":"5767454"},
# "items": [...]
#}
# watch操作
# 检测从resourceVersion=5767454开始(例如 create、delete、apply 或 update)的通知
$ curl $KUBEAPI/api/v1/namespaces/default/services?watch=1&resourceVersion=5767454
#------
# 首先会进行ADD事件增量
# 后续对service进行修改或删除,会对应获取到
# MODIFIED/DELETED事件
注意:给定的 Kubernetes 服务器只会保留一定的时间内发生的历史变更列表。 使用 etcd3 的集群默认保存过去 5 分钟内发生的变更。 当所请求的 watch 操作因为资源的历史版本不存在而失败, 客户端必须能够处理因此而返回的状态代码 410 Gone,清空其本地的缓存, 重新执行 get 或者 list 操作, 并基于新返回的 resourceVersion 来开始新的 watch 操作。
对于订阅集合,Kubernetes 客户端库通常会为 list -然后- watch 的逻辑提供某种形式的标准工具。 (在 Go 客户端库中,这称为 反射器(Reflector),位于 k8s.io/client-go/tools/cache 包中。
1.2 Bookmarks
为了减轻短历史窗口的影响,Kubernetes API 提供了一个名为 BOOKMARK 的监视事件。 这是一种特殊的事件,用于标记客户端请求的给定 resourceVersion 的所有更改都已发送。
在Kubernetes中,Kubernetes API访问的书签(Bookmark)是一种机制,用于在长时间运行的操作中跟踪资源列表的状态。它允许客户端在多次请求之间保持一个持久的游标,并返回一组资源的片段而不是完整的资源列表。
使用书签功能可以分批次地获取资源列表,从而降低对API服务器的负载,并减少响应时间。客户端可以使用书签机制来定期轮询资源列表,而无需每次请求获取整个列表。
在Kubernetes API中,书签由resourceVersion字段表示,它是一个表示资源版本的字符串。当客户端发起一个带有书签的API请求时,API服务器会返回该资源列表的快照,并在响应中包含新的书签值。客户端可以将此书签值用于后续请求,以获取自上次请求以来更新的资源列表。
通过使用书签,客户端可以有效地追踪和处理大量资源,而无需在每个请求中获取整个列表。这对于监视和同步资源状态非常有用,特别是当资源数量庞大时。
使用书签的好处是,您可以确保在重新连接到API服务器后不会错过任何重要的资源更改。通过指定先前观察到的资源版本作为书签,API将返回从该版本之后发生的事件,以便您可以从先前的状态恢复并接收到完整的更改历史。
这对于需要实时监控资源更改的应用程序和工具非常有用。通过使用书签,您可以保持与Kubernetes集群的同步,并接收到在您断开连接期间发生的任何重要更改的通知。这可以避免您在重新连接后需要重新获取整个资源列表,并使您能够有效地处理资源的增量更新。
1.3 Chunk
在较大规模集群中,检索某些资源类型的集合可能会导致非常大的响应,从而影响服务器和客户端。 例如,一个集群可能有数万个 Pod,每个 Pod 大约相当于 2 KiB 的编码 JSON。 跨所有命名空间检索所有 Pod 可能会导致非常大的响应 (10-20MB) 并消耗大量服务器资源。
你可以请求 API 服务器通过使用页(Kubernetes 将其称为“块(Chunk)”)的方式来处理 list, 完成单个集合的响应。 要以块的形式检索单个集合,针对集合的请求支持两个查询参数 limit 和 continue, 并且从集合元 metadata 字段中的所有 list 操作返回响应字段 continue。 客户端应该指定他们希望在每个带有 limit 的块中接收的条目数上限,如果集合中有更多资源, 服务器将在结果中返回 limit 资源并包含一个 continue 值。
作为 API 客户端,你可以在下一次请求时将 continue 值传递给 API 服务器, 以指示服务器返回下一页(块)结果。继续下去直到服务器返回一个空的 continue 值, 你可以检索整个集合。
与 watch 操作类似,continue 令牌也会在很短的时间(默认为 5 分钟)内过期, 并在无法返回更多结果时返回 410 Gone 代码。 这时,客户端需要从头开始执行上述检视操作或者忽略 limit 参数。
类似于我们平时业务开发中的分页查询
请注意,集合的
resourceVersion在每个请求中保持不变, 这表明服务器正在向你显示 Pod 的一致快照。 在版本10245之后创建、更新或删除的 Pod 将不会显示, 除非你在没有继续令牌的情况下发出单独的 list 请求。 这使你可以将大请求分成更小的块,然后对整个集合执行 watch 操作,而不会丢失任何更新。
remainingItemCount是集合中未包含在此响应中的后续项目的数量。 如果 list 请求包含标签或字段选择器, 则剩余项目的数量是未知的,并且 API 服务器在其响应中不包含remainingItemCount字段。 如果 list 是完整的(因为它没有分块,或者因为这是最后一个块),没有更多的剩余项目, API 服务器在其响应中不包含remainingItemCount字段。remainingItemCount的用途是估计集合的大小。
1.4 410 Gone 响应
服务器不需要提供所有老的资源版本,在客户端请求的是早于服务器端所保留版本的 resourceVersion 时,可以返回 HTTP 410 (Gone) 状态码。 客户端必须能够容忍 410 (Gone) 响应。 参阅高效检测变更以了解如何在监测资源时处理 410 (Gone) 响应。
如果所请求的 resourceVersion 超出了可应用的 limit, 那么取决于请求是否是通过高速缓存来满足的,API 服务器可能会返回一个 410 Gone HTTP 响应。
我们在client-go中,进行list请求都会进行判断资源是否可用,后续我们深究源码的时候可以看到对应410判断err和code的逻辑。
2.写在最后
本文作为对学习client-go的一个预热,摘取了k8s官方关于kubernetesAPI几个点,有助于针对我们后续研究client-go源码知道底层的请求是如何构建。我认为学习技术永远是: 文档 >= 博客 + 视频。希望大家可以多多查阅官方文档。希望每一次阅读,都能品出不一样的知识。
下一篇文章我们将对client-go中informer架构的Reflector源码进行深入解析,探究一下,Reflector底层是如何处理封装上述请求。