k8s之apiserver

news2024/11/15 4:10:42

1、Kube-APIServer 启动

APIServer 启动采用 Cobra 命令行,解析相关 flags 参数,经过 Complete(填充默认值)->Validate(校验) 逻辑后,通过 Run 启动服务。

在 Run 函数中,按序分别初始化 APIServer 链(APIExtensionsServer、KubeAPIServer、AggregatorServer),分别服务于 CRD(用户自定义资源)、K8s API(内置资源)、API Service(扩展外部的APIServer) 对应的资源请求,因此在处理API对象时,当API对象在Aggregator中找不到时,会去KubeAPIServer中找,再找不到则会去APIExtensions中找,三者通过 Aggregator –> KubeAPIServer –> APIExtensions 这样的方式顺序串联起来,这就是所谓的Chain的方式,或者Delegation的方式,实现了APIServer的扩展机制。

之后,经过非阻塞(NonBlockingRun) 方式启动 SecureServingInfo.Serve,并配置 HTTP2(默认开启) 相关传输选项,最后启动 Serve 监听客户端请求。

111

2、kube-apiserver get api资源流程

https://mp.weixin.qq.com/s/KCb8mbRg40hB6d8okgrMGA 该文章以内置资源的 handler 注册过程为线索介绍了 APiServer 的启动过程和 handler 注册过程。对APIServer的访问会先经过 filter,再路由给具体的 handler。filter 在 DefaultBuildHandlerChain 中定义,主要对请求做超时处理,认证,鉴权等操作。handler 的注册则是初始化 APIGoupInfo 并设置其 VersionedResourcesStorageMap 后作为入参,调用 GenericAPIServer.InstallAPIGroups即可完成 handler 的注册。k8s.io/apiserver/pkg/endpoints/handlers包中的代码则是对用户请求做编解码,对象版本转换,协议处理等操作,最后在交给rest.Storage 具体实现的接口进行处理。

3、server 层

Server模块对外提供服务器能力。主要包括调用调用Endpoints中APIInstaller完成路由注册,同时为apiserver的扩展做好服务器层面的支撑(主要是APIService这种形式扩展)

// 注册所有 apiGroupVersion 的处理函数 到restful.Container 中
func (s *GenericAPIServer) installAPIResources(apiPrefix string, apiGroupInfo *APIGroupInfo, openAPIModels openapiproto.Models) error {
    for _, groupVersion := range apiGroupInfo.PrioritizedVersions {
        apiGroupVersion := s.getAPIGroupVersion(apiGroupInfo, groupVersion, apiPrefix)
        if err := apiGroupVersion.InstallREST(s.Handler.GoRestfulContainer); err != nil {
            ...
        }
    }
    return nil
}

除了路由注册到服务器的核心内容外,server模块还提供了如下内容:

  1. 路由层级的日志记录(在httplog模块)

  1. 健康检查的路由(healthz模块)

  1. 服务器级别的过滤器(filters模块),如,cors,请求数,压缩,超时等过滤器,

  1. server级别的路由(routes模块),如监控,swagger,openapi,监控等。

4、endpoint 层

位于 k8s.io/apiserver/pkg/endpoints 包下。根据Registry层返回的路径与存储逻辑的关联关系,完成服务器上路由的注册 <path,handler> ==> route ==> webservice。

