断断续续研究Kubernetes代码已经大半年时间了,一直在看APIServer相关的代码,因为API是一个系统的入口,是所有功能对外的抽象体现,同时也是其他组件都依赖的一个组件,处于非常核心的地位,因此它被社区进行了精心的设计,了解了它,就可以顺藤摸瓜去了解其他核心的功能。不过,经过这么长时间的摸索,发现Kubernetes的代码是真心复杂,明显感觉要比看OpenStack的代码费劲多了,感觉他的复杂性主要来自于以下几个方面:

1.Kubernetes经过这么多年的发展,功能不断在扩展,不断地在复杂化,为了应对这种复杂化,代码也不断被重构和抽象,逐渐往模块化,插件化,自动化发展,典型的像apimachinery这个库,就是api层面最高层的抽象,如果不结合它的使用,单看这个库的代码,几乎是看不懂的,而且往往Kubernetes里面一个结构体的内容非常多,结构体里又嵌套多层结构体,围绕这个结构体又有一堆的方法,信息量巨大,此外代码中还有大量的magic code,不了解背景的话,很难理解为什么写这段代码。

2.Kubernetes是用Golang写的,Golang是没有类似于C++, Java, Python那种类的概念的,也没有继承,多态,这种面向对象的编程方式,它的抽象方式,只有一种,就是Interface,以及实现了这个Interface的结构体,所以面对这种复杂的项目,代码组织是非常凌乱的。

3.毕竟Golang没有Python/Java这种编程语言老牌,Kubernetes项目中,用到的第三方库比较少,很多都是自己写的库,典型的像APIServer中,处理REST请求的库,虽然使用了第三方go-restful,但还是自己开发了一个NonGoRestfulMux,因为go-restful不能满足它的一些功能要求,与之类似的,还有API对象的序列化,以及对数据库的操作,都是自己写的库,这在Python里面都有成熟的强大的库,可以屏蔽掉这些细节,这些都显著增加了它的复杂度。

面对它四五百万行的代码量,真心感觉罗马不是一天建成的。单看APIServer,里面有各种各样的机制,比如authentication,authorization,admission,storage,api group, extension,metric, log, audit, client, informer等等,本系列文章,打算介绍下Kubernetes APIServer一些主要机制的实现方式,包括如下几个方面:

1.APIServer是怎么run起来的

2.APIServer是怎么跟数据库打交道的

3.APIServer中定义的API的Group和Version是怎么组织的

4.APIServer的扩展机制是怎么实现的

5.APIServer的序列化机制

本篇文章,主要介绍下APIServer的大致脉络,即上面提到的第一个问题,APIServer是怎么run起来的。本质上,APIServer是使用golang中net/http库中的Server构建起来的,

所以在这之前,我们先来看看golang里面的http Server是怎么使用的。下面是一个非常简单的例子:

