Kubernetes API 基礎

Cylon 發表於 2022-05-16
Kubernetes

APIServer

在kubernetes架構概念層面上,Kubernetes由一些具有不同角色的服務節點組成。而master的控制平面由 Apiserver Controller-managerScheduler 組成。

Apiserver 從概念上理解可以分為 apiobject 的集合,api 可以理解為,處理讀寫請求來修改相應 object 的元件;而 object 可以表示為 kubernetes 物件,如 PodDeployment 等 。

基於宣告式的API

在命令式 API 中,會直接傳送要執行的命令,例如:執行停止 等命令。在宣告式API 中,將宣告希望系統執行的操作,系統將不斷將自身狀態朝希望狀態改變。

為什麼使用宣告式

在分散式系統中,任何元件隨時都可能發生故障,當元件故障恢復時,需要明白自己需要做什麼。在使用命令式時,出現故障的元件可能在異常時錯過呼叫,並且在恢復時需要其他外部元件進行干預。而宣告式僅需要在恢復時確定當前狀態以確定他需要做什麼。

External APIs

在kubernetes中,控制平面是透明的,及沒有internal APIs。這就意味著Kubernetes元件間使用相同的API互動。這裡通過一個例子來說明外部APIs與宣告式的關係。

例如,建立一個Pod物件,Scheduler 會監聽 API來完成建立,建立完成後,排程程式不會命令被分配節點啟動Pod。而在kubelet端,發現pod具有與自己相同的一些資訊時,會監聽pod狀態。如改變kubelet則修改狀態,如果刪除掉Pod(物件資源不存在與API中),那麼kubelet則將終止他。

為什麼不使用Internal API

使用External API可以使kubernetes元件都使用相同的API,使得kubernetes具有可擴充套件性和可組合性。對於kubernetes中任何預設元件,如不足滿足需求時,都可以更換為使用相同API的元件。

另外,外部API還可輕鬆的使用公共API來擴充套件kubernetes的功能

API資源

從廣義上講,kubernetes物件可以用任何資料結構來表示,如:資源例項、配置(審計策略)或持久化實體(Pod);在使用中,常見到的就是對應YAML的資源清單。轉換出來就是RESTful地址,那麼應該怎麼理解這個呢?即,對資源的動作(操作)如圖所示。但如果需要了解Kubernetes API需要掌握一些概念才可繼續。

Kubernetes API 基礎

Group

出於對kubernetes擴充套件性的原因,將資源型別分為了API組進行獨立管理,可以通過 kubectl api-resources檢視。在程式碼部分為 vendor/k8s.io/api

Kubernetes API 基礎

也可以通過 kubectl xxx -v 6 來檢視 kubectl 命令進行了那些API呼叫

$ kubectl get pods -v 6
I0513 21:54:33.250752   38661 round_trippers.go:444] GET http://localhost:8080/api?timeout=32s 200 OK in 1 milliseconds
I0513 21:54:33.293831   38661 round_trippers.go:444] GET http://localhost:8080/apis?timeout=32s 200 OK in 0 milliseconds
I0513 21:54:33.299741   38661 round_trippers.go:444] GET http://localhost:8080/apis/discovery.k8s.io/v1beta1?timeout=32s 200 OK in 3 milliseconds
I0513 21:54:33.301097   38661 round_trippers.go:444] GET http://localhost:8080/apis/autoscaling/v2beta1?timeout=32s 200 OK in 4 milliseconds
I0513 21:54:33.301128   38661 round_trippers.go:444] GET http://localhost:8080/apis/authorization.k8s.io/v1beta1?timeout=32s 200 OK in 3 milliseconds
I0513 21:54:33.301222   38661 round_trippers.go:444] GET http://localhost:8080/apis/rbac.authorization.k8s.io/v1beta1?timeout=32s 200 OK in 1 milliseconds
I0513 21:54:33.301238   38661 round_trippers.go:444] GET http://localhost:8080/apis/authentication.k8s.io/v1beta1?timeout=32s 200 OK in 4 milliseconds
I0513 21:54:33.301280   38661 round_trippers.go:444] GET http://localhost:8080/apis/certificates.k8s.io/v1beta1?timeout=32s 200 OK in 4 milliseconds
....
No resources found in default namespace.

