APIServer
在kubernetes架構概念層面上,Kubernetes由一些具有不同角色的服務節點組成。而master的控制平面由 Apiserver
Controller-manager
和 Scheduler
組成。
Apiserver
從概念上理解可以分為 api
和 object
的集合,api
可以理解為,處理讀寫請求來修改相應 object
的元件;而 object
可以表示為 kubernetes 物件,如 Pod
, Deployment
等 。
基於宣告式的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需要掌握一些概念才可繼續。
Group
出於對kubernetes擴充套件性的原因,將資源型別分為了API組進行獨立管理,可以通過 kubectl api-resources
檢視。在程式碼部分為 vendor/k8s.io/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
實際上為資源名稱,Pod
,Deployment
等。
根據 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:實際的狀態
API Link
前面講到的 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
,因其只是儲存的資料,所以沒有 spec
和 status
kubectl get --raw /api/v1/namespaces/kube-system/configmaps/coredns|jq
kind
apiVersion
metadata
data
API組成
一個API的組成為 一個 API 組Group
, 一個版本 Version
, 和一個資源 Resource
; 簡稱為 GVR
轉換為實際的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()
接收上下文,從儲存中傳遞請求的物件。