package mainimport ("fmt""log""net/http""time"
)type MyHandler struct {foo string
}func (h *MyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {fmt.Println(h.foo)
}func main() {handler := &MyHandler {foo: "hello world",}s := &http.Server {Addr:      ":8080",Handler:   handler,ReadTimeout:  10 * time.Second,WriteTimeout:  10 * time.Second,MaxHeaderBytes: 1 << 20,}log.Fatal(s.ListenAndServe())
}

Handler是其中一个非常重要的概念,它是最终处理HTTP请求的实体,在golang中,定义了Handler的接口:

type Handler interface {ServeHTTP(ResponseWriter, *Request);
}

凡是实现了ServeHTTP()方法的结构体,那么它就是一个Handler了,所以上面定义的MyHandler结构体因为实现了ServeHTTP()方法,所以它是一个Handler,可以用来处理HTTP请求。然后在main()方法中,实例化一个MyHandler的对象,将其通过Handler参数传给了http.Server,然后ListenAndServe(),将Server运行起来,这样就完成了一个简单的HTTP Server了。这其实就是Kubernetes APIServer的骨架了,只不过它有非常复杂的Handler。

宏观上来看,APIServer就是一个实现了REST API的WebServer,最终是使用golang的net/http库中的Server运行起来的,数据库使用etcd,而且目前是唯一支持的后端存储,所以简单理解,APIServer所做的事情,就是对数据库的增删查改。但是,作为一个功能完备的Web Server,不能只有对数据库的增删查改,还需要比如:对外暴露API,必须要有认证和授权,而且Kubernetes为了能够让管理员更进一步控制API,还实现了其独有的Admission机制,此外,通过group和version(组和版本)来组织其API对象,为了保持兼容性,多个版本的对象可以共存,还有其扩展机制,即著名的CRD和Aggregation,等等这些,让APIServer丰满和复杂起来。APIServer启动的过程,就是对这些机制setup的过程,其大致流程如下图所示:

k8s-apiserver-overview

1.init()是在main()函数启动之前,就进行的一些初始化操作,主要做的事情就是注册各种API对象类型到APIServer中,这个后续会讲到。

2.随后就是进行命令行参数的解析,以及设置默认值,还有校验了,APIServer使用cobra构建它的CLI,各种参数通过POSIX风格的参数传给APIServer,比如下面的参数示例:

"--bind-address=0.0.0.0",

"--secure-port=6444",

"--tls-cert-file=/var/run/kubernetes/serving-kube-apiserver.crt",

"--tls-private-key-file=/var/run/kubernetes/serving-kube-apiserver.key",

这些显示指定的参数,以及没有指定,而使用默认值的参数,最终都被解析,然后集成到一个叫做ServerRunOptions的结构体中,而这个结构体又包含了很多xxxOptions的结构体,比如EtcdOptions,SecureServingOptions等,供后面使用。

3.随后就到了CreateServerChain阶段,这个是整个APIServer启动过程中,最重要的也是最复杂的阶段了,整个APIServer的核心功能就包含在这个里面,这里面最主要的其实干了两件事:一个是构建起各个API对象的Handler处理函数,即针对REST的每一个资源的增删改查方法的注册,比如/pod,对应的会有CREATE/DELETE/GET/LIST/UPDATE/WATCH等Handler去处理,这些处理方法其实主要是对数据库的操作;第二个就是通过Chain的方式,或者叫Delegation的方式,实现了APIServer的扩展机制,如上图所示,KubeAPIServer是主APIServer,这里面包含了Kubernetes的所有内置的核心API对象,APIExtensions其实就是我们常说的CRD扩展,这里面包含了所有自定义的CRD,而Aggretgator则是另外一种高级扩展机制,可以扩展外部的APIServer,三者通过 Aggregator –> KubeAPIServer –> APIExtensions 这样的方式顺序串联起来,当API对象在Aggregator中找不到时,会去KubeAPIServer中找,再找不到则会去APIExtensions中找,这就是所谓的delegation,通过这样的方式,实现了APIServer的扩展功能。此外,还有认证,授权,Admission等都在这个阶段实现。

4.然后是PrepareRun阶段,这个阶段主要是注册一些健康检查的API,比如Healthz,Livez,Readyz等;

5.最后就到了Run阶段,经过前面的步骤,已经生成了让Server Run起来的所有东西,其中最重要的就是Handler了,然后将其通过NonBlocking的方式run起来,即将http.Server在一个goroutine中运行起来;随后启动PostStartHook,PostStartHook是在CreateServerChain阶段注册的hook函数,用来周期性执行一些任务,每一个Hook起在一个单独的goroutine中;这之后就是通过channel的方式将关闭API Server的方法阻塞住,当channel收到os.Interrup或者 syscall.SIGTERM signal时,就会将 APIServer 关闭。

以上,就是对 Kubernetes APIServer 机制的一个大概认识,了解下 APIServer 的本质,以及它启动的一个大致流程,后续会对其中一些步骤进行深入剖析。

Kubernetes APIServer机制概述相关推荐

  1. Kubernetes基础组件概述

    本文讲的是Kubernetes基础组件概述[编者的话]最近总有同学问Kubernetes中的各个组件的相关问题,其实这些概念内容在官方文档中都有,奈何我们有些同学可能英文不好,又或者懒得去看,又或者没 ...

  2. 【OS学习笔记】三十 保护模式九:段页式内存管理机制概述

    上几篇文章学习了任务切换相关知识,如下: [OS学习笔记]二十六 保护模式八:任务门-任务切换 [OS学习笔记]二十七 保护模式八:任务切换的方法之----jmp与call的区别以及任务的中断嵌套 今 ...

  3. Android 安全机制概述

    1 Android 安全机制概述 Android 是一个权限分离的系统 . 这是利用 Linux 已有的权限管理机制,通过为每一个 Application 分配不同的 uid 和 gid , 从而使得 ...

  4. SQL Server 内存中OLTP内部机制概述(二)

    ----------------------------我是分割线------------------------------- 本文翻译自微软白皮书<SQL Server In-Memory ...

  5. 基于FAST的TSN交换(1)TSN交换机制概述

    基于FAST的TSN交换(1)TSN交换机制概述     2012年,IEEE 802.1的Audio Video Bridging任务组正式被TSN任务组代替.TSN任务组主要工作是定义在交换式以太 ...

  6. Cocos2d-x事件分发机制概述

    Cocos2d-x事件分发机制概述   Cocos2d-x通过事件分发机制响应用户事件,已内置支持常见的事件如触摸事件,键盘事件等.同时提供了创建自定义事件的方法,满足我们在游戏的开发过程中,特殊的事 ...

  7. 【Java 19】反射 - 反射机制概述、获取Class实例、类的加载与ClassLoader的理解、创建运行时类的对象、获取运行时类的完整结构、调用运行时类的指定结构、动态代理

    反射机制概述.获取Class实例.类的加载与ClassLoader的理解.创建运行时类的对象.获取运行时类的完整结构.调用运行时类的指定结构.动态代理 反射 1 Java反射机制概述 1.1 Java ...

  8. 注意力(Attention)机制概述

    注意力(Attention)机制概述 1 前言 ​ 在视觉方面,注意力机制的核心思想是突出对象的某些重要特征.[从关注全部到关注重点] ​ 注意力机制的目的可以认为是在深度神经网络的结构设计中,对某些 ...

  9. kubernetes apiserver认证

    kubernetes认证 Kubernetes集群的操作可以通过apiserver来进行操作,kubectl命令最终也是调用的apiserver,如果想要获取对apiserver进行操作,需要先通过其 ...

最新文章

  1. Python 用while 实现循环 到特定条件退出循环(input 输入错误之后重新输入)
  2. 电脑机时,电脑死机时,为啥会忍不住扇它一巴掌?
  3. linux基于此语言的密码,一次有趣的Linux下.Net Core与C语言的合作开发体验:生成Linux标准的用户密码串...
  4. dreamweaver中的JSP的编程环境配置
  5. Java IO流之字符缓冲流
  6. java项目 配置文件_细数Java项目中用过的配置文件(properties篇)
  7. php mysql_query预处理,php+mysqli使用预处理技术进行数据库查询的方法
  8. [Grid Layout] Place grid items on a grid using grid-column and grid-row
  9. java手游 《剑心》_java
  10. 玩ts要注意什么_幼儿园装修要注意什么
  11. 第3章 系统设计和架构设计【扩胸运动,有容乃大】
  12. 从零基础入门Tensorflow2.0 ----二、4.2 wide deep 模型(子类API)
  13. 在DataList、Repeater的HeaderTemplate和FooterTemplate模板中寻找控件FindControl
  14. 天煌计算机组成原理控制软件,天煌THTJZ-2型计算机组成原理课程设计.doc
  15. 利用rufus重装ubuntu
  16. 外贸单证管理系统如何解决企业制单问题
  17. 【读书笔记】天生不聪明
  18. AEMDA: Inferring miRNA-disease associations based on deep autoencoder
  19. python数据类型的转化和获取
  20. 基于Python摄影图片分享系统设计与实现 开题报告

热门文章

  1. java中 int 比较_java中Integer与int的种种比较你知道多少?
  2. C++学习笔记:(五)继承 多态
  3. 03.德国博士练习_02_admin_cluster
  4. (~最新合集~)计算机网络谢希仁第七版 第五章课后答案
  5. @Cacheable原理
  6. linux该专接本还是工作_是该专接本还是直接工作?学历和经验哪个重要?
  7. php sdk微信,GitHub - swayer/wechat-php-sdk: 微信公众平台 PHP SDK
  8. 实验图文详解——apache的编译安装及httpd服务开机自启
  9. spring boot plugin_spring-boot-starter-parent 与 spring-boot-dependencies
  10. 基于spring cloud 的灰度发布实践_【收藏】基于spring cloud灰度发版方案