Kubernetes APIServer机制概述
斷斷續續研究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机制概述的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Nmap经常使用的场景用法
- 下一篇: 工具|渗透测试之5种工具分享(Shiro