真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

kubernetes代碼閱讀apiserver的示例分析

這篇文章主要介紹了kubernetes代碼閱讀apiserver的示例分析,具有一定借鑒價(jià)值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

成都創(chuàng)新互聯(lián)公司主要從事做網(wǎng)站、網(wǎng)站建設(shè)、網(wǎng)頁(yè)設(shè)計(jì)、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)海城,10年網(wǎng)站建設(shè)經(jīng)驗(yàn),價(jià)格優(yōu)惠、服務(wù)專業(yè),歡迎來電咨詢建站服務(wù):028-86922220

apiserver是整個(gè)kubernetes的核心模塊,做的事情多,代碼量也較大。市面上已經(jīng)有不少apiserver代碼解讀的文章了,但問題在于,由于k8s的代碼變化很快,想寫一篇長(zhǎng)久能用的未必能做到。所以,我參照了《Kubernetes權(quán)威指南》和浙大SEL實(shí)驗(yàn)室的一些文章,先把我看到的東西記下來,待后觀是否有用。

kubernetes源代碼版本1.2.0

代碼閱讀方法

先簡(jiǎn)單講講整個(gè)代碼的目錄結(jié)構(gòu)

目錄說明
api輸出接口文檔用
build構(gòu)建腳本
cluster適配不同I層的云,例如亞馬遜AWS,微軟Azure,谷歌GCE的集群?jiǎn)?dòng)腳本
cmd所有的二進(jìn)制可執(zhí)行文件入口代碼,例如apiserver/scheduler/kubelet
contrib項(xiàng)目貢獻(xiàn)者
docs文檔,包括了用戶文檔、管理員文檔、設(shè)計(jì)、新功能提議
example使用案例
Godeps項(xiàng)目中依賴使用的Go第三方包,例如docker客戶端SDK,rest等
hack工具箱,各種編譯、構(gòu)建、測(cè)試、校驗(yàn)的腳本都在這里面
hooksgit提交前后觸發(fā)的腳本
pkg項(xiàng)目代碼主目錄,cmd的只是個(gè)入口,這里是所有的具體實(shí)現(xiàn)
plugin插件,k8s認(rèn)為調(diào)度器是插件的一部分,所以調(diào)度器的代碼在這里
release應(yīng)該是Google發(fā)版本用的?
test測(cè)試相關(guān)的工具
third_party一些第三方工具,應(yīng)該不是強(qiáng)依賴的?
wwwUI,不過已經(jīng)被移動(dòng)到新項(xiàng)目了

可以看到,關(guān)鍵實(shí)現(xiàn)代碼都放在pkg這個(gè)目錄下。對(duì)于apiserver這種跨度很廣的組件而言,唯一有效的閱讀方式估計(jì)就是

  1. 遍歷pkg下所有的目錄,概覽大概知道這個(gè)目錄是干啥的

  2. 從cmd這個(gè)入口來看apiserver的代碼,然后一點(diǎn)點(diǎn)由淺入深,看apiserver的大致實(shí)現(xiàn)

  3. 分特性,看具體某個(gè)大的特性是怎么實(shí)現(xiàn)的,例如安全,例如和etcd存儲(chǔ)對(duì)接

  4. 在上面這幾步的過程中可以看看別人的代碼閱讀文檔,能有效的節(jié)省時(shí)間

0. apiserver主要實(shí)現(xiàn)了什么?

kubernetes代碼閱讀apiserver的示例分析

apiserver是k8s系統(tǒng)中所有對(duì)象的增刪查改盯的http/restful式服務(wù)端,其中盯是指watch操作。數(shù)據(jù)最終存儲(chǔ)在分布式一致的etcd存儲(chǔ)內(nèi),apiserver本身是無狀態(tài)的,提供了這些數(shù)據(jù)訪問的認(rèn)證鑒權(quán)、緩存、api版本適配轉(zhuǎn)換等一系列的功能。

  • restful服務(wù)入門

