您好,登錄后才能下訂單哦!
這篇文章主要介紹了kubernetes代碼閱讀apiserver的示例分析,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
apiserver是整個kubernetes的核心模塊,做的事情多,代碼量也較大。市面上已經(jīng)有不少apiserver代碼解讀的文章了,但問題在于,由于k8s的代碼變化很快,想寫一篇長久能用的未必能做到。所以,我參照了《Kubernetes權(quán)威指南》和浙大SEL實驗室的一些文章,先把我看到的東西記下來,待后觀是否有用。
kubernetes源代碼版本1.2.0
先簡單講講整個代碼的目錄結(jié)構(gòu)
目錄 | 說明 |
---|---|
api | 輸出接口文檔用 |
build | 構(gòu)建腳本 |
cluster | 適配不同I層的云,例如亞馬遜AWS,微軟Azure,谷歌GCE的集群啟動腳本 |
cmd | 所有的二進制可執(zhí)行文件入口代碼,例如apiserver/scheduler/kubelet |
contrib | 項目貢獻者 |
docs | 文檔,包括了用戶文檔、管理員文檔、設(shè)計、新功能提議 |
example | 使用案例 |
Godeps | 項目中依賴使用的Go第三方包,例如docker客戶端SDK,rest等 |
hack | 工具箱,各種編譯、構(gòu)建、測試、校驗的腳本都在這里面 |
hooks | git提交前后觸發(fā)的腳本 |
pkg | 項目代碼主目錄,cmd的只是個入口,這里是所有的具體實現(xiàn) |
plugin | 插件,k8s認(rèn)為調(diào)度器是插件的一部分,所以調(diào)度器的代碼在這里 |
release | 應(yīng)該是Google發(fā)版本用的? |
test | 測試相關(guān)的工具 |
third_party | 一些第三方工具,應(yīng)該不是強依賴的? |
www | UI,不過已經(jīng)被移動到新項目了 |
可以看到,關(guān)鍵實現(xiàn)代碼都放在pkg這個目錄下。對于apiserver這種跨度很廣的組件而言,唯一有效的閱讀方式估計就是
遍歷pkg下所有的目錄,概覽大概知道這個目錄是干啥的
從cmd這個入口來看apiserver的代碼,然后一點點由淺入深,看apiserver的大致實現(xiàn)
分特性,看具體某個大的特性是怎么實現(xiàn)的,例如安全,例如和etcd存儲對接
在上面這幾步的過程中可以看看別人的代碼閱讀文檔,能有效的節(jié)省時間
apiserver是k8s系統(tǒng)中所有對象的增刪查改盯的http/restful式服務(wù)端,其中盯是指watch操作。數(shù)據(jù)最終存儲在分布式一致的etcd存儲內(nèi),apiserver本身是無狀態(tài)的,提供了這些數(shù)據(jù)訪問的認(rèn)證鑒權(quán)、緩存、api版本適配轉(zhuǎn)換等一系列的功能。
restful服務(wù)入門
對于http服務(wù)和使用go語言實現(xiàn)方式,可以看go-restful的文檔和例子,對這個有基本的了解,這個文檔對入門者和一知半解者極為有效!
古人有言,程序就是算法+數(shù)據(jù)結(jié)構(gòu),搞懂了數(shù)據(jù)結(jié)構(gòu),整個程序的處理過程就明白了一半。對于apiserver的任何一個api請求來說,上圖說明了所有的數(shù)據(jù)結(jié)構(gòu)關(guān)系。
k8s放在etcd內(nèi)的存儲對象是api.Pod對象(無版本),從不同版本的請求路徑標(biāo)識來操作,例如api/v1
,最后獲取到的是不同版本,例如v1.Pod
的json文本。這里就經(jīng)歷了幾個過程,包括
http client訪問/api/v1/pod/xyz,想要獲取這個Pod的數(shù)據(jù)
從etcd獲取到api.Pod對象
api.Pod對象轉(zhuǎn)換為v1.Pod對象
v1.Pod對象序列化為json或yaml文本
文本通過http的response體,返回給http client
其中用于處理業(yè)務(wù)數(shù)據(jù)的關(guān)鍵數(shù)據(jù)結(jié)構(gòu)是APIGroupVersion,里面的幾個成員變量的作用是:
成員 | 作用 |
---|---|
GroupVersion | 包含 api/v1 這樣的string,用于標(biāo)識這個實例 |
Serializer | 對象序列化和反序列化器 |
Converter | 這是一個強大的數(shù)據(jù)結(jié)構(gòu),這里放的是個接口,本體在/pkg/conversion/conversion.go ,幾乎可以轉(zhuǎn)換任意一種對象到另一種,只要你事先注入了相應(yīng)的轉(zhuǎn)換函數(shù) |
Storage | 這個map的key,用于對象的url,value是一個rest.Storage結(jié)構(gòu),用于對接etcd存儲,在初始化注冊時,會把這個map化開,化為真正的rest服務(wù)到存儲的一條龍服務(wù) |
文件 | 主要數(shù)據(jù)結(jié)構(gòu)/函數(shù) | 用途 |
---|---|---|
kubernetes/cmd/kube-apiserver/apiserver.go | 入口 | |
kubernetes/cmd/kube-apiserver/app/options/options.go | struct APIServer | 啟動選項 |
kubernetes/cmd/kube-apiserver/apiserver.go | func Run | 初始化一些客戶端、啟動master對象 |
kubernetes/pkg/genericapiserver/genericapiserver.go | func Run | 啟動安全和非安全的http服務(wù) |
k8s采用ApiGroup來管理所有的api分組和版本升級,目前有的API分組包括
核心組,REST路徑在 /api/v1
,但這個路徑不是固定的,v1是當(dāng)前的版本。與之相對應(yīng)的代碼里面的apiVersion
字段的值是 v1
。
擴展組,REST路徑在 /apis/extensions/$VERSION
,相對應(yīng)的代碼里面的 apiVersion: extensions/$VERSION
(例如當(dāng)前的apiVersion: extensions/v1beta1
)。這里提供的API對象今后有可能會被移動到別的組內(nèi)。
"componentconfig"和 "metrics"這這些組。
在這個文檔里面講述了實現(xiàn)ApiGroup的幾個目標(biāo),包括api分組演化,對舊版API的向后兼容(Backwards compatibility),包括用戶可以自定義自己的api等。接下來我們看看他么是怎么初始化注冊的,這里都是縮減版代碼,去掉了其他部分。
kubernetes/pkg/master/master.go
api注冊入口
func New(c *Config) (*Master, error) { m.InstallAPIs(c) }
根據(jù)Config往APIGroupsInfo
內(nèi)增加組信息,然后通過InstallAPIGroups
進行注冊
func (m *Master) InstallAPIs(c *Config) { if err := m.InstallAPIGroups(apiGroupsInfo); err != nil { glog.Fatalf("Error in registering group versions: %v", err) } }
轉(zhuǎn)換為APIGroupVersion
這個關(guān)鍵數(shù)據(jù)結(jié)構(gòu),然后進行注冊
func (s *GenericAPIServer) installAPIGroup(apiGroupInfo *APIGroupInfo) error { apiGroupVersion, err := s.getAPIGroupVersion(apiGroupInfo, groupVersion, apiPrefix) if err := apiGroupVersion.InstallREST(s.HandlerContainer); err != nil { return fmt.Errorf("Unable to setup API %v: %v", apiGroupInfo, err) } }
關(guān)鍵數(shù)據(jù)結(jié)構(gòu)
kubernetes/pkg/apiserver/apiserver.go
type APIGroupVersion struct { Storage map[string]rest.Storage Root string // GroupVersion is the external group version GroupVersion unversioned.GroupVersion }
實際注冊的Storage的map如下:
kubernetes/pkg/master/master.go
m.v1ResourcesStorage = 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.Binding,
那么,這里的map[string]rest.Storage
最后是怎么變成一個具體的API來提供服務(wù)的呢?例如這么一個URL:
GET /api/v1/namespaces/{namespace}/pods/{name}
restful服務(wù)的實現(xiàn)
k8s使用的一個第三方庫github.com/emicklei/go-restful
,里面提供了一組核心的對象,看例子
數(shù)據(jù)結(jié)構(gòu) | 功能 | 在k8s內(nèi)的位置 |
---|---|---|
restful.Container | 代表一個http rest服務(wù)對象,包括一組restful.WebService | genericapiserver.go - GenericAPIServer.HandlerContainer |
restful.WebService | 由多個restful.Route組成,處理這些路徑下所有的特殊的MIME類型等 | api_installer.go - NewWebService() |
restful.Route | 路徑——處理函數(shù)映射map | api_installer.go - registerResourceHandlers() |
實際注冊過程
kubernetes/pkg/apiserver/api_installer.go
func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storage, ws *restful.WebService, proxyHandler http.Handler) (*unversioned.APIResource, error) { }
最終的API注冊過程是在這個函數(shù)中完成的,把一個rest.Storage對象轉(zhuǎn)換為實際的getter, lister等處理函數(shù),并和實際的url關(guān)聯(lián)起來。
上面已經(jīng)基本厘清了從http請求 -> restful.Route -> rest.Storage這條線路,那rest.Storage僅僅是一個接口,有何德何能,可以真正的操作etcd呢?
這段也是牽涉到多個文件,但還比較清晰,首先,所有的對象都有增刪改查這些操作,如果為Pod單獨搞一套,Controller單獨搞一套,那代碼會非常重復(fù),不可復(fù)用,所以存儲的關(guān)鍵目錄是在這里:
kubernetes/pkg/registry/generic/etcd/etcd.go
這個文件定義了所有的對etcd對象的操作,get,list,create等,但具體的對象是啥,這個文件不關(guān)心;etcd客戶端地址,這個文件也不關(guān)心。這些信息都是在具體的PodStorage對象創(chuàng)建的時候注入的。以Pod為例子,文件在:
kubernetes/pkg/registry/pod/etcd/etcd.go
這里的NewStorage
方法,把上述的信息注入了etcd里面去,生成了PodStorage這個對象。
// REST implements a RESTStorage for pods against etcd type REST struct { *etcdgeneric.Etcd proxyTransport http.RoundTripper }
由于PodStorage.Pod是一個REST類型,而REST類型采用了Go語言的struct匿名內(nèi)部成員,天然就擁有Get, List等方法。
kubernetes/pkg/apiserver/api_installer.go
最后在這里把PodStorage轉(zhuǎn)換成了Getter對象,并最終注冊到ApiGroup
里面去。
感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“kubernetes代碼閱讀apiserver的示例分析”這篇文章對大家有幫助,同時也希望大家多多支持億速云,關(guān)注億速云行業(yè)資訊頻道,更多相關(guān)知識等著你來學(xué)習(xí)!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。