作者:STEFAN SCHIMANSKI AND MICHAEL HAUSENBLAS AUGUST 15, 2017
翻译:狄卫华
原文:Kubernetes deep dive: API Server – part 3a
原文链接:https://blog.openshift.com/kubernetes-deep-dive-api-server-part-3a/
本系列翻译链接:
- Kubernetes深入系列:API Server-Part 1
- Kubernetes深入系列:API Server-Part 2
- Kubernetes深入系列:API Server-Part 3a
- Kubernetes深入系列:为自定义资源生成代码
在本系列的前两部分中,我们回顾了API Server 中的一般流程以及如何使用 etcd 管理对象状态。 现在我们正在讨论如何扩展核心 API。
最初,扩展 API Server 的唯一方法是 Fork 和 Patch kube-apiserver 源代码并集成自己的资源。 或者可以尝试游说将新类型放入上游核心对象集合中。 但是这导致了一个问题:核心 API 将随着时间的推移而增长,可能导致 API 变得臃肿。 为了不让核心 API 变得太笨重,项目提出了两种扩展核心的方法:
- 使用的自定义资源定义(CRD),此前被称做第三方资源(TPR)。 通过这些 CRD,您可以轻松而灵活地定义自己的对象类型,并让 API 服务器处理整个生命周期。
- 使用与主 API Server 并行运行的用户 API Server(UAS)。 虽然涉及更多的先期投入与研发工作,但可以达到更细粒度控制对象行为。
此外,在扩展的上下文中,我们将讨论对象生命周期(从初始化到入场到终结)。 我们将在两篇文章中介绍 CRD的主题,因为它相当复杂(elaborate),我们正在处理 1.7 到 1.8 版本中的迁移工作。 在这篇文章中,我们关注 CRD,第二部分我们将向您展示如何为它编写自定义控制器,包括使用 kube-gen 生成代码。
声明和创建 CRD
正如我们在第1部分中讨论的那样,资源按 API Groups 分组,每个版本都有相应的 HTTP 路径。 现在,如果您要实现 CRD,首先要命名一个不能与现有核心组重叠的新 API Group。 在您自己的 API Group 中,您可以拥有尽可能多的资源,并且可以使用与其他组中可能存在的名称相同的名称。 我们来看一个具体的例子:
我们区分 CRD 与自定义资源 CR,CRD 就像面向对象编程中的类定义,而 CR 则可以看做是对应的类实例。 首先我们看一下类定义:在上面的第 1 行中,您会看到在 CRD 中必须使用 apiVersion
; kube-apiserver 1.7 和更高版本都支持该功能。 在第 5 行及以下,您使用 spec
字段来定义:
- 第 6 行:CRD API 组(在我们的案例中,一个好的做法是使用组织的完整域名,如 example.com。
- 第 7 行:CRD 对象的版本。 每个资源只有一个版本,但 API Group 中可能有多个版本不同的资源。
spec.names
字段有两个必需的子项:
- 第 9 行
Kind
按照惯例是大写单数(Database
) - 第 10 行:
plural
,按照惯例是小写复数(这里是databases
)。 您可以使用有趣的命名字段plural
来定义资源HTTP路径,我们的示例为:https://<server/apis/example.com/v1/namespaces/default/databases
。 还有一个可选的singular
字段,默认为小写的类型值,可以在 kubectl 的上下文中使用。
此外,spec.names
还有许多可选字段,由 API Server 自动派生和填充。
请记住从第1部分可以看出,该类型描述了对象的类型,而资源则对应于 HTTP 路径。 大多数时候,这两个一致; 但在某些情况下,API Server 可能会在相同的 API HTTP 路径上返回不同的类型(例如:Status
错误对象明显是另一种类型)。
需注意资源名称(示例中的 database
)和组(example.com)必须匹配元数据字段 name
(请参见上面的第4 行)。
现在我们可以基于上述 YAML 规范创建 CRD:
1 | $ kubectl create -f databases-crd.yaml |
需注意,创建过程是异步过程,这意味着您必须检查 CRD 状态以显示检查指定的名称是否已被接受(即与其他资源没有名称冲突),并且 API Server 已经建立了要处理的 API 处理程序添加了新的资源。 在脚本或代码中,轮询是处理这种情况比较好的方式。
最终,我们得到这个:
1 | $ kubectl get crd databases.example.com -o yaml |
在上面,你可以看到 kubectl
已经获取到了我们之前定义的 CRD 并且能够提供关于它的状态信息;所有的名字都被接受而没有冲突,并且 CRD 已经被创建,也就是说,API Server 现在就提供对于该 CRD 的服务。
发现和使用CRD
在使用 kubectl proxy
在本地代理 Kubernetes API 后,我们可以发现我们在上一步中定义的数据库 CRD ,如下所示:
1 | $ http 127.0.0.1:8001/apis/example.com |
请注意,kubectl
使用 〜/.kube/cache/discovery
目录默认缓存 10分钟内发现内容。 另外,kubectl
最多可能需要10分钟才能看到新的资源,例如我们定义的 CRD。 但是在高速缓存未命中时–也就是说,当 kubectl
无法在命令中识别资源名称时—将立即被重新发现。
接下来,我们要使用 CRD 的一个实例:
1 | $ cat wordpress-database.yaml |
要通过 API 直接监控资源创建和更新,您可以在某个 resourceVersion
上使用 watch
操作 (如第2部分所述)。首先,我们将查找定义的 Database
CRD 的 resourceVersion
,然后使用 curl
观察对该资源在单独的 shell 会话中:
1 | $ http 127.0.0.1:8001/apis/example.com/v1/namespaces/default/databases |
所以在这里我们发现我们的 CRD 资源 /apis/example.com/v1/namespaces/default/databases/wordpress
实际数值 “resourceVersion" : "2154"
,这将用于带 curl
的 Watch
的操作中:
1 | $ curl -f 127.0.0.1:8001/apis/example.com/v1/namespaces/default/databases?watch=true&resourceVersion=2154 |
现在我们打开一个新的 shell 会话并删除 wordpress
CRD 资源; 我们可以在原始会话中看到 watch
的通知:
1 | $ kubectl delete databases.example.com/wordpress |
注意:我们也可以使用 kubectl delete database wordpress
,因为 Kubernetes 中没有预定义的 database
资源。 此外,单数字 database
是我们 CRD 中的 spec.name.singular
字段,它自动根据英语语法派生。
在原始会话中,您启动了curl
watch
命令,现在可以从 API Server 看到实时更新:
1 | {"type":"DELETED","object":{"apiVersion":"example.com/v1","kind":"Database","metadata":{"clusterName":"","creationTimestamp":"2017-0[0/515] |
综合起来,使用三个 shell 会话(底部的初始kube proxy
命令的附加命令),上面的命令和相应的输出如下所示:
最后,让我们看看 database
CRD的各个数据在 etcd 中如何存储的。 在下面我们直接通过 HTTP API 访问主节点上的 etcd:
1 | $ curl -s localhost:2379/v2/keys/registry/example.com/databases/default | jq . |
从上面的 etcd 资源转储中可以看到,CRD 数据本质上是一个未解析的 blob。
请注意,删除 CRD 时所有实例也将被删除,即它是级联删除操作。
CRD的现状、限制、未来
目前,我们有 Kubernetes 1.7 作为稳定版本,预计2017 年 10 月初 1.8 版本发布。当前 CRD 的状态如下:
- CRD 开始取代 Kubernetes 1.7 中
ThirdPartyResources
(TPRs),而TPRs
将在 Kubernetes 1.8 中取消。 - TPR 到 CRD 可以进行简单迁移。
- 每个 CRD 支持单个版本,但是每个组可能有多个版本。
- CRD 提供了一致的 API,并且从用户的角度来看与本地资源基本上没有区别。
- CRD 在后续版本中更多功能的稳定基础功能,例如:
- 要使用 JSON-Schema 进行验证,可以查看 CRD 验证提议
- 1.8 中的垃圾收集
现在您已经看到了如何使用 CRD,接下来我们将讨论其局限性:
- 它们不提供版本转换功能,也就是说,每个 CRD 只能有一个版本(预计不会在近期或中期看到转换支持)。
- 目前没有验证,但可能会在 1.8 版本中出现,请参阅 Google Summer of Code 项目。并且使用即将推出的JSON 模式(不是图灵完备)有限的验证能力。
- 没有快速的进程内入场可能(但支持初始化和入场的webhooks)
- 您无法定义子资源,例如
scale
或status
,但有一个正在进行中的 proposal。 - 最后但并非最不重要的是,CRD 目前不支持默认值,即将默认值分配给某些字段(这可能出现在后续某一个版本中)。
为了解决上述问题并以更灵活的方式扩展 Kubernetes,您可以使用与主 API Server 并行运行的 用户 API Server(UAS)。我们将在本博客文章系列的下一篇文章中详细介绍如何编写 UAS。下次我们将通过为其编写自定义控制器来完成 CRD。
除特别声明本站文章均属原创(翻译内容除外),如需要转载请事先联系,转载需要注明作者原文链接地址。