如何擴充套件Kubernetes管理的資源物件?
Kubernetes是一套容器化解決方案,也是一套資源管理的架構和標準;本次分享是基於我在餓了麼現階段容器化經驗和理念的總結,探討深化Kubernetes在企業內部的應用的方法,介紹如何利用開源的API Server框架在企業內部打造和擴充套件Kubernetes管理的資源物件。
Kubernetes逐漸成熟,也成為許多公司容器化平臺的首選,然而在落地當中,每個企業面對的問題場景多少也有些不一樣的,總是希望對Kubernetes做改造,來更好的滿足企業目前的需求。
然而fork一個Kubernetes分支出來並不是一個好的選擇,那麼有其他方案嗎?
接下來,我們先了解下Kubernetes的API Server。
- API Server作為整個Kubernetes叢集的核心元件,讓所有資源可被描述和配置;這裡的資源包括了類似網路、儲存、Pod這樣的基礎資源也包括了replication controller、deployment這樣的管理物件
- API Server某種程度上來說更像是包含了一定邏輯的物件資料庫;介面上更加豐富、自帶GC、支援物件 間的複雜邏輯;當然API Server本身是無狀態的 資料都在etcd當中;
- API Server提供基於RESTful的管理介面,支援增刪改查和patch、監聽的操作,其他元件通過和API Server的介面獲取資源配置和狀態,以實現各種資源處理邏輯。
在Kubernetes叢集外打造另一個API Server來擴充套件Kubernetes的資源,與原生Kubernetes組成“聯邦”;一來解除和社群版本的耦合,二來可以最大化定製需求,在一些場景下,這個方案更具靈活性和可操作性。
我們也部署了Kubernetes叢集,但是也遇到了一些挑戰。一是Kubernetes並不能解決所有容器化帶來的問題,二來我們也看到了Kubernetes這套框架在擴充套件性、靈活性等方面優點,所以我們已經在積極嘗試實踐Kubernetes框架來延伸Kubernetes方案。
那麼好實現嗎?有沒有現成的開源框架方便實現這個方案呢,而不需要大海撈針,在Kubernetes原始碼裡去抽絲剝繭呢?
令人興奮的是答案是肯定的,Kubernetes單獨開源了API Server的開發框架。
專案地址:https://github.com/kubernetes/apiserver.git,需要說明的是這個專案本身和Kubernetes的程式碼保持同步的。
那麼我們接下來就看下如何利用Kubernetes開源的框架構建特定資源的API Server。
由於已經有很多文章介紹API Server的架構這裡不再贅述,我主要講下如何使用框架,從新增一個資源的過程來了解這個框架。
先上架構圖
這裡有幾個概念要先介紹:
- Scheme:定義了資源序列化和反序列化的方法以及資源型別和版本的對應關係;這裡我們可以理解成一張紀錄表。
- Storage:是對資源的完整封裝,實現了資源建立、刪除、watch等所有操作。
- APIGroupInfo:是在同一個Group下的所有資源的集合。
還需要注意的是:一個資源對應著兩個版本;一個版本是使用者訪問的介面物件(yaml或者json通過介面傳遞的格式),另一個版本則是核心物件,實現了資源建立和刪除等,並且直接參與持久化,對應了在etcd中儲存,這兩個版本的資源是需要相互轉化的,並且轉換方法需要事先註冊在Scheme中。
接下來我們具體描述下API Server框架下資源的構建過程。
定義一個資源先要定義好核心物件:
type TestObjList struct { Items []TestObj } type TestObj struct {}
然後定義該資源的”對外”版本-介面物件,可以和核心物件一樣也可以不一樣,例如,我們可以這樣定義介面物件:
type TestObjList struct { Items []TestObj } type TestObj struct { Number int }
接下來實現資源向Scheme註冊的介面函式 SchemeFunc—AddToScheme
func addKnownTypes(scheme *runtime.Scheme) error { scheme.AddKnownTypes(SchemeGroupVersion, &TestObj{}, &TestObjList{}, ) metav1.AddToGroupVersion(scheme, SchemeGroupVersion) return nil } SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) AddToScheme = SchemeBuilder.AddToScheme
資源要能被RESTful介面訪問到,是需要構建實現rest.Storage介面的物件;我們可以藉助Registry.Store(實現了標準的儲存物件介面)實現:
type REST struct { *registry.Store } func NewREST() *REST { store := ®istry.Store{} return &REST{store} }
然後組裝出APIGroupInfo(APIGroupInfo是包含了一組資源型別的集合):
apiGroupInfo := apiserver.NewDefaultAPIGroupInfo(... Scheme) v1alpha1storage := map[string]rest.Storage{} v1alpha1storage["testobj"] = NewREST() apiGroupInfo.VersionedResourcesStorageMap["v1alpha1"] = v1alpha1storage
GenericAPIServer.InstallAPIGroup(&apiGroupInfo).Run()
注意:上文中程式碼為了更好的突出顯示資源建立邏輯,一些細節被隱藏掉了。例如可能大家會有疑問,etcd、admissionControl怎麼沒配置,這其實是在GenericAPIServer中實現了。
最後總結一下,Kubernetes是一套容器化解決方案,也是一套資源管理的架構和標準。
Q&A
A:舉個例子,假如有這樣一個場景,Nginx作為反向代理,我們需要非常詳細的管理具體配置,並且Nginx的upstream不單單是容器還有許多部署在物理機和虛擬機器上的應用,這就要求我們需要具體定義專門管理Nginx的資源物件;由於企業應用場景是十分具體的,也就需要對於資源做具體描述。
Q:能否講下具體應用場景和聯邦後的用法?
A:場景上個問題講過了,關於聯邦我目前的方案是在自定義的Controller裡做相關聯絡和操作。
Q:擴充套件API Server和通過third party resource + controller的方式相比有哪些優點?支援和多個叢集的聯邦嗎?Kubernetes社群對這兩種擴充套件模式的態度是怎麼樣的?
A:首先third party resource在Kubernetes裡一直不是很穩定,再者third party resource和原生資源有很多不同(可以參考官方文件),滿足一些小的場景可以,但是對於深度定製化(資源之間關聯、許可權限制等),我還是會選擇擴充套件API Server。