對(duì)于http服務(wù)和使用go語言實(shí)現(xiàn)方式,可以看go-restful的文檔和例子,對(duì)這個(gè)有基本的了解,這個(gè)文檔對(duì)入門者和一知半解者極為有效!

1. 對(duì)象的數(shù)據(jù)結(jié)構(gòu)

kubernetes代碼閱讀apiserver的示例分析

古人有言,程序就是算法+數(shù)據(jù)結(jié)構(gòu),搞懂了數(shù)據(jù)結(jié)構(gòu),整個(gè)程序的處理過程就明白了一半。對(duì)于apiserver的任何一個(gè)api請(qǐng)求來說,上圖說明了所有的數(shù)據(jù)結(jié)構(gòu)關(guān)系。

k8s放在etcd內(nèi)的存儲(chǔ)對(duì)象是api.Pod對(duì)象(無版本),從不同版本的請(qǐng)求路徑標(biāo)識(shí)來操作,例如api/v1,最后獲取到的是不同版本,例如v1.Pod的json文本。這里就經(jīng)歷了幾個(gè)過程,包括

  1. http client訪問/api/v1/pod/xyz,想要獲取這個(gè)Pod的數(shù)據(jù)

  2. 從etcd獲取到api.Pod對(duì)象

  3. api.Pod對(duì)象轉(zhuǎn)換為v1.Pod對(duì)象

  4. v1.Pod對(duì)象序列化為json或yaml文本

  5. 文本通過http的response體,返回給http client

其中用于處理業(yè)務(wù)數(shù)據(jù)的關(guān)鍵數(shù)據(jù)結(jié)構(gòu)是APIGroupVersion,里面的幾個(gè)成員變量的作用是:

成員作用
GroupVersion包含 api/v1這樣的string,用于標(biāo)識(shí)這個(gè)實(shí)例
Serializer對(duì)象序列化和反序列化器
Converter這是一個(gè)強(qiáng)大的數(shù)據(jù)結(jié)構(gòu),這里放的是個(gè)接口,本體在/pkg/conversion/conversion.go,幾乎可以轉(zhuǎn)換任意一種對(duì)象到另一種,只要你事先注入了相應(yīng)的轉(zhuǎn)換函數(shù)
Storage這個(gè)map的key,用于對(duì)象的url,value是一個(gè)rest.Storage結(jié)構(gòu),用于對(duì)接etcd存儲(chǔ),在初始化注冊(cè)時(shí),會(huì)把這個(gè)map化開,化為真正的rest服務(wù)到存儲(chǔ)的一條龍服務(wù)

2. 入口和啟動(dòng)

文件主要數(shù)據(jù)結(jié)構(gòu)/函數(shù)用途
kubernetes/cmd/kube-apiserver/apiserver.go
入口
kubernetes/cmd/kube-apiserver/app/options/options.gostructAPIServer啟動(dòng)選項(xiàng)
kubernetes/cmd/kube-apiserver/apiserver.gofuncRun初始化一些客戶端、啟動(dòng)master對(duì)象
kubernetes/pkg/genericapiserver/genericapiserver.gofuncRun啟動(dòng)安全和非安全的http服務(wù)

3. API分組、多版本的初始化注冊(cè)(Rest)

kubernetes代碼閱讀apiserver的示例分析

k8s采用ApiGroup來管理所有的api分組和版本升級(jí),目前有的API分組包括

  1. 核心組,REST路徑在 /api/v1 ,但這個(gè)路徑不是固定的,v1是當(dāng)前的版本。與之相對(duì)應(yīng)的代碼里面的apiVersion 字段的值是 v1。

  2. 擴(kuò)展組,REST路徑在 /apis/extensions/$VERSION,相對(duì)應(yīng)的代碼里面的 apiVersion: extensions/$VERSION (例如當(dāng)前的apiVersion: extensions/v1beta1)。這里提供的API對(duì)象今后有可能會(huì)被移動(dòng)到別的組內(nèi)。

  3. "componentconfig"和 "metrics"這這些組。

