概述
在上一篇中,我介绍了如何创建一个 CRD 以及通过这个 CRD 来创建 CR。这些关于 CR 的操作都是通过 kubectl 命令来完成的,但是,事实上,到目前位置,kubectl 是如何操作这些 CR 的我们还是不清楚。
对于后面还有很多内容都是需要代码和 CR 关联的,所以,我觉得在开始一些代码的工作之前,有必要先对 Kubernetes 的 Resource 机制进行一些介绍。在 Kubernetes 入门第二篇 中,我介绍了 API Server 是用于资源操作的组件,事实上,之前我是说可以认为是作为 etcd 的一个接口来理解,但是,实际上 API Server 完成的工作不仅仅这么简单,从上一篇的这张图可以看到:
API Server 完成了相当多的事情,但是,就目前而言,这些事情基本上都还不需要关心,这一篇要关心的就是,到底 kubectl 是如何操作 API Server 中的资源的。
GVK
从上一篇中的 CRD 定义中,可以发现在 Kubernetes 中要想完成一个 CRD,需要指定 group
/kind
和 version
,这个在 Kubernetes 的 API Server 中简称为 GVK。GVK 是定位一种类型的方式,例如,daemonsets 就是 Kubernetes 中的一种资源,当我们跟 Kubernetes 说我想要创建一个 daemonsets 的时候,kubectl 是如何知道该怎么向 API Server 发送呢?是所有的不同资源都发向同一个 URL,还是每种资源都是不同的?
这就得看回我定义 daemonsets 的描述文件了:
[[email protected]]# head -4 00-sample-daemonsets.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: node-exporter
这里我就声明了 apiVersion 是 apps/v1
,其实就是隐含了 Group
是 apps,Version
是 v1,Kind
就是定义的 DaemonSet,而 kubectl 接收到这个声明之后,就可以根据这个声明去调用 API Server 对应的 URL 去获取信息,例如这个就是 /api/apps/v1/daemonset
(kubetl 怎么知道 DaemonSet 对应的就是 daemonset?第一篇有说到)。
可能到这里你已经猜到了,Kubernetes 组织资源的方式是以 REST 的 URI 的形式来的,而组织的路径就是:
额,不对,不是说是 G(roup)V(ersion)K(ind) 的吗,怎么这里又是 G(roup)V(ersion)R(ource) ?嘿,是的,这就是 API Server 中的第二个概念,GVR。
GVR
其实,理解了 GVK 之后再理解 GVR 就很容易了,这就是面向对象编程里面的类和对象的概念是一样的:
Kubernetes | OOP |
---|---|
Kind | Class |
Resource | Object |
好理解吧,Kind 其实就是一个类,用于描述对象的;而 Resource 就是具体的 Kind,可以理解成类已经实例化成对象了。
REST Mapping
当我们要定义一个 GVR 的时候,那么怎么知道这个 GVR 是属于哪个 GVK 的呢?也就是前面说的,kubectl 是如何从 YAML 描述文件中知道该请求的是哪个 GVR URL?这就是 REST Mapping 的功能,REST Mapping 可以指定一个 GVR(例如 daemonset 的这个例子),然后它返回对应的 GVK 以及支持的操作等。
在代码中,其实就对应于这个接口:
这样,就把 GVK 和 GVR 联系起来了。
API Server
既然,前面都说了,API Server 可以通过 URI 的形式访问到资源,那么这里我就来实战一下,一般来说,如果是正常安装的 Kubernetes 集群,那么肯定会有 http 证书以及认证证书,这会让我的尝试很麻烦,所以,为了去掉这重麻烦,我会通过 kubectl proxy
来代理一个本地的 API Server 端口,这样就可以绕过认证了,直接可以以 http 的形式进行:
[[email protected]]# kubectl proxy --port=9090
Starting to serve on 127.0.0.1:9090
然后直接访问 API Server:
[[email protected]]# GET http://127.0.0.1:9090/apis/apps/v1/daemonsets/
{
"kind": "DaemonSetList",
"apiVersion": "apps/v1",
"metadata": {
"selfLink": "/apis/apps/v1/daemonsets/",
"resourceVersion": "209282"
},
"items": [
{
"metadata": {
"name": "svclb-traefik",
"namespace": "kube-system",
"selfLink": "/apis/apps/v1/namespaces/kube-system/daemonsets/svclb-traefik",
"uid": "bd42f48c-42de-4df6-96bd-15e56bdfaec7",
"resourceVersion": "176921",
"generation": 2,
... ...
因为内容太多,就不一一展示了。
核心资源
如果想看系统支持哪些 GVK,那么可以通过 kubectl 的命令查看:
[[email protected]]# k api-resources
NAME | SHORTNAMES | APIGROUP | NAMESPACED | KIND |
---|---|---|---|---|
pods | po | true | Pod | |
services | svc | true | Service | |
mutatingwebhookconfigurations | admissionregistration.k8s.io | false | MutatingWebhookConfiguration | |
validatingwebhookconfigurations | admissionregistration.k8s.io | false | ValidatingWebhookConfiguration | |
customresourcedefinitions | crd,crds | apiextensions.k8s.io | false | CustomResourceDefinition |
apiservices | apiregistration.k8s.io | false | APIService | |
controllerrevisions | apps | true | ControllerRevision | |
daemonsets | ds | apps | true | DaemonSet |
这里可能你会发现一些特别的地方,就是对于 Pod
和 Service
,它的 API GROUP 居然是空的,这又是什么意思?这其实就是 Kubernetes 核心资源的含义,也就是所谓的 Kubernetes 中的基础资源(Kubernetes Resource),他们不需要 Group,只有 Version 和 Kind,其实,我认为这是历史原因导致的,在 Kubernetes 的开始之初还不支持自定义类型的时候就没考虑过 Group。