【注】源码分析均以 k8s 的第一个 commit 代码分析;
代码语言:go复制cmd/apiserver/apiserver.go
api-server 的入口代码(main)函数的位置;
在 apiserver.go 中,定义 apiserver 启动的相关参数:
- port/address: IP:Port, apiserver 启动监听的端口;
- apiPrefix: 访问 api-server 的 URL 前缀
- etcdServerList: etcd 存储节点列表
- machineList:工作节点的列表
var (
taskRegistry registry.TaskRegistry
controllerRegistry registry.ControllerRegistry
serviceRegistry registry.ServiceRegistry
)
主要是三个接口:
- TaskRegistry
- ControllerRegistry
- ServiceRegistry
对于设置 etcd 存储节点的的 api-server 的启动参数,需要实例化 etcd 的客户端,用于访问 etcd 节点;
对于有 etcd 节点列表的实例化:
代码语言:go复制etcdClient := etcd.NewClient(etcdServerList)
taskRegistry = registry.MakeEtcdRegistry(etcdClient, machineList)
controllerRegistry = registry.MakeEtcdRegistry(etcdClient, machineList)
serviceRegistry = registry.MakeEtcdRegistry(etcdClient, machineList)
使用 etcd 存储节点的,可以进行数据持久化;
对于没有 etcd 节点列表的实例化:
代码语言:go复制taskRegistry = registry.MakeMemoryRegistry()
controllerRegistry = registry.MakeMemoryRegistry()
serviceRegistry = registry.MakeMemoryRegistry()
没有 etcd 存储节点,使用内存保存信息,不能持久化;
taskRegistry 的实例化:
代码语言:go复制pkg/registry/etcd_registry.go
func MakeEtcdRegistry(client EtcdClient, machines []string) *EtcdRegistry {}
对于 EtcdRegistry 结构体:
代码语言:go复制// EtcdRegistry is an implementation of both ControllerRegistry and TaskRegistry which is backed with etcd.
type EtcdRegistry struct {
etcdClient EtcdClient
machines []string
manifestFactory ManifestFactory
}
这个结构体中有三个成员变量:
- etcdClient:访问 etcd 的客户端
- machines: 工作节点的 IP 列表
- manifestFactory:ManifestFactory 接口
MakeManifest(machine string, task Task) (ContainerManifest, error)
这个接口只有 MakeManifest 方法,主要是用于根据机器和任务信息,生成容器信息;
对于 manifestFactory 接口的实例化:
代码语言:go复制registry.manifestFactory = &BasicManifestFactory{
serviceRegistry: registry,
}
通过一个基本的 BasicManifestFactory 结构体实例化:
代码语言:go复制type BasicManifestFactory struct {
serviceRegistry ServiceRegistry
}
在这个结构体中,是一个 ServiceRegistry 的接口类型;
在 MakeEtcdRegistry 函数中,用的是 EtcdRegistry 结构的实例进行实现;
EtcdRegistry 结构同样实现了 ServiceRegistry 的接口;
那再分析下 ServiceRegistry 接口:
代码语言:go复制type ServiceRegistry interface {
ListServices() (ServiceList, error)
CreateService(svc Service) error
GetService(name string) (*Service, error)
DeleteService(name string) error
UpdateService(svc Service) error
UpdateEndpoints(e Endpoints) error
}
总共有六个方法,对于 EtcdRegistry 结构,需要实现这六个方法:
在 pkg/registry/service_registry.go 中:
代码语言:go复制type ServiceRegistryStorage struct {
registry ServiceRegistry
}
这个 ServiceRegistryStorage 结构体中同样有 ServiceRegistry 接口的成员变量;
这个结构体实现 apiserver.RESTStorage 接口;
代码语言:go复制func MakeServiceRegistryStorage(registry ServiceRegistry) apiserver.RESTStorage {}
再回过头来到 main() 函数中:
- taskRegistry
- controllerRegistry
- serviceRegistry 这个三个都是 EtcdRegistry 结构的实例;
container 的信息获取是通过:
代码语言:go复制 containerInfo := &kube_client.HTTPContainerInfo{
Client: http.DefaultClient,
Port: 10250,
}
这个地方只是保存了 http 的客户端和需要访问的端口信息;
代码语言:go复制 storage := map[string]apiserver.RESTStorage{
"tasks": registry.MakeTaskRegistryStorage(taskRegistry, containerInfo, registry.MakeFirstFitScheduler(machineList, taskRegistry)),
"replicationControllers": registry.MakeControllerRegistryStorage(controllerRegistry),
"services": registry.MakeServiceRegistryStorage(serviceRegistry),
}
这里 storage 是通过 map 的方式进行存储, key 是支持的三个 Registry 的名字,后续可以通过名字找到对应的 RESTStorage 接口;
- MakeTaskRegistryStorage()
- MakeControllerRegistryStorage()
- MakeServiceRegistryStorage()
这个三个函数分别生成对应的 apiserver.RESTStorage 接口的实现;
代码语言:go复制 endpoints := registry.MakeEndpointController(serviceRegistry, taskRegistry)
go util.Forever(func() { endpoints.SyncServiceEndpoints() }, time.Second*10)
对于 EndpointController 结构:
代码语言:go复制type EndpointController struct {
serviceRegistry ServiceRegistry
taskRegistry TaskRegistry
}
这个结构体中,serviceRegistry 和 taskRegistry 接口参数;
- SyncServiceEndpoints(): 函数主要的功能是:每 10s 同步一次 Endpoint 列表信息;
s := &http.Server{
Addr: fmt.Sprintf("%s:%d", *address, *port),
Handler: apiserver.New(storage, *apiPrefix),
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
MaxHeaderBytes: 1 << 20,
}
log.Fatal(s.ListenAndServe())
最后启动 http 的服务;
第一个 commit 的 api-server 代码不是很复杂,跟着代码的思路,基本都可以看懂,这里主要是接口的抽象和实例化,可以通过流程图进行分析;
(后续有机会可以出视频教程,这样讲解起来比较清楚)