// k8s.io/apiserver/pkg/endpoints/installer.go
typeAPIInstallerstruct {
    group             *APIGroupVersion
    prefix            string// Path prefix where API resources are to be registered.
    minRequestTimeouttime.Duration
}
// 一个Resource 下的 所有处理函数 都注册到 restful.WebService 中了
func (a*APIInstaller) registerResourceHandlers(pathstring, storagerest.Storage, ws*restful.WebService) (*metav1.APIResource, error) {
    // 遍历所有操作,完成路由注册
    for_, action :=rangeactions {
        ...
        switchaction.Verb {
            case"GET": // Get a resource.
                handler=restfulGetResource(getter, exporter, reqScope)
                ...
                route :=ws.GET(action.Path).To(handler).
                    Doc(doc).
                    Param(ws.QueryParameter("pretty", "If 'true', then the output is pretty printed.")).
                    Returns(http.StatusOK, "OK", producedObject).
                    Writes(producedObject)
                ...
                routes=append(routes, route)
            case...
        }
        ...
        for_, route :=rangeroutes {
            ...
            ws.Route(route)
        }
    }
}
funcrestfulGetResource(rrest.Getter, erest.Exporter, scopehandlers.RequestScope) restful.RouteFunction {
    returnfunc(req*restful.Request, res*restful.Response) {
        handlers.GetResource(r, e, &scope)(res.ResponseWriter, req.Request)
    }
}
func (a*APIInstaller) Install() ([]metav1.APIResource, *restful.WebService, []error) {
    ws :=a.newWebService()
    ...
    for_, path :=rangepaths {
        apiResource, err :=a.registerResourceHandlers(path, a.group.Storage[path], ws)
        apiResources=append(apiResources, *apiResource)
    }
    returnapiResources, ws, errors
}
typeAPIGroupVersionstruct {
    Storagemap[string]rest.Storage// 对应上文的restStorageMap 
    Rootstring
}
// 一个APIGroupVersion 下的所有Resource处理函数 都注册到 restful.Container 中了
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()
    ...
    container.Add(ws)
    returnutilerrors.NewAggregate(registrationErrors)
}

同时在Endpoints还负责路径级别的操作:比如:到指定类型的认证授权,路径的调用统计,路径上的操作审计等。这部分内容通常在endpoints模块下的fileters内实现,这就是一层在http.Handler外做了一层装饰器,便于对请求进行拦截处理。

5、registry 层

实现各种资源对象的存储逻辑

  1. kubernetes/pkg/registry负责k8s内置的资源对象存储逻辑实现

  1. k8s.io/apiextensions-apiserver/pkg/registry负责crd和cr资源对象存储逻辑实现

k8s.io/apiserver/pkg/registry
    /generic
        /regisry
            /store.go       // 对storage 层封装,定义 Store struct
k8s.io/kubernetes/pkg/registry/core
    /pod
        /storage
            /storage.go     // 定义了 PodStorage struct,使用了Store struct
    /service
    /node
    /rest
        /storage_core.go

registry这一层比较分散,k8s在不同的目录下按照k8s的api组的管理方式完成各自资源对象存储逻辑的编写,主要就是定义各自的结构体,然后和Store结构体进行一次组合。

typePodStoragestruct {
    Pod                 *REST
    Log                 *podrest.LogREST
    Exec                *podrest.ExecREST
    ...
}
typeRESTstruct {
    *genericregistry.Store
    proxyTransporthttp.RoundTripper
}
func (cLegacyRESTStorageProvider) NewLegacyRESTStorage(restOptionsGettergeneric.RESTOptionsGetter) (LegacyRESTStorage, genericapiserver.APIGroupInfo, error) {
    ...
    // 关联路径 与各资源对象的关系
    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,
    }
}

6、存储层

位于 k8s.io/apiserver/pkg/storage 下,封装了对etcd 的操作,还提供了一个cacher 以减少对etcd 的访问压力(kube-apiserver本身对etcd实现了list-watch机制,将所有对象的最新状态和最近的事件存放到cacher里,所有外部组件对资源的访问都经过cacher),在Storage这一层,并不能感知到k8s资源对象之类的内容,纯粹的存储逻辑。

typeCacherstruct {
  incomingchanwatchCacheEvent  // incoming 事件管道, 会被分发给所有的watchers
  storagestorage.Interface  //storage 的底层实现
  objectTypereflect.Type   // 对象类型
  watchCache*watchCache   // watchCache 滑动窗口,维护了当前kind的所有的资源,和一个基于滑动窗口的最近的事件数组 
  reflector  *cache.Reflector  // reflector list并watch etcd 并将事件和资源存到watchCache中 
  watchersBuffer []*cacheWatcher   // watchersBuffer 代表着所有client-go客户端跟apiserver的连接
  ....
}

