K8sApi-Server流程简述

更新时间:2023-07-25 20:43:16 阅读: 评论:0

K8sApi-Server流程简述
最近开发环境的k8s出现过⼀次读取不出来configmap,并导致api-rver OOM重启的现象,供应商说是因为configmap条⽬太多,导致api-rver⼤量decode etcd的数据为yaml所致。在原⽣k8s上反复重试过多次,均⽆法复现该现象,所以⼜看了⼀遍api-rver⼤致的代码逻辑,这⾥简单记录⼀下。
小提琴名曲核⼼业务逻辑
在看代码之前,基于对k8s架构的理解,我猜测:api-rver应该就是对etcd的⼀层代理。其中需要实现了对各种资源的路由、准⼊控制、限速、资源的格式转换以及各种操作的接⼝封装等功能。具体代码逻辑⼜实现了些什么呢?下⾯来简单介绍。
其实和猜测的差不多,从⼊⼝之后,api-rver就调⽤CreateServerChain来创建了⼀系列的服务,包括:
KubeApiServer
也就是为k8s定义的抽象资源(⽐如workload,rvice,configmap等)提供服务;
ApiExtensionsServer
主要负责CRD相关的服务;
AggregatorServer
这个不太熟,但是顾名思义,应该就是服务api aggregator的。
代码框架
先上⼀张⼤图,也是为了之后看图就能够快速定位代码逻辑。有机结合
转存失败
前⾯说的那三种rver,其实就在⼤图中左上⾓部分,下⾯在 #总⼊⼝ 中要重点讲下router这部分的逻辑。
总⼊⼝
接下来,我们找熟悉的KubeApiServer分析。函数CreateKubeAPIServer调⽤了kubeAPIServerConfig.Complete().New。通过该函数,基本看出了端倪,api-rver是通过webrver的形势对外提供api服务的;该函数⾸先准备了⼀堆的资源组,然后将这
些RESTStorageProvider安装到了Master,这⾥可以理解为准备router信息(较抽象)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26func (c completedConfig) New(delegationTarget genericapirver.DelegationTarget) (*Master, error) {
// 准备所有的资源组
restStorageProviders := []RESTStorageProvider{
auditregistrationrest.RESTStorageProvider{},
authenticationrest.RESTStorageProvider{Authenticator: c.GenericConfig.Authentication.Authenticator, APIAudiences:
c.GenericConfig.Authentication.APIAudiences},
authorizationrest.RESTStorageProvider{Authorizer: c.GenericConfig.Authorization.Authorizer, RuleResolver: c.GenericConfig.RuleResolver},  autoscalingrest.RESTStorageProvider{},
batchrest.RESTStorageProvider{},
certificatesrest.RESTStorageProvider{},
coordinationrest.RESTStorageProvider{},
extensionsrest.RESTStorageProvider{},
networkingrest.RESTStorageProvider{},
noderest.RESTStorageProvider{},
policyrest.RESTStorageProvider{},
rbacrest.RESTStorageProvider{Authorizer: c.GenericConfig.Authorization.Authorizer},
schedulingrest.RESTStorageProvider{},
ttingsrest.RESTStorageProvider{},
storagerest.RESTStorageProvider{},
appsrest.RESTStorageProvider{},
admissionregistrationrest.RESTStorageProvider{},
eventsrest.RESTStorageProvider{TTL: c.ExtraConfig.EventTTL},
}
// 第⼆个重点, 安装资源handler了
m.InstallAPIs(c.ExtraConfig.APIResourceConfigSource, c.GenericConfig.RESTOptionsGetter, )
}
以上只是粗枝⼤叶的⼊门,如果要对资源router的挂载搞透彻,我们还需要理解进⼀步理解这⾥的资源,以及InstallAPIs的流程。
资源组织
k8s api的定义中,对rest-api操作的对象都按照资源组,版本的形势做了组织。要查看所有⽀持的资源组和版本信息可以执⾏以下操作:
1 2 3 4 5 6 7~ $ kc get apirvices
NAME                                  SERVICE  AVAILABLE  AGE v1.                                    Local    True        3d11h
v1.apps                                Local    True        3d11h
v1beta1.apps                          Local    True        3d11h
v1beta2.apps                          Local    True        3d11h ...
下⾯会涉及到两个概念:资源组和资源。
资源组
这⾥,我们就使⽤ appsrest.RESTStorageProvider{} 这个最成熟、⼤家最熟悉的资源组(apps)来分析。
⾸先看下图⽬录结构,位于k8s项⽬pkg/registry/⽬录下的这些⼦⽬录都是k8s⽀持的资源组类型。这⾥的apps就是其中之⼀,apps下⾯⼜包含了常见的deployment等workloads。
转存失败
每⼀个资源组⽬录下都包含了⼀个rest⽬录,⾥⾯放的不是⼦资源,⽽是该资源组的RESTStorageProvider接⼝实现。该接⼝
的NewRESTStorage⽅法将资源组下的所有资源的storage都以版本信息作key填充到apiGroupInfo.VersionedResourcesStorageMap字典中。前⾯提到的m.InstallAPIs就是遍历字典,将所有资源组下的资源逐⼀安装到master router中。
顶层storage
到此,我们已经清楚,每添加⼀个资源组,在api-rver⾥⾯都需要把它加⼊到apiGroupInfo.VersionedResourcesStorageMap中,这样才会被安装到router⾥⾯。顶层的storage就是⼲这个事情的。
来看rest⽬录中⾥⾯资源组的版本和⼦资源是如何组织的代码。下⾯可以看到,对于apps这个资源组,针对v1beta1这个版本,添加了deployments这个资源,⽽这个组织好的结构就是⼀个storage。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21// 该函数将各个版本的storage填充到字典中
func (p RESTStorageProvider) NewRESTStorage(apiResourceConfigSource rverstorage.APIResourceConfigSource, restOptionsGetter generic.RESTOptionsGetter) (genericapirver.APIGroupInfo, bool) {
...
if apiResourceConfigSource.VersionEnabled(appsapiv1beta1.SchemeGroupVersion) {
apiGroupInfo.VersionedResourcesStorageMap[appsapiv1beta1.SchemeGroupVersion.Version] =
p.v1beta1Storage(apiResourceConfigSource, restOptionsGetter)
}
...
return apiGroupInfo, true
}
// 该函数在准备单个版本所有的⼦资源
func (p RESTStorageProvider) v1beta1Storage(apiResourceConfigSource rverstorage.APIResourceConfigSource, restOptionsGetter generic.RESTOptionsGetter) map[string]rest.Storage {
storage := map[string]rest.Storage{}
//这⾥要再看NewStorage的代码,注意它的参数,这在后⾯会提到
deploymentStorage := deploymentstore.NewStorage(restOptionsGetter)孔雀画法
storage["deployments"] = deploymentStorage.Deployment
...
return storage
}
接下来,我们将进⼊到deployment资源相关的⼦⽬录分析。
资源
通过⽬录结构图可以知道,每⼀个资源下都包含了storage和strategy⽬录。
转存失败
storage
其中storage中定义了NewREST,还通过REST对外统⼀提供操作资源的⼀些操作接⼝(如New/Get/Update等);这⾥将NewStorage 和DeploymentStorage都⼀并附上。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18type DeploymentStorage struct {
Deployment *REST        // 这些类型都是包含了 *genericregistry.Store
Status    *StatusREST  // 这些类型都是包含了 *genericregistry.Store
Scale      *ScaleREST    // 这些类型都是包含了 *genericregistry.Store
Rollback  *RollbackREST // 这些类型都是包含了 *genericregistry.Store
}
癌细胞检查func NewStorage(optsGetter generic.RESTOptionsGetter) DeploymentStorage {
// 这⾥调⽤了 NewREST,参数还是前⾯ NewStorage 的参数⼀如既往的往下传
deploymentRest, deploymentStatusRest, deploymentRollbackRest := NewREST(optsGetter)
return DeploymentStorage{
Deployment: deploymentRest,
Status:    deploymentStatusRest,丁香五月丁香
Scale:      &ScaleREST{store: deploymentRest.Store},
Rollback:  deploymentRollbackRest,
}
}
在NewREST返回了三个REST,每⼀个REST⾥⾯都包含了 *genericregistry.Store, 该store类型重点实现下⾯三个⽅法:
1 2 3 4 5 6 7 8 9 10 11 12 13func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, *RollbackREST) { store := &genericregistry.Store{
NewFunc:                  func() runtime.Object { return &apps.Deployment{} },
NewListFunc:              func() runtime.Object { return &apps.DeploymentList{} },
DefaultQualifiedResource: apps.Resource("deployments"),
清蒸鲈鱼的做法CreateStrategy: deployment.Strategy,  // 重点
UpdateStrategy: deployment.Strategy,  // 重点
DeleteStrategy: deployment.Strategy,  // 重点
...
}
...
烤箱烤披萨}
strategy
接下来就将注意⼒转移到deployment.Stategy上来了。deploymentStrategy⾥⾯主要实现了对资源做增删改前后的各种校验和准备⼯作,这⾥就不再详细的讲述。
etcd/cache
前⾯讲NewREST的时候,提到了其参数,其实该参数的最终值是这样赋值得到的:
1genericConfig.RESTOptionsGetter = &genericoptions.SimpleRestOptionsFactory{Options: etcdOptions}
获取该值的时候,通过调⽤该factory的GetRESTOptions⽅法.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17func (f *SimpleRestOptionsFactory) GetRESTOptions(resource schema.GroupResource) (generic.RESTOptions, error) { ...
// 重要
if f.Options.EnableWatchCache {
sizes, err := ParWatchCacheSizes(f.Options.WatchCacheSizes)公鸡会下蛋吗
if err != nil {
return generic.RESTOptions{}, err
}
cacheSize, ok := sizes[resource]
if !ok {
cacheSize = f.Options.DefaultWatchCacheSize
}
// 重要
ret.Decorator = genericregistry.StorageWithCacher(cacheSize)
}
return ret, nil
}

本文发布于:2023-07-25 20:43:16,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/89/1096482.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:资源   代码   逻辑   服务   版本   理解   函数
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图