关于Kubernetes REST API的工作方式:
在哪里以及如何定义从REST路径到处理REST调用的函数的映射?
与etcd的交互发生在哪里?
从客户端发出请求到保存在etcd中对象的端到端路径是怎样的?
Kubernetes REST框架
Kubernetes REST实现可大致分为三个部分,如下图所示。
客户端/服务器功能通过k8s.io包中的各种库实现。服务器端实现分布在多个包中。
服务器端的根目录包是apiserver, 其包含有endpoints,server,registry和storage等重要的包。
客户端在client-go包中实现,其包含的主要包是rest。
几个关键Kubernetes概念
1)组(Group)
KubernetesREST API以层次结构组织,并以/apis为根。 一个组为根下的一组REST资源集定义一个逻辑名称。例如API组名为apps,它在层次结构中就表示为/apis/apps。
可以使用如下命令检查所有可用的API组:
kubectl get --raw/apis | python -mjson.tool
2)版本(Version)
KubernetesREST API使用版本。版本名用于定义REST资源端点,这些资源短点在组内不断演变。典型的版本名称有v1,v1alpha1,v1beta1。可以使用如下命令查找API组的所有可用版本:
kubectl get-raw /apis/<group-name>
例如,想找apps组下的所有可用版本,可使用如下命令:
kubectl get --raw/apis/apps | python -mjson.tool
3)类型(Type)
表示概念的命名实体(例如:Pod,Deployment,Service等)。
4)种类(Kind)
Kubernetes类型的JSON/YAML表示。
5)资源(Resource)
处理特定种类的REST请求的端点/路径。资源在api层次结构中通用表示为:
/apis/<group>/<version>/namespaces/<namespace>/<kind-plural>
例如, deployments可表示为
/apis/apps/v1/namespaces/default/deployments
服务器端
服务器端集中探究以下问题:
A: 服务器中注册了哪些资源?
B: 与etcd的交互发生在哪里?
1)genericapiserver.go
文件先定义APIGroupInfo类型用于保存关于API组的信息,例如存在哪些版本以及在这些版本中定义了哪些资源。其次,定义GenericAPIServer类型,并实现为API组注册REST端点的InstallAPIGroup方法。该方法在api组版本实例中内部调用InstallREST方法。为运行服务器端,GenericAPIServer还包含Run()方法。
2)groupversion.go
文件先定义APIGroupVersion类型,用于承载关于某api组的特定版本的信息,例如引用提供实际REST端点实现(store.go)的对象的引用。还定义InstallREST方法,内部调用安装程序上的Install方法来注册该版本的REST资源。
3)installer.go
文件定义实现Install方法的APIInstaller类型。Install方法使用GroupVersion实例中的REST实现对象(请参见第2点),以将REST路径注册到go-restful库中的处理函数映射。当使用这个库时,模式是为一个特定的REST路径定义一个可调用的`handler`函数。该模式在installer.go中用于设置处理对应于不同资源端点。
例如:ws.GET(action.Path).To(handler), 其中handler是从GroupVersion实例的REST实现对象中获得的函数。它被定义为处理action.Path上的GET请求时被调用。
4)master.go
文件先定义了包含指向GenericAPIServer实例的指针的Master类型。还定义了InstallAPIs方法,通过调用genericapiserver的InstallAPIGroup方法启动注册工作流程。在创建Master的新实例时,InstallAPIs方法被调用。
5)registry/rest/rest.go
文件定义了不同的各种接口,应该被任何想要提供Kubernetes-like REST端点的后端实现。该文件中的关键接口是:Storage和StandardStorage。REST实现对象的引用属于rest.Storage接口类型,该对象由在groupversion.go中的APIGroupVersion维护。
6)registry/generic/registry/store.go
文件定义了实现rest.StandardStorage接口的Store类型。方法实现在由Store类型维护的Storage对象上的调用。此对象的类型为storage.Inte**ce(请参见下文)。
7)storage/Interface.go
文件定义了一个名为Interface的接口,包含一些方法。如果我们想可用于实际持久化的store,必须实现这些方法。对于'Interface'接口中所有方法,一个关键点是它们只返回error而没有其他的内容。如果任何数据需要由方法返回,将通过一个指针作为参数传递的对象返回。作为一个例子,检查签名的Get方法。
8)storage/etcd3/store.go
文件定义了实现storage.Interface的Store类型它使用etcd 的clientv3库与etcd3进行交互。
客户端
在客户端,我们主要探究REST调用如何进行?
1)request.go
文件定义了Request类型,实现用于在资源上进行REST调用的方法。进行调用的模式是先创建一个NewRequest对象,然后使用流式样方法链来调用REST方法(GET,POST,PUT,DELETE)。资源和名称空间的名称是创建完整端点所必需的,它们通过链式方法调用进行定义。
2)client.go
文件首先定义了一个名为Interface的接口,它包含返回Request对象指针(在request.go中定义)的REST方法包装器。其次定义了实现Interface接口的REST Client类型。
进行REST调用的模式是首先创建一个NewRESTClient,然后通过其中一个REST方法包装体获取NewRequest对象。一旦NewRequest对象可用,REST调用就像上面解释的那样使用方法链进行。
探究
1. Kubernetes代码拥有丰富的文档,这有助于理解一段代码作用。
2. 包含类型隐含地实现方法的地方,可以很方便的在Interfaces中统计所有方法,进而很容易明白该类型实现了哪些方法。 (注册表包很好地实现了这一点,但installer.go是一个不会发生这种情况的例子。)
3. Golang导入别名可以帮助确定一个方法来自哪个包。虽然代码确实使用了别名,但还有更广泛的使用它们的空间。