計算機系統是分層的,也就是下層作一些支持的工做,暴露接口給上層用。注意:語言的本質是一種接口。api
計算機的最下層是CPU指令,其本質就是用「變量定義+順序執行+分支判斷+循環」所表達的邏輯過程。計算機應用的最上層是實現人類社會的某種功能。因此全部計算機編碼的過程,就是用邏輯表達現實的過程。層與層之間定義的藉口,越接近現實的表達就叫越「聲明式」(declarative),越接近計算機的執行過程就叫越「命令式」(imperative)。注意這不是絕對的概念,而是相對的概念。緩存
當接口越是在表達「要什麼」,就是越聲明式;越是在表達「要怎樣」,就是越命令式。SQL就是在表達要什麼(數據),而不是表達怎麼弄出我要的數據,因此它就很「聲明式」。C++就比C更聲明式,由於面向對象自己就是一種聲明式的體現。HTML也很聲明式,它只描述我要一張什麼樣的表,並不表達怎麼弄出一張表。bash
越是聲明式,意味着下層要作更多的東西,或者說能力越強。也意味着效率的損失。越是命令式,意味着上層對下層有更多的操做空間,能夠按照本身特定的需求要求下層按照某種方式來處理。數據結構
想要使用Kubernetes 的 API 對象,須要編寫一個對應的 YAML 文件交給 Kubernetes,而聲明式API,則爲kubectl apply 命令。而先 kubectl create,再 replace 的操做,稱爲命令式配置文件操做,並非聲明式API。app
kube-apiserver 在響應命令式請求(如kubectl replace)的時候, 一次只能處理一個寫請求,不然會有產生衝突的可能;而對於聲明式請求(如kubectl apply),一次能處理多個寫操做,而且具有 Merge 能力。函數
聲明式 API是 Kubernetes 項目編排能力「賴以生存」的核心所在:編碼
首先,「聲明式」就是提交一個定義好的API對象來聲明所指望的狀態是什麼url
其次,聲明式API容許有多個API寫端,以PATCH的方式對API對象進行修改,而無需關心本地原始YAML文件的內容code
RESTful 使用POST來建立一個資源,使用PUT或者PATCH來更新一個資源 區別是: – PUT用來總體更新一個資源,因此請求中必須包含完整的資源信息。若是缺乏部分信息,會致使這部分數據被更新爲NULL。 – PATCH則是部分更新。僅更新提供的字段,請求中缺乏的字段仍保持不變
最後,也是最重要的,有了上述兩個能力,Kubernetees項目才能夠基於對API對象的增、刪、改、查在徹底無需外界干預的狀況下,完成對「實際狀態」和「指望狀態」的調諧(Reconcile)過程。orm
首先知道一下一個 API 對象在 Etcd 裏的完整資源路徑,是由:Group(API 組)、 Version(API 版本)和 Resource(API 資源類型)三個部分組成的,能夠用以下圖的樹形結構表示出來:
API對象的組織方式是層層遞進的,Kubernetes會對Group、Version和Resource進行解析,也就是層層匹配,獲得相應的對象定義,如Cronjob(Pod、Node 等核心API對象不須要Group,直接匹配Version)。
把YAML 文件提交給 Kubernetes 以後,建立出 API 對象的流程:以建立 CronJob爲例
發起建立CronJob的POST請求後,編寫的YAML的信息就被提交給api-server
Api-server過濾這個請求,完成一些前置性的工做,好比受權、超時處理、審計等
請求進入mux和routes流程,mux和routees是api-server完成url和handler綁定的場所,api-server的Handler要作的事情就是按照層層匹配的過程,找到對應的CronJob類型定義
Api-server根據crontJob類型定義,使用用戶提交的YAML文件裏的字段,建立一個CrontJob對象
Api-server會進行一個convert工做,即把用戶提交的YAML文件轉換成一個叫作Super Version
的對象,它正是該API資源類型全部版本的字段全集,這樣用戶提交的不一樣版本的YAML就均可以用這個Super Version對象來進行處理了
前後進行admission()和validation()操做
Admission Controller和Initializer都屬於Admission的內容,Validation負責驗證這個對象裏的各個字段是否合法,這個被驗證過的API對象,都保存在來api-server裏一個叫作Registry的數據結構中,也就是說只要一個API對象的定義能在Registry裏查到,他就是一個有效的Kubernetes API對象
把驗證過的API對象轉換成用戶最初提交的版本,進行序列化操做,並調用Etcd的API把它保存起來
若是想要添加自定義API資源類型,建議使用CRD( Custom Resource Definition),它容許用戶在 Kubernetes 中添加一個跟 Pod、Node 相似的、新的 API 資源類型,即:自定義 API 資源。
使用CRD建立出自定義API對象後,就是爲這個 API 對象編寫一個自定義控制器(Custom Controller),這樣, Kubernetes 才能根據 自定義 API 對象的「增、刪、改」操做,在真實環境中作出相應的響應。
編寫自定義控制器分爲三個過程:編寫 main 函數、編寫自定義控制器的定義,以編寫控制器裏的業務邏輯。
首先從 Kubernetes 的 APIServer 裏獲取它所關心的對象,也就是自定義的控制器對象。這個操做,依靠的是一個叫做 Informer(通知器)的代碼庫完成的;Informer 與 API 對象是一一對應的,因此須要傳遞給自定義控制器一個Informer;
Informer是一個帶有本地緩存和索引機制的、能夠註冊EventHandler 的 client。它是自定義控制器跟 APIServer 進行數據同步的重要組件。
建立Informer的時候須要傳一個Client,Informer 正是使用Client,跟 APIServer 創建了鏈接;真正負責維護這個鏈接的是 Informer 所使用的 Reflector 包。
Reflector 使用的是一種叫做ListAndWatch的方法,來「獲取」並「監聽」這些API對象實例的變化(Informer經過 ListAndWatch,把 APIServer 中的 API 對象緩存在了本地,並負責更新和維護這個緩存。)在 ListAndWatch 機制下,一旦 APIServer 端有新的API對象實例被建立、刪除或者更新, Reflector 都會收到「事件通知」;這時,該事件及它對應的 API 對象這個組合,就被稱爲增量 (Delta),它會被放進一個 Delta FIFO Queue(即:增量先進先出隊列)中;Informe 會不斷地從 Delta FIFO Queue 裏讀取(Pop)增量。每拿到一個增量,Informer 就會判斷這個增量裏的事件類型,而後建立或者更新本地對象的緩存;這個緩存,在 Kubernetes 裏通常被叫做 Store
Informer 的第二個職責,則是根據這些事件的類型,觸發事先註冊好的 ResourceEventHandler;
這些 Handler,須要在建立控制器的時候註冊給它對應的 Informer。
Informer 與要編寫的控制循環之間,則使用了一個工做隊列來進行協同,防止控制循環執行過慢把Informer拖死。
接下來就是熟悉的控制循環的邏輯了
參考連接: