apiserver源码分析——启动流程

写在最后

学习技术是一条慢长而艰苦的道路,不能靠一时激情,也不是熬几天几夜就能学好的,必须养成平时努力学习的习惯。所以:贵在坚持!

最后再分享的一些BATJ等大厂20、21年的面试题,把这些技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,上面只是以图片的形式给大家展示一部分。

蚂蚁金服三面直击面试官的Redis三连,Redis面试复习大纲在手,不慌

Mybatis面试专题

蚂蚁金服三面直击面试官的Redis三连,Redis面试复习大纲在手,不慌

MySQL面试专题

蚂蚁金服三面直击面试官的Redis三连,Redis面试复习大纲在手,不慌

并发编程面试专题

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

三种类型的Server底层都需要依赖GeneriAPIServer。第二步创建的CustomResourceDefinitions是本类型Server的对象,用于后续进行路由注册。APIGroupInfo是用于每个版本、每个资源类型对应的存储对象。最后调用InstallAPIGroup进行路由注册,把每一个资源的版本,类型映射到一个URI地址中。代码如下所示

func createAPIExtensionsServer(apiextensionsConfig *apiextensionsapiserver.Config, delegateAPIServer genericapiserver.DelegationTarget) (*apiextensionsapiserver.CustomResourceDefinitions, error) {

return apiextensionsConfig.Complete().New(delegateAPIServer)

}

//代码位于 /vendor/k8s.io/apiextensions-apiserver/apiserver.go

func (c completedConfig) New(delegationTarget genericapiserver.DelegationTarget) (*CustomResourceDefinitions, error) {

//创建Generic

genericServer, err := c.GenericConfig.New(“apiextensions-apiserver”, delegationTarget)

//实例化 CustomResourceDefinitions

s := &CustomResourceDefinitions{

GenericAPIServer: genericServer,

}

//实例化APIGroupInfo

apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(apiextensions.GroupName, Scheme, metav1.ParameterCodec, Codecs)

if apiResourceConfig.VersionEnabled(v1beta1.SchemeGroupVersion) {

storage := map[string]rest.Storage{}

// customresourcedefinitions

customResourceDefinitionStorage, err := customresourcedefinition.NewREST(Scheme, c.GenericConfig.RESTOptionsGetter)

if err != nil {

return nil, err

}

storage[“customresourcedefinitions”] = customResourceDefinitionStorage

storage[“customresourcedefinitions/status”] = customresourcedefinition.NewStatusREST(Scheme, customResourceDefinitionStorage)

apiGroupInfo.VersionedResourcesStorageMap[v1beta1.SchemeGroupVersion.Version] = storage

}

//另一个版本的类似,不作展示

//InstallAPIGroup注册

if err := s.GenericAPIServer.InstallAPIGroup(&apiGroupInfo); err != nil {

return nil, err

}

}

KubeAPIServer

KubeAPIServer处理k8s内置资源请求,它的创建流程与APIExtensionServer类似,包含下面几个步骤

  • 创建GeneriAPIServer

  • 实例化Instance

  • installLegacyAPI

  • installAPI

其中Instance是KubeAPIServer的Server对象。KubeAPIServer创建和Install的APIGroup需要调用两个方法,一个是installLegacyAPI,另一个是installAPI,原因在于k8s的apiGroup分了/api和/apis两种。初期的资源其实没有apiGroup这个概念,而后期引入了groupVersion为了兼容原有的才把旧的资源类型的URI地址都归属于/api这个路径下的,新的全部在/apis这个路径下,因此在创建注册APIGroup时都分了两类。代码如下

func CreateKubeAPIServer(kubeAPIServerConfig *controlplane.Config, delegateAPIServer genericapiserver.DelegationTarget) (*controlplane.Instance, error) {

kubeAPIServer, err := kubeAPIServerConfig.Complete().New(delegateAPIServer)

if err != nil {

return nil, err

}

return kubeAPIServer, nil

}

//代码位于 /vendor/k8s.io/kube-aggregrator/pkg/apiserver/apiserver.go

