久久精品人人爽,华人av在线,亚洲性视频网站,欧美专区一二三

kubernetes代碼閱讀apiserver的示例分析

149次閱讀
沒有評論

共計 5235 個字符,預計需要花費 14 分鐘才能閱讀完成。

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

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

kubernetes 源代碼版本 1.2.0

代碼閱讀方法

先簡單講講整個代碼的目錄結構

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

可以看到,關鍵實現代碼都放在 pkg 這個目錄下。對于 apiserver 這種跨度很廣的組件而言,唯一有效的閱讀方式估計就是

遍歷 pkg 下所有的目錄,概覽大概知道這個目錄是干啥的

從 cmd 這個入口來看 apiserver 的代碼,然后一點點由淺入深,看 apiserver 的大致實現

分特性,看具體某個大的特性是怎么實現的,例如安全,例如和 etcd 存儲對接

在上面這幾步的過程中可以看看別人的代碼閱讀文檔,能有效的節省時間

0. apiserver 主要實現了什么?

apiserver 是 k8s 系統中所有對象的增刪查改盯的 http/restful 式服務端,其中盯是指 watch 操作。數據最終存儲在分布式一致的 etcd 存儲內,apiserver 本身是無狀態的,提供了這些數據訪問的認證鑒權、緩存、api 版本適配轉換等一系列的功能。

restful 服務入門

對于 http 服務和使用 go 語言實現方式,可以看 go-restful 的文檔和例子,對這個有基本的了解,這個文檔對入門者和一知半解者極為有效!

1. 對象的數據結構

古人有言,程序就是算法 + 數據結構,搞懂了數據結構,整個程序的處理過程就明白了一半。對于 apiserver 的任何一個 api 請求來說,上圖說明了所有的數據結構關系。

k8s 放在 etcd 內的存儲對象是 api.Pod 對象 (無版本),從不同版本的請求路徑標識來操作,例如 api/v1,最后獲取到的是不同版本,例如 v1.Pod 的 json 文本。這里就經歷了幾個過程,包括

http client 訪問 /api/v1/pod/xyz,想要獲取這個 Pod 的數據

從 etcd 獲取到 api.Pod 對象

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

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

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

其中用于處理業務數據的關鍵數據結構是 APIGroupVersion,里面的幾個成員變量的作用是:

成員作用 GroupVersion 包含 api/v1 這樣的 string,用于標識這個實例 Serializer 對象序列化和反序列化器 Converter 這是一個強大的數據結構,這里放的是個接口,本體在 /pkg/conversion/conversion.go,幾乎可以轉換任意一種對象到另一種,只要你事先注入了相應的轉換函數 Storage 這個 map 的 key,用于對象的 url,value 是一個 rest.Storage 結構,用于對接 etcd 存儲,在初始化注冊時,會把這個 map 化開,化為真正的 rest 服務到存儲的一條龍服務 2. 入口和啟動文件主要數據結構 / 函數用途 kubernetes/cmd/kube-apiserver/apiserver.go
入口 kubernetes/cmd/kube-apiserver/app/options/options.gostruct APIServer 啟動選項 kubernetes/cmd/kube-apiserver/apiserver.gofunc Run 初始化一些客戶端、啟動 master 對象 kubernetes/pkg/genericapiserver/genericapiserver.gofunc Run 啟動安全和非安全的 http 服務 3. API 分組、多版本的初始化注冊 (Rest)

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

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

擴展組,REST 路徑在 /apis/extensions/$VERSION,相對應的代碼里面的 apiVersion: extensions/$VERSION (例如當前的 apiVersion: extensions/v1beta1)。這里提供的 API 對象今后有可能會被移動到別的組內。

componentconfig 和 metrics 這這些組。

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

kubernetes/pkg/master/master.go

api 注冊入口

func New(c *Config) (*Master, error) {m.InstallAPIs(c)
}

根據 Config 往 APIGroupsInfo 內增加組信息,然后通過 InstallAPIGroups 進行注冊

func (m *Master) InstallAPIs(c *Config) {if err := m.InstallAPIGroups(apiGroupsInfo); err != nil {glog.Fatalf( Error in registering group versions: %v , err)
}

轉換為 APIGroupVersion 這個關鍵數據結構,然后進行注冊

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)
}

關鍵數據結構

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 來提供服務的呢?例如這么一個 URL:

GET /api/v1/namespaces/{namespace}/pods/{name}

restful 服務的實現

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

數據結構功能在 k8s 內的位置 restful.Container 代表一個 http rest 服務對象,包括一組 restful.WebServicegenericapiserver.go – GenericAPIServer.HandlerContainerrestful.WebService 由多個 restful.Route 組成,處理這些路徑下所有的特殊的 MIME 類型等 api_installer.go – NewWebService()restful.Route 路徑——處理函數映射 mapapi_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 注冊過程是在這個函數中完成的,把一個 rest.Storage 對象轉換為實際的 getter, lister 等處理函數,并和實際的 url 關聯起來。

4.etcd 存儲的操作 (ORM)

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

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

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

這個文件定義了所有的對 etcd 對象的操作,get,list,create 等,但具體的對象是啥,這個文件不關心;etcd 客戶端地址,這個文件也不關心。這些信息都是在具體的 PodStorage 對象創建的時候注入的。以 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 匿名內部成員,天然就擁有 Get, List 等方法。

kubernetes/pkg/apiserver/api_installer.go

最后在這里把 PodStorage 轉換成了 Getter 對象,并最終注冊到 ApiGroup 里面去。

感謝你能夠認真閱讀完這篇文章,希望丸趣 TV 小編分享的“kubernetes 代碼閱讀 apiserver 的示例分析”這篇文章對大家有幫助,同時也希望大家多多支持丸趣 TV,關注丸趣 TV 行業資訊頻道,更多相關知識等著你來學習!

正文完
 
丸趣
版權聲明:本站原創文章,由 丸趣 2023-08-16發表,共計5235字。
轉載說明:除特殊說明外本站除技術相關以外文章皆由網絡搜集發布,轉載請注明出處。
評論(沒有評論)
主站蜘蛛池模板: 南昌市| 屯昌县| 广宁县| 玛纳斯县| 宜兰县| 石屏县| 辽宁省| 乐安县| 西乌| 澄迈县| 九江市| 德安县| 南宁市| 龙里县| 花莲市| 新宁县| 达日县| 长岭县| 贵德县| 新宁县| 新巴尔虎右旗| 当阳市| 永登县| 大连市| 安庆市| 铅山县| 丰城市| 台东县| 沙洋县| 台南市| 定州市| 宝坻区| 景洪市| 资溪县| 昌宁县| 保德县| 江门市| 安康市| 东辽县| 仙桃市| 惠州市|