1. 程式人生 > >深度剖析Kubernetes API Server三部曲 - part 1

深度剖析Kubernetes API Server三部曲 - part 1

格式 author pve services batch 歡迎來到 blog 用戶權限 list

歡迎來到深入學習Kubernetes API Server的系列文章,在本系列文章中我們將深入的探究Kubernetes API Server的相關實現。如果你對Kubernetes 的內部實現機制比較感興趣或者正在進行Kubernetes 項目的相關開發工作,那麽本系列文章能夠為你提供一些幫助。了解學習過go語言,會在某些方面幫助你更好的理解本系列文章。
在本期文章中,我們首先會對Kubernetes API Server進行一個總體的大致說明,然後對API的技術術語及請求流作說明。在下幾期的文章中則主要對API Server與etcd存儲的交互以及對API Server進行相關擴展進行探討,說明。
API Server的總體說明
從理論上來說,Kubernetes 是由一些具有不同角色的節點組成的。作為控制面的主節點主要部署有API Server, Controller Manager 和 Scheduler(s)等組件。API Server作為Kubernetes 中的管理中心,是唯一能夠與存儲etcd交互通信的組件。它主要能夠提供如下服務:

  1. 作為 Kubernetes API的服務端,為集群內的節點以及kubectl工具提供API服務。
  2. 作為集群組件的代理,例如Kubernetes UI
  3. 通過API Server能夠對Kubernetes的API對象比如pods,services進行增刪查改等操作。
  4. 保證在分布式存儲系統(etcd)中的Kubernetes API對象的狀態一致。
    技術分享圖片
    Kubernetes API是一個HTTP形式的 API,JSON格式是它主要的序列化架構。同時它也支持協議緩沖區(Protocol Buffers)的形式,這種形式主要是用在集群內通信中。出於可擴展性原因考慮, Kubernetes可支持多個API版本,通過不同的API路徑的方式區分。比如/api/v1 和 /apis/extensions/v1beta1,不同的API版本代表了這個API處於不同的版本穩定性階段。
  5. Alpha 階段,比如v1alpha1,在默認狀態下為關閉狀態。只在某個分支中支持使用,在將來可能會被廢棄。一般只支持在測試環境中短期使用。
  6. Beta階段,比如v2beta3,在默認狀態下為開啟狀態。表示這部分代碼已經經過測試,基本功能已經通過驗證。但是這個狀態的API對象將來還是有可能發生不可兼容的改動以過度到stable 穩定階段。
  7. Stable階段,比如v1,是一個穩定的軟件發布階段,API對象一般之後不會有太大改動。
    接下去,我們介紹一下HTTP API主要結構。首先我們需要區分三種不同的API形式:core group API (在/api/v1路徑下,由於某些歷史原因而並沒有在/apis/core/v1路徑下)和named groups API(在對應的/apis/$NAME/$VERSION路徑下)及system-wide API(比如/metrics,/healthz)。
    一個HTTP API的主要結構如下所示:
    技術分享圖片
    接下去我們主要列舉batch group下的兩個API例子來講解說明。在Kubernetes 1.5版本中,batch 群組下有/apis/batch/v1 和 /apis/batch/v2alpha1兩個API版本來供開發者使用。我們來看一下API的整體實現(下面列舉的API例子我們是通過proxy 命令kubectl proxy --port=8080直接訪問API獲得)。
    $ curl http://127.0.0.1:8080/apis/batch/v1
    {
    "kind": "APIResourceList",
    "apiVersion": "v1",
    "groupVersion": "batch/v1",
    "resources": [
    {
    "name": "jobs",
    "namespaced": true,
    "kind": "Job"
    },
    {
    "name": "jobs/status",
    "namespaced": true,
    "kind": "Job"
    }
    ]
    }
    在將來,將會使用更新的alpha 版本:
    $ curl http://127.0.0.1:8080/apis/batch/v2alpha1
    {
    "kind": "APIResourceList",
    "apiVersion": "v1",
    "groupVersion": "batch/v2alpha1",
    "resources": [
    {
    "name": "cronjobs",
    "namespaced": true,
    "kind": "CronJob"
    },
    {
    "name": "cronjobs/status",
    "namespaced": true,
    "kind": "CronJob"
    },
    {
    "name": "jobs",
    "namespaced": true,
    "kind": "Job"
    },
    {
    "name": "jobs/status",
    "namespaced": true,
    "kind": "Job"
    },
    {
    "name": "scheduledjobs",
    "namespaced": true,
    "kind": "ScheduledJob"
    },
    {
    "name": "scheduledjobs/status",
    "namespaced": true,
    "kind": "ScheduledJob"
    }
    ]
    }
    總體上來說 Kubernetes API 支持對API對象的增刪查改( create, update, delete, retrieve)通過使用JSON作為默認格式的HTTP (POST, PUT, DELETE, GET)方式來實現。
    大多數API對象會區分對象想要達到的預期狀態以及當前對象所處的實際狀態。所以一個規範的API描述應該對於這兩種狀態都有完整的描述說明並在儲存(etcd)中記錄。
    API Server的術語說明
    在對API Server以及HTTP API結構進行總體說明後,接下去我們對一些術語來進行說明解釋。Kubernetes 的主要API對象主要有pods, services, endpoints, deployment等。一個API對象主要由以下條目
    Kind:是一個API對象的類型。它告訴了client(比如kubectl)這種API對象所代表的實體類型。比如一個pod
    apiVersion: v1
    kind: Pod
    metadata:
    name: webserver
    spec:
    containers:
    • name: nginx
      image: nginx:1.9
      ports:
    • containerPort: 80
      目前API中有三種Kinds類型:
  8. Object對象代表了系統中持久存在的實體,一個object對象可能具有多個resources資源能讓客戶端來執行一些特定的操作。比如Pod和namespace.
  9. Lists 代表了一些resources資源或者object實體對象的集合。比如PodLists和 NodeLists.
  10. 代表了一個對實體對象的操作或一個非實體存在的狀態過程。比如binding或者status等。
    API Group :是一組相關的Kind的集合。比如在Kind:Job以及Kind:ScheduleJob都屬於batch的API Group.
    Version:每個API Group下面都能存在有多個version版本。比如在一個group群組中最早有第一個v1alpha1版本,後來中間發展到了v1beta1 版本,最終發展到v1的穩定版本。如果在系統創建了一個v1beta1 版本的對象,那麽它能過被Group任一支持的版本(比如v1)檢索到。這是由於API server能夠支持不同版本對象之間的無損耗轉換。
    Resource :代表以JSON格式通過HTTP發送或檢索的資源實體。它既可以使一個單獨的resource 資源(比如.../namespaces/default)也可以是一組resource 資源(比如.../jobs)
    一個API Group群組,一個Version版本,一個Resource(GVR)資源就能過定義一個唯一的HTTP路徑。
    技術分享圖片
    實際上,一個job對象的API路徑為/apis/batch/v1/namespaces/$NAMESPACE/jobs,因為jobs並不是cluster側的資源,所以需要有namespace字段。與之相對node作為cluster側的資源,它的API路徑就沒有$NAMESPACE的部分。
    值得註意的是Kinds不一定只在同一個Group群組下存在不同的Version版本,它在不同的Group群組也有可能存在不同的Version版本。比如Deployment 一開始在extensions group群組中作為alpha 版本存在,但最後它發展成GA version版本時擁有了一個新的獨立的Group群組apps.k8s.io。因此,如果想要區分唯一的Kinds,必須要有API Group,Version以及Kind(GVK)三部分。
    API請求流過程
    在對Kubernetes API中的術語有了了解之後,接下去我們將討論API請求的處理流程。相關API主要在k8s.io/pkg/api可以看到,它既處理來自集群內的API請求也處理來自集群外的API請求。
    當API Server接收到一個HTTP的Kubernetes API請求時,它主要處理流程如下所示:
  11. HTTP 請求通過一組定義在DefaultBuildHandlerChain()(config.go)函數中的過濾處理函數處理,並進行相關操作(相關過濾處理函數如下圖所示)。這些過濾處理函數將HTTP 請求處理後存到中ctx.RequestInfo,比如用戶的相關認證信息,或者相應的HTTP請求返回碼。
  12. 接著multiplexer (container.go)基於HTTP路徑會將HTTP 請求發給對應的各自的處理handlers 。
  13. routes (在routes/*定義)路由將HTTP路徑與handlers 處理器關聯。
  14. 根據每個API Group註冊的處理程序獲取HTTP請求相關內容對象(比如用戶,權限等),並將請求的內容對象存入存儲中。
    完整的處理流程如下圖所示
    技術分享圖片
    再次提醒,為簡潔起見,我們省略了上圖中HTTP路徑的$NAMESPACE字段。
    下面我們來仔細看一下定義在DefaultBuildHandlerChain()(config.go)函數中的相關filters過濾處理函數:
  15. 定義在 requestinfo.go中的WithRequestInfo()函數主要獲取HTTP請求的RequestInfo內容。
  16. 定義在 maxinflight.go的中的WithMaxInFlightLimit()函數限制請求的 in-flight數量。
  17. 定義在timeout.go的中的WithTimeoutForNonLongRunningRequests()函數主要定義了類似GET, PUT, POST, DELETE等non-long-running請求的超時時間。
  18. 定義在wrap.go 中的WithPanicRecovery()函數主要定義了當發生panic之後的相關處理。
  19. 定義在cors.go中的WithCORS()函數主要提供了CORS 實現。CORS代表跨源資源共享,它是一種機制,允許能夠處理嵌入在HTML頁面中的JavaScript的XMLHttpRequests請求。
  20. 定義在authentication.go 中的WithAuthentication()函數主要對請求中的用戶信息進行驗證,並將用戶信息存到相應的context中。如果認證成功,那麽Authorization HTTP頭將會在request請求體中移除。
  21. 定義在 audit.go 中的WithAudit()函數主要將request的用戶信息進行相關處理。然後將Request請求的源IP,用戶名,用戶操作及namespace等信息記入到相關審計日誌中。
  22. 定義在impersonation.go中的WithImpersonation()函數主要處理用戶模擬,通過嘗試修改請求的用戶(比如sudo)的方式。
  23. 定義在authorization.go中的WithAuthorization()函數主要請求中的用戶權限就行驗證,如果驗證通過則發送給相應的handler進行處理,如果權限驗證不通過則拒絕此次請求,返回相應錯誤。
    本部分文章主要對API Server進行了一個總體介紹。下一部分,我們將對API資源的序列化以及如何存入到相關分布式存儲中進行探究。https://www.huaweicloud.com/product/cce.html

深度剖析Kubernetes API Server三部曲 - part 1