在這個(gè)文檔里面講述了實(shí)現(xiàn)ApiGroup的幾個(gè)目標(biāo),包括api分組演化,對(duì)舊版API的向后兼容(Backwards compatibility),包括用戶可以自定義自己的api等。接下來我們看看他么是怎么初始化注冊(cè)的,這里都是縮減版代碼,去掉了其他部分。

kubernetes/pkg/master/master.go
  • api注冊(cè)入口

func New(c *Config) (*Master, error) {
	m.InstallAPIs(c)
}
  • 根據(jù)Config往APIGroupsInfo內(nèi)增加組信息,然后通過InstallAPIGroups進(jìn)行注冊(cè)

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這個(gè)關(guān)鍵數(shù)據(jù)結(jié)構(gòu),然后進(jìn)行注冊(cè)

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
}

實(shí)際注冊(cè)的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最后是怎么變成一個(gè)具體的API來提供服務(wù)的呢?例如這么一個(gè)URL:

GET /api/v1/namespaces/{namespace}/pods/{name}
  • restful服務(wù)的實(shí)現(xiàn)

k8s使用的一個(gè)第三方庫(kù)github.com/emicklei/go-restful,里面提供了一組核心的對(duì)象,看例子

數(shù)據(jù)結(jié)構(gòu)功能在k8s內(nèi)的位置
restful.Container代表一個(gè)http rest服務(wù)對(duì)象,包括一組restful.WebServicegenericapiserver.go - GenericAPIServer.HandlerContainer
restful.WebService由多個(gè)restful.Route組成,處理這些路徑下所有的特殊的MIME類型等api_installer.go - NewWebService()
restful.Route路徑——處理函數(shù)映射mapapi_installer.go - registerResourceHandlers()
  • 實(shí)際注冊(cè)過程

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注冊(cè)過程是在這個(gè)函數(shù)中完成的,把一個(gè)rest.Storage對(duì)象轉(zhuǎn)換為實(shí)際的getter, lister等處理函數(shù),并和實(shí)際的url關(guān)聯(lián)起來。

4.etcd存儲(chǔ)的操作(ORM)

上面已經(jīng)基本厘清了從http請(qǐng)求 -> restful.Route -> rest.Storage這條線路,那rest.Storage僅僅是一個(gè)接口,有何德何能,可以真正的操作etcd呢?

kubernetes代碼閱讀apiserver的示例分析

這段也是牽涉到多個(gè)文件,但還比較清晰,首先,所有的對(duì)象都有增刪改查這些操作,如果為Pod單獨(dú)搞一套,Controller單獨(dú)搞一套,那代碼會(huì)非常重復(fù),不可復(fù)用,所以存儲(chǔ)的關(guān)鍵目錄是在這里:

kubernetes/pkg/registry/generic/etcd/etcd.go

這個(gè)文件定義了所有的對(duì)etcd對(duì)象的操作,get,list,create等,但具體的對(duì)象是啥,這個(gè)文件不關(guān)心;etcd客戶端地址,這個(gè)文件也不關(guān)心。這些信息都是在具體的PodStorage對(duì)象創(chuàng)建的時(shí)候注入的。以Pod為例子,文件在:

kubernetes/pkg/registry/pod/etcd/etcd.go

這里的NewStorage方法,把上述的信息注入了etcd里面去,生成了PodStorage這個(gè)對(duì)象。

// REST implements a RESTStorage for pods against etcd
type REST struct {
	*etcdgeneric.Etcd
	proxyTransport http.RoundTripper
}

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

kubernetes/pkg/apiserver/api_installer.go

最后在這里把PodStorage轉(zhuǎn)換成了Getter對(duì)象,并最終注冊(cè)到ApiGroup里面去。

感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“kubernetes代碼閱讀apiserver的示例分析”這篇文章對(duì)大家有幫助,同時(shí)也希望大家多多支持創(chuàng)新互聯(lián),關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,更多相關(guān)知識(shí)等著你來學(xué)習(xí)!


分享題目:kubernetes代碼閱讀apiserver的示例分析
URL標(biāo)題:http://weahome.cn/article/picish.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部