深度剖析KubernetesAPIServer三部曲-part3-创新互联
在本系列的前两部分中我们介绍了 API Server 的总体流程,以及 API 对象如何存储到 etcd 中。在本文中我们将探讨如何扩展 API 资源。
创新互联建站-专业网站定制、快速模板网站建设、高性价比静宁网站开发、企业建站全套包干低至880元,成熟完善的模板库,直接使用。一站式静宁网站制作公司更省心,省钱,快速模板网站建设找我们,业务覆盖静宁地区。费用合理售后完善,10余年实体公司更值得信赖。在一开始的时候,扩展 API 资源的唯一方法是扩展相关 API 源代码,集成为你所需的资源。或者,推动一个全新的类型为新的核心对象 API 合入社区代码。但是,这样就会导致核心 API 资源类型的不断增加,直至 API 过载。为了避免这种 API 资源的无限制扩展,在 Kubernetes 中提供两种扩展核心 API 的方法:
1. 使用自定义资源定义( CRDs ),最开始的时候被称为第三方资源( TPRs )。通过 CRD 你能够简单而灵活的方式定义自己的资源对象类型,并让 API server 处理整个生命周期。
2. 使用与主 API Servers 并行运行的用户 API Servers ( UAS )。这种方式,可能更多的设计代码开发,可能需要你投入较多的时间及精力。当然,这种方式也能够让你对 API 资源有更细致,全面的了解。
在本文中,我们主要对 CRD 相关定义以及使用进行探讨。
CRDs 的声明及创建
在本系列文章第一部分所提到过的,每个 API 资源根据 Group 群组分类,每个对象都有一个对应的版本号与 HTTP 路径相关联。现在如果想要实现一个 CRD ,首先需要的是就是命名一个新的 API Group 群组,这个 API 群组不能与已经存在的群组重复。在你自己新建的 API 群组中,你可以拥有任意数量的资源,并且它们可以与其他群组中的资源具有相同的名称。下面我们来列举一个实际的例子:
在之前我们有介绍过,每个版本的由
API
群组管理的
Kubernetes
资源是跟
HTTP
路径相关的。
CRD
类似于面向对象编程中一个类的定义,而实际使用的
CR
可以看做为它的一组实例。首先我们对例子中的一些字段作说明,第一行中的
CRD apiVersion
在
kube-apiserver 1.7
之后都是这样定义的。从第
5
行之后我们定义了
spec
的相关字段。在第
6
行
spec.group
是定义了你创建的
CRD
的
API
群组(在本例子中定义为了
example.com
)。第
7
行定义了
CRD
对象的版本。每个资源只有一个固定版本,但在
API
群组中还是能有多个不同版本的资源。第
8
行的
spec.names
有两个必填项:
kind
,按照惯例第一个字母大写,
plural
,按照惯例全为小写,这个字段与最终生成的
HTTP
路径相关,比如在本例子中,最终的
HTTP
路径为
https:// 上面的
kind
主要是用来描述对象的类型,而
resource
资源是与
HTTP
路径相关的。大多数情况下这两个是匹配的;但是在某些特定情况下在相同的
API HTTP
路径下可能返回不通的
kind
(比如
Status
错误对象会返回另一种
kind
)。 值得注意的是
resource
资源(在本例中是
databases
)和
group
群组(本例中是
example.com
)必须与
metadata.name
字段匹配(本例为第四行
databases. example.com
)。 现在我们根据上面的
YAML
文件来创建一个
CRD
: $ kubectl create -f databases-crd.yaml customresourcedefinition "databases.example.com" created 由于这个创建过程是异步进行的,所以你必须检查一下你创建的
CRD
的状态,确认你创建的
CRD
没有与其它资源冲突,并且
API Server
已经调用相关处理函数完成创建。你可以在脚本或代码中通过轮询完成这个过程。最后我们能得到以下状态: $ kubectl get crd databases.example.com -o yaml apiVersion: apiextensions.k8s.io/v1beta1 kind: CustomResourceDefinition metadata: creationTimestamp: 2017-08-09T09:21:43Z name: databases.example.com resourceVersion: "792" selfLink: /apis/apiextensions.k8s.io/v1beta1/customresourcedefinitions/databases.example.com uid: 28c94a05-7ce4-11e7-888c-42010a9a0fd5 spec: group: example.com names: kind: Database listKind: DatabaseList plural: databases singular: database scope: Namespaced version: v1 status: acceptedNames: kind: Database listKind: DatabaseList plural: databases singular: database conditions: - lastTransitionTime: null message: no conflicts found reason: NoConflicts status: "True" type: NamesAccepted - lastTransitionTime: 2017-08-09T09:21:43Z message: the initial names have been accepted reason: InitialNamesAccepted status: "True" type: Established 以上,我们可以看到通过
kubectl
可以看到我们之前创建的
CRD
,并且显示出了
CRD
的一些状态信息。 CRDs
的使用 在
通过
kubectl proxy
将
Kubernetes API
开启本地代理后,查看我们刚才创建的
CRD: $ http 127.0.0.1:8001/apis/example.com HTTP/1.1 200 OK Content-Length: 223 Content-Type: application/json Date: Wed, 09 Aug 2017 09:25:44 GMT { "apiVersion": "v1", "kind": "APIGroup", "name": "example.com", "preferredVersion": { "groupVersion": "example.com/v1", "version": "v1" }, "serverAddressByClientCIDRs": null, "versions": [ { "groupVersion": "example.com/v1", "version": "v1" } ] } 请注意,在默认情况下十分钟内,
kubectl
是查看存储在
~/.kube/cache/discovery
目录的缓存。所以,可能会需要
10
分钟后你才能看到你新创建的
CRD
资源。但是,当没有缓存时,
kubectl
发现不了所需的资源时,那么会重新缓存它。 接下来,我们来看一个
CRD
实例: $ cat wordpress-database.yaml apiVersion: example.com/v1 kind: Database metadata: name: wordpress spec: user: wp password: secret encoding: unicode $ kubectl create -f wordpress-databases.yaml database "wordpress" created $ kubectl get databases.example.com NAME KIND wordpress Database.v1.example.com 想要通过
API
来监控资源的创建与
更新,你可以通过对某个
resourceVersion
(我们通过
$ http 127.0.0.1:8001/apis/example.com/v1/namespaces/default/databases HTTP/1.1 200 OK Content-Length: 593 Content-Type: application/json Date: Wed, 09 Aug 2017 09:38:49 GMT { "apiVersion": "example.com/v1", "items": [ { "apiVersion": "example.com/v1", "kind": "Database", "metadata": { "clusterName": "", "creationTimestamp": "2017-08-09T09:38:30Z", "deletionGracePeriodSeconds": null, "deletionTimestamp": null, "name": "wordpress", "namespace": "default", "resourceVersion": "2154", "selfLink": "/apis/example.com/v1/namespaces/default/databases/wordpress", "uid": "8101a7af-7ce6-11e7-888c-42010a9a0fd5" }, "spec": { "encoding": "unicode", "password": "secret", "user": "wp" } } ], "kind": "DatabaseList", "metadata": { "resourceVersion": "2179", "selfLink": "/apis/example.com/v1/namespaces/default/databases" } } 我们可以对
/apis/example.com/v1/namespaces/default/databases/wordpress
CRD
的
HTTP
路径
通过
curl
命令对的
"resourceVersion": "2154"
进行监控
watch: $ curl -f 127.0.0.1:8001/apis/example.com/v1/namespaces/default/databases?watch=true&resourceVersion=2154 现在我们新开一个
shell
对话窗口,删除
$ kubectl delete databases.example.com/wordpress 请注意:我们能够使用
kubectl delete database wordpress
删除
CRD
资源,是因为之前在
Kubernetes
没有定义有
database
资源。此外,
database
是我们
CRD
中的
spec.name.singular
字段
,从英语语法派生而来。 我们可以看到之前监控
watch CRD databases
从
API Server
处返回的更新状态: {"type":"DELETED","object":{"apiVersion":"example.com/v1","kind":"Database","metadata":{"clusterName":"","creationTimestamp":"2017-0[0/515] :38:30Z","deletionGracePeriodSeconds":null,"deletionTimestamp":null,"name":"wordpress","namespace":"default","resourceVersion":"2154","selfLink":"/apis/example.com/v1/namespaces/ default/databases/wordpress","uid":"8101a7af-7ce6-11e7-888c-42010a9a0fd5"},"spec":{"encoding":"unicode","password":"secret","user":"wp"}}} 上述
shell
会话的运行及输出结果如下图所示: 最后,让我们看一下
CRD database
的各个数据是如何存储在
etcd
中的。下面是我们直接通过
HTTP API
进入
etcd
访问得到的数据: $ curl -s localhost:2379/v2/keys/registry/example.com/databases/default | jq . { "action": "get", "node": { "key": "/registry/example.com/databases/default", "dir": true, "nodes": [ { "key": "/registry/example.com/databases/default/wordpress", "value": "{\"apiVersion\":\"example.com/v1\",\"kind\":\"Database\",\"metadata\":{\"clusterName\":\"\",\"creationTimestamp\":\"2017-08-09T14:53:40Z\",\"deletionGracePeriodSeconds\":null,\"deletionTimestamp\":null,\"name\":\"wordpress\",\"namespace\":\"default\",\"selfLink\":\"\",\"uid\":\"8837f788-7d12-11e7-9d28-080027390640\"},\"spec\":{\"encoding\":\"unicode\",\"password\":\"secret\",\"user\":\"wp\"}}\n", "modifiedIndex": 670, "createdIndex": 670 } ], "modifiedIndex": 670, "createdIndex": 670 } } 从上面可以看到,
CRD
数据在
etcd
中最终以一个未解析的的状态存在。现在将
CRD
删除,所有的
CRD
实例也会跟着删除,这是一个级联删除操作。 目前
CRDs
的使用现状,局限及将来的展望 CRDs
的发展现状如下所示: 1.
在
Kubernetes 1.7
版本中
CRDs
开始取代
2.
将
TPRs
迁移到
CRDs
实例可以参考文档
migration
。 3.
支持一个
CRD
中只有单个
version
版本,当然,一个群组中可能有多个
version
版本。 4.
CRDs
提供一个
API
方案,在用户角度看它与
Kubernetes
原生的
API
资源基本没有区别 5.
CRDs
是多版本多分支稳定的基础。关于
CRD
资源的
JSON-Schema
的格式有效性校验可以参考文档
CRD validation proposal
。相关资源回收可以参考文档
Garbage collection
。 接下去我们来看一下一些
CRDs
的局限: 1.
CRD
不提供版本转换功能,也就是说,每个
CRD
只能有一个版本(预计不会在近期或中期内看到支持
CRD
版本转换)。 2.
在
Kubernetes1.7
当中,目前并没有对于
CRD
的相关校验
validation
。 3.
没有快速,实时的准入(
admission
)机制(但是可以支持
webhooks
形式的初始化及准入)。 4.
在
Kubernetes1.7
中你不能定义子资源(
sub-resources
),比如
scale
或者
status
,不过目前有在这方面
proposal
的讨论。 5.
CRD
目前不支持默认值配置,即不支持为特定的字段配默认值(在
Kubernetes1.7
后续的版本中可能会支持)。 为了解决上述的问题,并且灵活的扩展
Kubernetes
,你可以运行一个与主
API Server
并行的用户
API Servers
。我们将在本博文的以后部分中详细介绍如何编写
UAS
,并编写一个
custom controller
完整使用
CRD
。https://www.huaweicloud.com/product/cce.html
curl
来实例对指定版本的
database
做监控
)之后的修改做监控
watch
。
wordpress
CRD
资源,我们可以查看刚才的监控
watch
窗口是否接收到了这个消息:
ThirdPartyResources
(TPRs)
,并且
TPRs
将会在
Kubernetes 1.8
被删除。
网页题目:深度剖析KubernetesAPIServer三部曲-part3-创新互联
网站URL:http://ybzwz.com/article/pcihd.html