前言
了解 k8s 的同学都知道,kube-apiserver 对外提供 RESTful API 接口提供 查询,监听集群(资源)状态的服务,kube-apiserver 主要就做一件事,就是如何将 RESTful API (CREATE, DELETE, UPDATE, GET .etc)接口调用映射到对后端存储(比如 etcd)的(增删改查)访问,在设计的时候考虑到 k8s 是个快速迭代的开源项目,很多 API 接口(版本)可能在未来版本发生变化,因此如何设计一个扩展性强,耦合度低的架构应该是 Google 那帮货当初主要考虑的问题,所以才导致 kube-apiserver 本来相比 kube-scheduler 和 kube-controller-manager 应该简单的代码设计的巨复杂(个人观点)~
从 kube-apiserver 收到 RESTful API 请求到从 后端存储中获取(更新 .etc)到数据大概需要经过一下几层(非官方命名),各层之间通过 《接口》 交互(解偶)
RESTful API
||
<REST Operation Interface>
||
Storage
||
<Storage Backend Interface>
||
Sotrage Backend(etcd2,etcd3)
比如 Storage 和 Storage Backend 之间通过 Storage Backend Interface(参考k8s :kube-apiserver 访问 etcd 后端存储 )交互,Storage 和 RESTful API 之间通过 REST Operation Interface(增删改查 方法的封装)交互
Storage
Storage is a generic interface for RESTful storage services.
Resources which are exported to the RESTful API of apiserver need to implement this interface(原文注释,下同)
It is expected that objects may implement any of the below interfaces
所有想通过 RESTful API 暴露出去的资源都必须实现 Storage 接口,Storage 接口是个最小接口(单一职责),资源类可以根据自身情况实现其它各种接口
// kubernetes/staging/src/k8s.io/apiserver/pkg/registry/rest/rest.go
type Storage interface {
New() runtime.Object
}
REST Operation Interface
StandardStorage is an interface covering the common verbs. Provided for testing whether a resource satisfies the normal storage methods.
Use Storage when passing opaque storage objects
StandardStorage
type StandardStorage interface {
Getter
Lister
GreaterUpdater
GracefulDeleter
CollectionDeleter
Watcher
}
StandardStorage 聚合了可以对 Storage 施加的操作(或者叫 Verb,动作),RESTful API根据该(子)接口测试 Storage 是否支持相关操作,然后注册相应的 API 接口,比如如果 Storage 支持 Delete 接口,就注册一个 HTTP method 为 DELETE 的方法到相应的资源路径
Storage 实现类
kubernetes/pkg/registry/core 目录下包含了各种 Storage 实现类,比如大家耳熟能详的 pod, service, endpoint, configmap, node 等等,各个资源的目录结构很相似,以 pod 为例
kubernetes/pkg/registry/core/pod
rest
storage
storage.go <- Storage 实现
doc.go
strategy.go
strategy_test.go
PodStorage
我们以 pod storage 为例来分析 storage 创建,首先是 pod storage 定义
type PodStorage struct {
Pod *REST
Binding *BindingREST
Eviction *EvictionREST
Status *StatusREST
Log *podrest.LogREST
Proxy *podrest.ProxyREST
Exec *podrest.ExecREST
Attach *podrest.AttachREST
PortForward *podrest.PortForwardREST
}
这里又冒出一些新的类型 REST,BindingREST .etc,这些 XXXREST 才是"真正"的 Storage,对应具体的 RESTful endpoint
// REST implements a RESTStorage for pods
type REST struct {
*genericregistry.Store
proxyTransport http.RoundTripper
}
// BindingREST implements the REST endpoint for binding pods to nodes when etcd is in use
type BindingREST struct {
store *genericregistry.Store
}
XXXREST 类类包含一个 genericregistry.Store 类型的字段,我们在k8s :kube-apiserver 访问 etcd 后端存储中分析过,它用于访问后端存储
PodStorage 通过 NewStorage 方法创建,各个 XXXREST 共享 Store
func NewStorage(optsGetter generic.RESTOptionsGetter, ...) {
创建 genericregistry.Store
store := &genericregistry.Store {
...
}
...
return PodStorage {
Pod: &REST{store, proxyTransport},
Binding: &BindingREST{store: store}
...
}
}
Storage 注册
Storage 是如何"绑定"到 api 接口呢?这中间还涉及到一些数据结构(类),这里先列出绑定相关的代码:
// kubernetes/pkg/registry/core/rest/storage_core.go
func (c LegacyRESTStorageProvider) NewLegacyRESTStorage(...) {
...
restStorageMap := map[string]rest.Storage {
"pods": podStorage.Pod,
"pods/attach": podStorage.Attach
...
}
}
后续再详细分析
总结
本文介绍了 kube-apiserver 中 Storage 相关的一些概念,希望对大家阅读 k8s 源代码有所帮助