func (c completedConfig) New(delegationTarget genericapiserver.DelegationTarget) (*Instance, error) {

//创建Generic

s, err := c.GenericConfig.New(“kube-apiserver”, delegationTarget)

//1.14版本的是Master,当前版本是Instance

m := &Instance{

GenericAPIServer: s,

ClusterAuthenticationInfo: c.ExtraConfig.ClusterAuthenticationInfo,

}

//实例化核心API

if c.ExtraConfig.APIResourceConfigSource.VersionEnabled(apiv1.SchemeGroupVersion) {

legacyRESTStorageProvider := corerest.LegacyRESTStorageProvider{

StorageFactory: c.ExtraConfig.StorageFactory,

ProxyTransport: c.ExtraConfig.ProxyTransport,

KubeletClientConfig: c.ExtraConfig.KubeletClientConfig,

EventTTL: c.ExtraConfig.EventTTL,

ServiceIPRange: c.ExtraConfig.ServiceIPRange,

SecondaryServiceIPRange: c.ExtraConfig.SecondaryServiceIPRange,

ServiceNodePortRange: c.ExtraConfig.ServiceNodePortRange,

LoopbackClientConfig: c.GenericConfig.LoopbackClientConfig,

ServiceAccountIssuer: c.ExtraConfig.ServiceAccountIssuer,

ExtendExpiration: c.ExtraConfig.ExtendExpiration,

ServiceAccountMaxExpiration: c.ExtraConfig.ServiceAccountMaxExpiration,

APIAudiences: c.GenericConfig.Authentication.APIAudiences,

}

if err := m.InstallLegacyAPI(&c, c.GenericConfig.RESTOptionsGetter, legacyRESTStorageProvider); err != nil {

return nil, err

}

}

restStorageProviders := []RESTStorageProvider{…}

//InstallAPIs,内部包含InstallAPIGroup

if err := m.InstallAPIs(c.ExtraConfig.APIResourceConfigSource, c.GenericConfig.RESTOptionsGetter, restStorageProviders…); err != nil {

return nil, err

}

}

注册核心apiGroups

进入m.InstallLegacyAPI,这个方法包含了实例化ApiGroupInfo和InstalAPIGroup两个操作,这部分资源是k8s的核心资源

func (m *Instance) InstallLegacyAPI(c *completedConfig, restOptionsGetter generic.RESTOptionsGetter, legacyRESTStorageProvider corerest.LegacyRESTStorageProvider) error {

//实例化ApiGroupInfo

legacyRESTStorage, apiGroupInfo, err := legacyRESTStorageProvider.NewLegacyRESTStorage(restOptionsGetter)

if err != nil {

return fmt.Errorf(“error building core storage: %v”, err)

}

controllerName := “bootstrap-controller”

coreClient := corev1client.NewForConfigOrDie(c.GenericConfig.LoopbackClientConfig)

bootstrapController := c.NewBootstrapController(legacyRESTStorage, coreClient, coreClient, coreClient, coreClient.RESTClient())

m.GenericAPIServer.AddPostStartHookOrDie(controllerName, bootstrapController.PostStartHook)

m.GenericAPIServer.AddPreShutdownHookOrDie(controllerName, bootstrapController.PreShutdownHook)

//相当于调用InstallAPIGroup

if err := m.GenericAPIServer.InstallLegacyAPIGroup(genericapiserver.DefaultLegacyAPIPrefix, &apiGroupInfo); err != nil {

return fmt.Errorf(“error in registering group versions: %v”, err)

}

return nil

}

实例化APIGroupInfo的代码局部如下,代码篇幅较长,只摘取pod一部分的源码展示,代码位于/pkg/registry/core/rest/storage_core.go

func (c LegacyRESTStorageProvider) NewLegacyRESTStorage(restOptionsGetter generic.RESTOptionsGetter) (LegacyRESTStorage, genericapiserver.APIGroupInfo, error) {

apiGroupInfo := genericapiserver.APIGroupInfo{

PrioritizedVersions: legacyscheme.Scheme.PrioritizedVersionsForGroup(“”),

VersionedResourcesStorageMap: map[string]map[string]rest.Storage{},

Scheme: legacyscheme.Scheme,

ParameterCodec: legacyscheme.ParameterCodec,

NegotiatedSerializer: legacyscheme.Codecs,

}

podStorage, err := podstore.NewStorage(

restOptionsGetter,

nodeStorage.KubeletConnectionInfo,

c.ProxyTransport,

podDisruptionClient,

)

restStorageMap := map[string]rest.Storage{

“pods”: podStorage.Pod,

“pods/attach”: podStorage.Attach,

“pods/status”: podStorage.Status,

“pods/log”: podStorage.Log,

“pods/exec”: podStorage.Exec,

“pods/portforward”: podStorage.PortForward,

“pods/proxy”: podStorage.Proxy,

“pods/binding”: podStorage.Binding,

“bindings”: podStorage.LegacyBinding,

}

}