Kind

kubectl api-resources 中可以看到,有Kind欄位,大部分人通常會盲目的 kubectl apply ,這導致了,很多人以為 kind 實際上為資源名稱,PodDeployment 等。

根據 api-conventions.md 的說明,Kind 是物件模式,包含三種型別:

  • Object,代表系統中持久化資料資源,如,Service, Namespace, Pod
  • List,是一個或多個資源的集合,通常以List結尾,如 DeploymentList
  • 對Object的操作和和非持久化實體,如,當發生錯誤時會返回“status”型別,並不會持久化該資料。

Object

物件是Kubernetes中持久化的實體,也就是儲存在etcd中的資料;如:Replicaset , Configmap 等。這個物件代表的了叢集期望狀態和實際狀態。

例如:建立了Pod,kubernetes叢集會調整狀態,直到相應的容器在執行

Kubernetes資源又代表了物件,物件必須定義一些欄位

  • 所有物件必須具有以下欄位:
    • Kind
    • apiVersion
  • metadata
  • spec:期望的狀態
  • status:實際的狀態

前面講到的 kubectl api-resources 展示的列表不能完整稱為API資源,而是已知型別的kubernetes物件,要對展示這個API物件,需要了解其完整的週期。以 kubectl get --raw / 可以遞迴查詢每個路徑。

kubectl get --raw /
{
  "paths": [
    "/api",
    "/api/v1",
    "/apis",
    "/apis/",
    "/apis/admissionregistration.k8s.io",
    "/apis/admissionregistration.k8s.io/v1",
    "/apis/admissionregistration.k8s.io/v1beta1",
    "/apis/apiextensions.k8s.io",
    "/apis/apiextensions.k8s.io/v1",
...

對於一個Pod來說,其查詢路徑就為 /api/v1/namespaces/kube-system/pods/coredns-f9bbb4898-7zkbf

kubectl get --raw /api/v1/namespaces/kube-system/pods/coredns-f9bbb4898-7zkbf|jq
	
kind: Pod
apiVersion: v1
metadata: {}
spec:{}
status: {}

但有一些資源物件也並非這種結構,如 configMap ,因其只是儲存的資料,所以沒有 specstatus

kubectl get --raw /api/v1/namespaces/kube-system/configmaps/coredns|jq

kind
apiVersion
metadata
data

API組成

一個API的組成為 一個 API 組Group , 一個版本 Version , 和一個資源 Resource ; 簡稱為 GVR

Kubernetes API 基礎

轉換為實際的http路徑為:

  • /api/{version}/namespaces/{namespace_name}/resourcesPlural/{actual_resources_name}
  • /api/v1/namespaces/default/pods/pods123

而GVR中的R代表的是RESTful中的資源,轉換為Kubernetes中資源應為 Kind,簡稱為 GVK,K在URI中表示在:

  • /apis/{GROUP}/{VERSION}/namespaces/{namespace}/{KIND}

請求和處理

這裡討論API請求和處理,API的一些資料結構位於 k8s.io/api ,並處理叢集內部與外部的請求,而Apiserver 位於 k8s.io/apiserver/pkg/server 提供了http服務。

那麼,當 HTTP 請求到達 Kubernetes API 時,實際上會發生什麼?

  • 首先HTTP請求在 DefaultBuildHandlerChain (可以參考k8s.io/apiserver/pkg/server/config.go)中註冊filter chain,過濾器允許並將相應的資訊附加至 ctx.RequestInfo; 如身份驗證的相應
  • k8s.io/apiserver/pkg/server/mux 將其分配到對應的應用
  • k8s.io/apiserver/pkg/server/routes 定義了REST與對應應用相關聯
  • k8s.io/apiserver/pkg/endpoints/groupversion.go.InstallREST() 接收上下文,從儲存中傳遞請求的物件。

Kubernetes API 基礎