前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【K8s】api-server 源码分析 01-01

【K8s】api-server 源码分析 01-01

原创
作者头像
Librant
修改2022-06-16 22:17:08
5290
修改2022-06-16 22:17:08
举报
文章被收录于专栏:跟我一起学 K8s跟我一起学 K8s

【注】源码分析均以 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:工作节点的列表
代码语言:go
复制
	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 接口
代码语言:go
复制
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 列表信息;
代码语言:go
复制
	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 代码不是很复杂,跟着代码的思路,基本都可以看懂,这里主要是接口的抽象和实例化,可以通过流程图进行分析;

(后续有机会可以出视频教程,这样讲解起来比较清楚)

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档