m.GenericAPIServer.InstallLegacyAPIGroup的第一个参数是apiPrefix,值是/api;第二个参数是上面创建好的,包含资源存储方式的apiGroupInfo

与InstallAPIGroup类似地,InstallLegacyAPIGroup需要经过两层调用才会到达InstallREST,调用链如下

m.GenericAPIServer.InstallLegacyAPIGroup

|–s.installAPIResources

|–apiGroupVersion.InstallREST

InstallREST的入参是restful.Container,他是golang http框架go-restful里面的一个重要对象,在InstallREST里面构造出installer,installer包含资源的存储方法和资源对应api的前缀,利用installer.Install()来创建出go-restful的webservice,webservice加入到传入得container,即完成api的注册。

代码位于/vendor/k8s.io/apiserver/pkg/endpoints/groupversion.go

func (g *APIGroupVersion) InstallREST(container *restful.Container) error {

prefix := path.Join(g.Root, g.GroupVersion.Group, g.GroupVersion.Version)

installer := &APIInstaller{

group: g,

prefix: prefix,

minRequestTimeout: g.MinRequestTimeout,

}

apiResources, ws, registrationErrors := installer.Install()

versionDiscoveryHandler := discovery.NewAPIVersionHandler(g.Serializer, g.GroupVersion, staticLister{apiResources})

versionDiscoveryHandler.AddToWebService(ws)

container.Add(ws)

return utilerrors.NewAggregate(registrationErrors)

}

installer.Install()方法的边幅很长,它既然创建了webservice,api中各个URL的路由注册,handler的绑定也会在里面实现。由于这部分代码也涉及到apiserver如何响应处理一个http请求,本篇先不探讨

go-restful框架

不过上面提及到go-restful框架的几个概念,在这里进行一个简单的科普

  • container:在http的角度就是一个Server,里面就包含若干个webservice

  • webservice:webservice从结构来说是承上启下的一个角色,它包含了一组route,而且这组route都会有一个共同的basePath或者说他们的URL的prefix是相同的

  • route:route对应具体的一个URL,它需要指定具体的路径Path,请求方法Method和处理函数Handler,以及一些参数Parameter等等。

他们的层次结构如下

container

|–webservice

|–Route

AggregratorServer

用于处理聚合进来的api请求,实际是做七层转发,它的创建流程与APIExtensionServer的最为相似

  • 创建GeneriAPIServer

  • 实例化Aggregrator

  • 实例化APIGroupInfo

  • InstallAPIGroup

实际创建AggregratorServer的代码位于/vendor/k8s.io/kube-aggregrator/pkg/apiserver/apiserver.go

func (c completedConfig) NewWithDelegate(delegationTarget genericapiserver.DelegationTarget) (*APIAggregator, error) {

//创建GeneriAPIServer

genericServer, err := c.GenericConfig.New(“kube-aggregator”, delegationTarget)

//实例化Aggregrator

s := &APIAggregator{…}

//实例化APIGroupInfo

apiGroupInfo := apiservicerest.NewRESTStorage(c.GenericConfig.MergedResourceConfig, c.GenericConfig.RESTOptionsGetter)

//InstallAPIGroup

if err := s.GenericAPIServer.InstallAPIGroup(&apiGroupInfo); err != nil {

return nil, err

}

}

运行http server

api的路由绑定完毕,最后就是要把http server跑起来,prepared.Run调用的是由preparedGenericAPIServer实现的Run方法,经过多层调用最终把server跑起来,调用链如下

prepared.Run /vendor/k8s.io/kube-aggregrator/pkg/apiserver/apiserver.go

|–s.runnable.Run(stopCh)

|==preparedGenericAPIServer.Run /vendor/k8s.io/apiserver/pkg/server/genericapiserver.go

|–s.NonBlockingRun

|–s.SecureServingInfo.Serve /vendor/k8s.io/kube-aggregrator/pkg/server/secure_serving.go

|–&http.Server{}

|–RunServer

http server的对象是在SecureServingInfo.Serve创建的,即调用链的s.SecureServingInfo.Serve,最终让server开始监听是在RunServer处。它接收了http.Server作为参数。至此apiserver运行起来,接收来自各个组件或客户端的请求。

小结

