天天看點

kubernetes之kube-ApiServer代碼分析

  kube-ApiServer相當于是k8叢集的一個入口,不論通過kubectl還是使用remote api 直接控制,都要經過apiserver。apiserver說白了就是一個server負責監聽指定的端口(http/https協定),之後處理不同的請求,隻不過加上的很多控制;apiserver是k8s系統中所有對象的增删查改盯的http/restful式服務端,其中盯是指watch操作【watch是apiserver中的重要操作之一】。資料最終存儲在分布式一緻的etcd存儲内,apiserver本身是無狀态的,提供了這些資料通路的認證鑒權、緩存、api版本适配轉換等一系列的功能。

kubernetes之kube-ApiServer代碼分析

  k8s存放在etcd内的存儲對象是api.Pod對象(無版本),從不同版本的請求路徑标示來操作,例如api/v1,最後擷取到的是不同版本,例如v1.Pod的json文本。這裡就經曆了幾個過程,包括:

    1、http client通路/api/v1/pod/xyz, 想要擷取到這個Pod的資料

    2、從etcd擷取到api.Pod對象

    3、api.Pod對象轉換為v1.Pod對象

    4、v1.Pod對象序列化為json或yaml文本

    5、文本通過http的response體,傳回給http client

  其中用于處理業務資料的關鍵資料結構是APIGroupVersion:

  

kubernetes之kube-ApiServer代碼分析

  k8s采用ApiGroup來管理所有的api分組和版本更新,目前的API分組包括:

    1、核心組,REST路徑在/api/v1,但這個路徑不是固定的,v1是目前的版本。與之相對應的代碼裡面的apiVersion字段的值為v1.

    2、擴充組,REST路徑在/apis/extensions/$version, 相應的代碼裡面的apiversion:extensions/$VERSION(eg:apiVersion:extensions/v1beta1),這裡的API對象可能會被重新分組;

    3、"componentconfig" 和 "metrics"這些組

api注冊入口:

  2.根據Config往<code>APIGroupsInfo</code>内增加組資訊,然後通過<code>InstallAPIGroups</code>進行注冊

  3.轉換為<code>APIGroupVersion</code>這個關鍵資料結構,然後進行注冊

  4.APIGroupVersion 關鍵資料結構

  5.實際注冊的Storage的map如下:

  那麼,這裡的<code>map[string]rest.Storage</code>最後是怎麼變成一個具體的API來提供服務的呢?例如這麼一個URL:

資料結構

功能

在k8s内的位置

restful.Container

代表一個http rest服務對象,包括一組restful.WebService

genericapiserver.go - GenericAPIServer.HandlerContainer

restful.WebService

由多個restful.Route組成,處理這些路徑下所有的特殊的MIME類型等

api_installer.go - NewWebService()

restful.Route

路徑——處理函數映射map

api_installer.go - registerResourceHandlers

實際注冊過程

最終的API注冊過程是在這個函數中完成的,把一個rest.Storage對象轉換為實際的getter, lister等處理函數,并和實際的url關聯起來。

  上面已經基本厘清了從http請求 -&gt; restful.Route -&gt; rest.Storage這條線路,那rest.Storage僅僅是一個接口,有何德何能,可以真正的操作etcd呢?

kubernetes之kube-ApiServer代碼分析

  這段也是牽涉到多個檔案,但還比較清晰,首先,所有的對象都有增删改查這些操作,如果為Pod單獨搞一套,Controller單獨搞一套,那代碼會非常重複,不可複用,是以存儲的關鍵目錄是在這裡:

  這個檔案定義了所有的對etcd對象的操作,get,list,create等,但具體的對象是啥,這個檔案不關心;etcd用戶端位址,這個檔案也不關心。這些資訊都是在具體的PodStorage對象建立的時候注入的。以Pod為例子,檔案在:

  這裡的<code>NewStorage</code>方法,把上述的資訊注入了etcd裡面去,生成了PodStorage這個對象。

  由于PodStorage.Pod是一個REST類型,而REST類型采用了Go語言的struct匿名内部成員,天然就擁有Get, List等方法。

  最後在這裡把PodStorage轉換成了Getter對象,并最終注冊到<code>ApiGroup</code>裡面去。