7、kube-apiserver 启动代码梳理

step01 apiserver启动 cmd/kube-apiserver/apiserver.go:34

step02 通过cobra启动 cmd/kube-apiserver/app/server.go:129

step03 创建 apiservers 包括APIExtensionsServer、KubeAPIServer、AggregatorServer) cmd/kube-apiserver/app/server.go:164

  • step03-01 初始化创建 KubeAPIServer 所需要的配置(apiServer启动参数配置、注册指标、ca配置、初始化认证授权配置等 cmd/kube-apiserver/app/server.go:182

  • step03-02 创建 apiExtensionsServer 实例,服务于 CRD(用户自定义资源) cmd/kube-apiserver/app/server.go:197

  • step03-02-01 注册APIGroup vendor/k8s.io/apiextensions-apiserver/pkg/apiserver/apiserver.go:166

  • step03-02-02 step03-06 registerResourceHandlers vendor/k8s.io/apiserver/pkg/endpoints/installer.go:191

  • step03-02-03 为每个类型的请求添加对应的 handler vendor/k8s.io/apiserver/pkg/endpoints/installer.go:693

  • step03-03 创建 kubeAPIServer 实例, 用于K8s API(内置资源) cmd/kube-apiserver/app/server.go:203

  • step03-03-01 InstallLegacyAPI pkg/controlplane/instance.go:383

  • step03-03-02 installAPIResources 为每一个 API resource 调用 apiGroupVersion.InstallREST 添加路由 vendor/k8s.io/apiserver/pkg/server/genericapiserver.go:712

  • step03-03-03 InstallREST 将 restful.WebService 对象添加到 container 中 vendor/k8s.io/apiserver/pkg/endpoints/groupversion.go:109

  • step03-03-04 installer.Install 返回最终的 restful.WebService 对象

  • step03-03-05 registerResourceHandlers 通过go-restful框架实现路由和对应handler处理逻辑的绑定 vendor/k8s.io/apiserver/pkg/endpoints/installer.go:192

  • step03-03-06 为每个类型的请求添加对应的handler vendor/k8s.io/apiserver/pkg/endpoints/installer.go:693

  • step03-04 创建AggregatorServer,用于API Service(API 扩展资源) 对应的资源请求 cmd/kube-apiserver/app/server.go:214

step04 运行前准备(健康检查、存活检查和OpenAPI路由的注册) cmd/kube-apiserver/app/server.go:170

step05 启动安全的http server提供服务 cmd/kube-apiserver/app/server.go:176

  • step05-01 启动http服务 staging/src/k8s.io/apiserver/pkg/server/genericapiserver.go:459

  • step05-02 非阻塞式运行启动 SecureServingInfo.Serve,并配置 HTTP2(默认开启) 相关传输选项,最后启动 Serve 监听客户端请求。 staging/src/k8s.io/apiserver/pkg/server/genericapiserver.go:535

step06 接受get请求

  • step06-01 get请求访问入口层,处理get请求的hanler vendor/k8s.io/apiserver/pkg/endpoints/handlers/get.go:86

  • step06-02 对请求数据进行处理层 vendor/k8s.io/apiserver/pkg/registry/generic/registry/store.go:743

  • step06-03 apiserver的cache层 vendor/k8s.io/apiserver/pkg/storage/cacher/cacher.go:547

  • step06-04 直接访问etcd层 vendor/k8s.io/apiserver/pkg/storage/etcd3/store.go:125

参考文章:

资源API的注册 https://cloud.tencent.com/developer/article/2013498

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/341306.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Java开发笔记】分库分表

【Java开发笔记】分库分表 1 分库分表基本概述 为什么要分库分表&#xff1f; 【性能角度】分库分表就是为了解决由于数据量多大而导致数据库性能下降的问题&#xff1a; 原来独立的数据库拆分成若干数据库组成将原来的大表&#xff08;存储近千万数据&#xff09;拆分为若干…

利用git reflog 命令来查看历史提交记录,并使用提交记录恢复已经被删除掉的分支

一.问题描述 当我们在操作中手误删除了某个分支&#xff0c;那该分支中提交的内容也没有了&#xff0c;我们可以利用git reflog这个命令来查看历史提交的记录从而恢复被删除的分支和提交的内容 二.模拟问题 1.创建git仓库&#xff0c;并提交一个文件 [rootcentos7-temp /da…

oracle10g安装教程

oracle 10g 安装 环境 操作系统&#xff1a;win 7 64位 内存&#xff1a;8G Oracle 10压缩包&#xff1a;10203_vista_w2k8_x86_production_db.zip 客户端&#xff1a;Oracle_client_win32.zip pl/sql&#xff1a;plsqldev1005.exe 背景 Oracle是众多中大型企业必选的数…

17万字数字化医院信息化建设大数据平台建设方案WORD

【版权声明】本资料来源网络&#xff0c;知识分享&#xff0c;仅供个人学习&#xff0c;请勿商用。【侵删致歉】如有侵权请联系小编&#xff0c;将在收到信息后第一时间删除&#xff01;完整资料领取见文末&#xff0c;部分资料内容&#xff1a; 目录 第1章 医院信息化概述 1.…

MySQL-数据目录浅析

InnoDB 、 MyISAM 这样的存储引擎都是把表存储在磁盘上的&#xff0c;操作系统用文件系统来管理磁盘。 数据目录 MySQL服务器程序在启动时会到文件系统的某个目录下加载一些文件&#xff0c;之后在运行过程中产生的数据也都会存储到这个目录下的某些文件中&#xff0c;这个目…

JVM学习02:内存结构

JVM学习02&#xff1a;内存结构 1. 程序计数器 1.1、定义 Program Counter Register 程序计数器&#xff08;寄存器&#xff09; 作用&#xff1a;是记住下一条jvm指令的执行地址 特点&#xff1a; 是线程私有的不会存在内存溢出 1.2、作用 程序计数器物理上是由寄存器来实…

Spring中IOC框架结构是什么?都包含那些模块,各个模块具体是什么样的

继续整理记录这段时间来的收获&#xff0c;详细代码可在我的Gitee仓库Java设计模式克隆下载学习使用&#xff01; 7.自定义Spring框架 7.1 Spring框架使用回顾 7.1.1 数据访问层 定义UserDaoMapper接口及实现类 public interface UserMapper { public void add(); } pu…

k8s默认StorageClass,解决pvc一直处于“Pending”

文章目录报错详情排查思路查看 pvc 详细属性查看 nfs-provisioner pod日志解决方案报错详情 排查思路 查看 pvc 详细属性 [rootk8s-master01 /opt/zadig]# kubectl describe pvc pvc-sc Name: pvc-sc Namespace: default StorageClass: nfs-yinwu Status: …

代码随想录算法训练营第27天|● 93.复原IP地址 ● 78.子集 ● 90.子集II

93.复原IP地址 看完题后的思路 典型分割问题略lue略剪枝条件 sub&#xff1a; 1&#xff09; 不是一位首字母为0 2&#xff09;大于三位 3&#xff09;介于0-255之间 4) 当已分割得到3个时&#xff0c;第四个直接从startIndex到末尾就行 代码 ArrayList<String> slist…

剑指Offer 第28天 复杂链表的赋值

复杂链表的复制_牛客题霸_牛客网 描述 输入一个复杂链表&#xff08;每个节点中有节点值&#xff0c;以及两个指针&#xff0c;一个指向下一个节点&#xff0c;另一个特殊指针random指向一个随机节点&#xff09;&#xff0c;请对此链表进行深拷贝&#xff0c;并返回拷贝后的头…

(免费分享)基于 SpringBoot 的高校宿舍管理系统带论文

项目描述 系统代码质量高&#xff0c;功能强大&#xff0c;带论文。 系统的功能主要有&#xff1a; &#xff08;1&#xff09;基本信息管理 基本信息分为学生信息和宿舍信息两部分&#xff0c;其功能是负责维护这些信息&#xff0c;对 它们进行增删查改等操作。 &#x…

UART通讯简介

UART全称Universal AsynchronousReceiver/Transmitter&#xff0c;通用异步收发传输器。 一、工作原理 和其它串口一样&#xff0c;数据按照二进制从低位到高位一位一位的传输&#xff0c;能将要传输的数据在串行通信与并行通信之间加以转换&#xff0c;能够灵活地与外部设备进…

网络编程(未完待续)

网络编程 文章目录网络编程前置概念1- 字节序高低地址与高低字节高低地址&#xff1a;高低字节字节序大端小端例子代码判断当前机器是大端还是小端为何要有字节序字节序转换函数需要字节序转换的时机例子一例子二2- IP地址转换函数早期(不用管)举例现在与字节序转换函数相比:**…

Open Street Map—2023年水系数据

之前文章我们给大家分享了从OSM地图下载的道路数据&#xff08;可查看之前推送的文章&#xff09;&#xff0c; 这一篇我们给大家带来的是从OSM地图下载的水系数据&#xff01;我们下载了全国范围&#xff08;包括港澳台&#xff09;的水系数据&#xff0c;下载时间为2023年2月…

硬件篇-配置

写在最前 这已经可以成为垃圾佬配置了。。。 机箱->239元 机箱选用的itx迷你机箱&#xff0c;为了后期nas方便拓展选了4盘位&#xff0c;该机箱还是比较符合我的预期的&#xff0c;颇有种麻雀虽小五脏俱全的感觉&#xff0c;机箱可以安装matx主板和itx主板&#xff0c;还是…

聊聊MySQL中的事务,MVCC

事务我们知道&#xff0c;事务具有四大特性——ACIDA atomicity 指的是原子性C consistency 指的是一致性I isolation 指的是隔离性D durability 指的是持久性四大特性的实现原理原子性原子性在这指的是整个事务操作&#xff0c;要么同时成功要么同时失败。让它变成一个整体。同…

若依管理系统搭建运行环境--基于SpringBootVue前端分离版

若依框架搭建运行环境-如何下载一、技术支持&#xff1a;二、Redis安装及运行三 目录结构四、导入数据库五 修改配置文件1.application-druid.yml文件 &#xff08;路径&#xff1b;RuoYi-Vue-master\ruoyi-admin\src\main\resources\application-druid.yml&#xff09;2.appli…

越界访问数组

越界访问是指访问&#xff08;操作修改&#xff09;了不属于自己的空间 我们以如下代码为例&#xff1a;此代码在vs中进行 #include <stdio.h> int main() {int i 0;int arr[] {1,2,3,4,5,6,7,8,9,10};for(i0; i<12; i){arr[i] 0;printf("hello\n");}r…

阿里云平台与MQTTX软件通信

阿里云平台与MQTTX软件通信 上一篇文章介绍了如何创建阿里云物联网平台以及MQTT.fx软件通信配置&#xff1a;https://blog.csdn.net/weixin_46251230/article/details/128993864 但MQTT.fx软件需要许可证才能使用&#xff0c;所以使用另一款软件MQTTX来代替 MQTTX软件下载 官…

【C++】类与对象(二)

前言 在前一章时我们已经介绍了类与对象的基本知识&#xff0c;包括类的概念与定义&#xff0c;以及类的访问限定符&#xff0c;类的实例化&#xff0c;类的大小的计算&#xff0c;以及C语言必须传递的this指针&#xff08;C中不需要我们传递&#xff0c;编译器自动帮我们实现&…