本篇讲述了k8s-apiserver的启动流程,介绍了apiserver包含了3个server组件,apiserver的服务实际上由这三个组件提供,讲述了他们创建流程,实例化底层的GenericServer,实例化各自的Server类,实例化ApiGroupInfo来建立资源与存储操作间的映射关系,最后InstallAPI。还专门挑了k8s核心资源类型的ApiGroup注册过程介绍。整个启动过程的调用链如下

Run /cmd/kube-apiserver/app/server.go

|–CreateServerChain

| |–CreateKubeAPIServerConfig

| | |–buildGenericConfig

| | |–genericapiserver.NewConfig

| | |–s.Authentication.ApplyTo

| | |–BuildAuthorizer

| | |–s.Admission.ApplyTo

| |–createAPIExtensionsConfig

| |–createAPIExtensionsServer

| | |–apiextensionsConfig.Complete().New /vendor/k8s.io/apiextensions-apiserver/apiserver.go

| | |–c.GenericConfig.New

| | |–&CustomResourceDefinitions{}

| | |–genericapiserver.NewDefaultAPIGroupInfo

| | |–s.GenericAPIServer.InstallAPIGroup

| |–CreateKubeAPIServer

| | |–kubeAPIServerConfig.Complete().New /pkg/controlplane/instance.go

| | | |–c.GenericConfig.New

| | | |–&Instance{}

| | | |–m.InstallLegacyAPI /pkg/controlplane/instance.go

| | | | |–legacyRESTStorageProvider.NewLegacyRESTStorage /pkg/registry/core/rest/storage_core.go

| | | | |–m.GenericAPIServer.InstallLegacyAPIGroup ##相当于新版本的InstallAPIGroup

| | | | | |–s.installAPIResources

| | | | | | |–apiGroupVersion.InstallREST

| | | |–m.InstallAPIs

| |–createAggregatorConfig

| |–createAggregatorServer

| |–aggregatorConfig.Complete().NewWithDelegate /vendor/k8s.io/kube-aggregrator/pkg/apiserver/apiserver.go

| |–c.GenericConfig.New

| |–&APIAggregator{}

| |–apiservicerest.NewRESTStorage

| |–s.GenericAPIServer.InstallAPIGroup

|–server.PrepareRun /vendor/k8s.io/kube-aggregrator/pkg/apiserver/apiserver.go

| |–s.GenericAPIServer.PrepareRun /vendor/k8s.io/kube-aggregrator/pkg/server/genericapiserver.go

| |–s.installHealthz()

| |–s.installLivez()

| |–s.installReadyz()

|–prepared.Run /vendor/k8s.io/kube-aggregrator/pkg/apiserver/apiserver.go

|–s.runnable.Run(stopCh)
|==preparedGenericAPIServer.Run /vendor/k8s.io/apiserver/pkg/server/genericapiserver.go
|–s.NonBlockingRun
|–s.SecureServingInfo.Serve /vendor/k8s.io/kube-aggregrator/pkg/server/secure_serving.go
|–&http.Server{}
|–RunServer

最后

即使是面试跳槽,那也是一个学习的过程。只有全面的复习,才能让我们更好的充实自己,武装自己,为自己的面试之路不再坎坷!今天就给大家分享一个Github上全面的Java面试题大全,就是这份面试大全助我拿下大厂Offer,月薪提至30K!

我也是第一时间分享出来给大家,希望可以帮助大家都能去往自己心仪的大厂!为金三银四做准备!
一共有20个知识点专题,分别是:

Dubbo面试专题

JVM面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

Java并发面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

Kafka面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

MongDB面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

MyBatis面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

MySQL面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

Netty面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

RabbitMQ面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

Redis面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

Spring Cloud面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

SpringBoot面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

zookeeper面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

常见面试算法题汇总专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

计算机网络基础专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

设计模式专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

1715810906246)]

RabbitMQ面试专题

[外链图片转存中…(img-84Kmomlq-1715810906246)]

Redis面试专题

[外链图片转存中…(img-c8J2jEAg-1715810906246)]

Spring Cloud面试专题

[外链图片转存中…(img-qeaYhx8L-1715810906247)]

SpringBoot面试专题

[外链图片转存中…(img-fjqqDyOo-1715810906247)]

zookeeper面试专题

[外链图片转存中…(img-bec0G3dM-1715810906247)]

常见面试算法题汇总专题

[外链图片转存中…(img-3hSGZjZH-1715810906248)]

计算机网络基础专题

[外链图片转存中…(img-bcTQyPRH-1715810906248)]

设计模式专题

[外链图片转存中…(img-gyiTfG39-1715810906248)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值