深度剖析Kubernetes API Server三部曲 - part 3
在本系列的前兩部分中我們介紹了 API Server 的總體流程,以及 API 物件如何儲存到 etcd 中。在本文中我們將探討如何擴充套件 API 資源。
在一開始的時候,擴充套件 API 資源的唯一方法是擴充套件相關 API 原始碼,整合為你所需的資源。或者,推動一個全新的型別為新的核心物件 API 合入社群程式碼。但是,這樣就會導致核心 API 資源型別的不斷增加,直至 API 過載。為了避免這種 API 資源的無限制擴充套件,在 Kubernetes 中提供兩種擴充套件核心 API 的方法:
1. 使用自定義資源定義( CRDs ),最開始的時候被稱為第三方資源( TPRs )。透過 CRD 你能夠簡單而靈活的方式定義自己的資源物件型別,並讓 API server 處理整個生命週期。
2. 使用與主 API Servers 並行執行的使用者 API Servers ( UAS )。這種方式,可能更多的設計程式碼開發,可能需要你投入較多的時間及精力。當然,這種方式也能夠讓你對 API 資源有更細緻,全面的瞭解。
在本文中,我們主要對 CRD 相關定義以及使用進行探討。
CRDs 的宣告及建立
在本系列文章第一部分所提到過的,每個 API 資源根據 Group 群組分類,每個物件都有一個對應的版本號與 HTTP 路徑相關聯。現在如果想要實現一個 CRD ,首先需要的是就是命名一個新的 API Group 群組,這個 API 群組不能與已經存在的群組重複。在你自己新建的 API 群組中,你可以擁有任意數量的資源,並且它們可以與其他群組中的資源具有相同的名稱。下面我們來列舉一個實際的例子:
在之前我們有介紹過,每個版本的由 API 群組管理的 Kubernetes 資源是跟 HTTP 路徑相關的。 CRD 類似於物件導向程式設計中一個類的定義,而實際使用的 CR 可以看做為它的一組例項。首先我們對例子中的一些欄位作說明,第一行中的 CRD apiVersion 在 kube-apiserver 1.7 之後都是這樣定義的。從第 5 行之後我們定義了 spec 的相關欄位。在第 6 行 spec.group 是定義了你建立的 CRD 的 API 群組(在本例子中定義為了 example.com )。第 7 行定義了 CRD 物件的版本。每個資源只有一個固定版本,但在 API 群組中還是能有多個不同版本的資源。第 8 行的 spec.names 有兩個必填項: kind ,按照慣例第一個字母大寫, plural ,按照慣例全為小寫,這個欄位與最終生成的 HTTP 路徑相關,比如在本例子中,最終的 HTTP 路徑為 。還有一個可選的 singular 欄位,預設為小寫型別值,可以在 kubectl 的上下文中使用。此外,在 spec.names 中還有許多可選欄位,這些欄位將會由 API Server 自動生成並填充。
上面的 kind 主要是用來描述物件的型別,而 resource 資源是與 HTTP 路徑相關的。大多數情況下這兩個是匹配的;但是在某些特定情況下在相同的 API HTTP 路徑下可能返回不通的 kind (比如 Status 錯誤物件會返回另一種 kind )。
值得注意的是 resource 資源(在本例中是 databases )和 group 群組(本例中是 example.com )必須與 metadata.name 欄位匹配(本例為第四行 databases. example.com )。
現在我們根據上面的 YAML 檔案來建立一個 CRD :
$ kubectl create -f databases-crd.yaml
customresourcedefinition "databases.example.com" created
由於這個建立過程是非同步進行的,所以你必須檢查一下你建立的 CRD 的狀態,確認你建立的 CRD 沒有與其它資源衝突,並且 API Server 已經呼叫相關處理函式完成建立。你可以在指令碼或程式碼中透過輪詢完成這個過程。最後我們能得到以下狀態:
$ kubectl get crd databases.example.com -o yaml
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
creationTimestamp: 2017-08-09T09:21:43Z
name: databases.example.com
resourceVersion: "792"
selfLink: /apis/apiextensions.k8s.io/v1beta1/customresourcedefinitions/databases.example.com
uid: 28c94a05-7ce4-11e7-888c-42010a9a0fd5
spec:
group: example.com
names:
kind: Database
listKind: DatabaseList
plural: databases
singular: database
scope: Namespaced
version: v1
status:
acceptedNames:
kind: Database
listKind: DatabaseList
plural: databases
singular: database
conditions:
- lastTransitionTime: null
message: no conflicts found
reason: NoConflicts
status: "True"
type: NamesAccepted
- lastTransitionTime: 2017-08-09T09:21:43Z
message: the initial names have been accepted
reason: InitialNamesAccepted
status: "True"
type: Established
以上,我們可以看到透過 kubectl 可以看到我們之前建立的 CRD ,並且顯示出了 CRD 的一些狀態資訊。
CRDs 的使用
在 透過 kubectl proxy 將 Kubernetes API 開啟本地代理後,檢視我們剛才建立的 CRD:
$ http 127.0.0.1:8001/apis/example.com
HTTP/1.1 200 OK
Content-Length: 223
Content-Type: application/json
Date: Wed, 09 Aug 2017 09:25:44 GMT
{
"apiVersion": "v1",
"kind": "APIGroup",
"name": "example.com",
"preferredVersion": {
"groupVersion": "example.com/v1",
"version": "v1"
},
"serverAddressByClientCIDRs": null,
"versions": [
{
"groupVersion": "example.com/v1",
"version": "v1"
}
]
}
請注意,在預設情況下十分鐘內, kubectl 是檢視儲存在 ~/.kube/cache/discovery 目錄的快取。所以,可能會需要 10 分鐘後你才能看到你新建立的 CRD 資源。但是,當沒有快取時, kubectl 發現不了所需的資源時,那麼會重新快取它。
接下來,我們來看一個 CRD 例項:
$ cat wordpress-database.yaml
apiVersion: example.com/v1
kind: Database
metadata:
name: wordpress
spec:
user: wp
password: secret
encoding: unicode
$ kubectl create -f wordpress-databases.yaml
database "wordpress" created
$ kubectl get databases.example.com
NAME KIND
wordpress Database.v1.example.com
想要透過
API
來監控資源的建立與
更新,你可以透過對某個
resourceVersion
(我們透過
curl
來例項對指定版本的
database
做監控
)之後的修改做監控
watch
。
$ http 127.0.0.1:8001/apis/example.com/v1/namespaces/default/databases
HTTP/1.1 200 OK
Content-Length: 593
Content-Type: application/json
Date: Wed, 09 Aug 2017 09:38:49 GMT
{
"apiVersion": "example.com/v1",
"items": [
{
"apiVersion": "example.com/v1",
"kind": "Database",
"metadata": {
"clusterName": "",
"creationTimestamp": "2017-08-09T09:38:30Z",
"deletionGracePeriodSeconds": null,
"deletionTimestamp": null,
"name": "wordpress",
"namespace": "default",
"resourceVersion": "2154",
"selfLink": "/apis/example.com/v1/namespaces/default/databases/wordpress",
"uid": "8101a7af-7ce6-11e7-888c-42010a9a0fd5"
},
"spec": {
"encoding": "unicode",
"password": "secret",
"user": "wp"
}
}
],
"kind": "DatabaseList",
"metadata": {
"resourceVersion": "2179",
"selfLink": "/apis/example.com/v1/namespaces/default/databases"
}
}
我們可以對 /apis/example.com/v1/namespaces/default/databases/wordpress CRD 的 HTTP 路徑 透過 curl 命令對的 "resourceVersion": "2154" 進行監控 watch:
$ curl -f 127.0.0.1:8001/apis/example.com/v1/namespaces/default/databases?watch=true&resourceVersion=2154
現在我們新開一個
shell
對話視窗,刪除
wordpress
CRD
資源,我們可以檢視剛才的監控
watch
視窗是否接收到了這個訊息:
$ kubectl delete databases.example.com/wordpress
請注意:我們能夠使用 kubectl delete database wordpress 刪除 CRD 資源,是因為之前在 Kubernetes 沒有定義有 database 資源。此外, database 是我們 CRD 中的 spec.name.singular 欄位 ,從英語語法派生而來。
我們可以看到之前監控 watch CRD databases 從 API Server 處返回的更新狀態:
{"type":"DELETED","object":{"apiVersion":"example.com/v1","kind":"Database","metadata":{"clusterName":"","creationTimestamp":"2017-0[0/515]
:38:30Z","deletionGracePeriodSeconds":null,"deletionTimestamp":null,"name":"wordpress","namespace":"default","resourceVersion":"2154","selfLink":"/apis/example.com/v1/namespaces/
default/databases/wordpress","uid":"8101a7af-7ce6-11e7-888c-42010a9a0fd5"},"spec":{"encoding":"unicode","password":"secret","user":"wp"}}}
上述 shell 會話的執行及輸出結果如下圖所示:
最後,讓我們看一下 CRD database 的各個資料是如何儲存在 etcd 中的。下面是我們直接透過 HTTP API 進入 etcd 訪問得到的資料:
$ curl -s localhost:2379/v2/keys/registry/example.com/databases/default | jq .
{
"action": "get",
"node": {
"key": "/registry/example.com/databases/default",
"dir": true,
"nodes": [
{
"key": "/registry/example.com/databases/default/wordpress",
"value": "{\"apiVersion\":\"example.com/v1\",\"kind\":\"Database\",\"metadata\":{\"clusterName\":\"\",\"creationTimestamp\":\"2017-08-09T14:53:40Z\",\"deletionGracePeriodSeconds\":null,\"deletionTimestamp\":null,\"name\":\"wordpress\",\"namespace\":\"default\",\"selfLink\":\"\",\"uid\":\"8837f788-7d12-11e7-9d28-080027390640\"},\"spec\":{\"encoding\":\"unicode\",\"password\":\"secret\",\"user\":\"wp\"}}\n",
"modifiedIndex": 670,
"createdIndex": 670
}
],
"modifiedIndex": 670,
"createdIndex": 670
}
}
從上面可以看到, CRD 資料在 etcd 中最終以一個未解析的的狀態存在。現在將 CRD 刪除,所有的 CRD 例項也會跟著刪除,這是一個級聯刪除操作。
目前 CRDs 的使用現狀,侷限及將來的展望
CRDs 的發展現狀如下所示:
1.
在
Kubernetes 1.7
版本中
CRDs
開始取代
ThirdPartyResources
(TPRs)
,並且
TPRs
將會在
Kubernetes 1.8
被刪除。
2. 將 TPRs 遷移到 CRDs 例項可以參考文件 。
3. 支援一個 CRD 中只有單個 version 版本,當然,一個群組中可能有多個 version 版本。
4. CRDs 提供一個 API 方案,在使用者角度看它與 Kubernetes 原生的 API 資源基本沒有區別
5. CRDs 是多版本多分支穩定的基礎。關於 CRD 資源的 JSON-Schema 的格式有效性校驗可以參考文件 。相關資源回收可以參考文件 Garbage collection 。
接下去我們來看一下一些 CRDs 的侷限:
1. CRD 不提供版本轉換功能,也就是說,每個 CRD 只能有一個版本(預計不會在近期或中期內看到支援 CRD 版本轉換)。
2. 在 Kubernetes1.7 當中,目前並沒有對於 CRD 的相關校驗 validation 。
3. 沒有快速,實時的准入( admission )機制(但是可以支援 webhooks 形式的初始化及准入)。
4. 在 Kubernetes1.7 中你不能定義子資源( sub-resources ),比如 scale 或者 status ,不過目前有在這方面 的討論。
5. CRD 目前不支援預設值配置,即不支援為特定的欄位配預設值(在 Kubernetes1.7 後續的版本中可能會支援)。
為了解決上述的問題,並且靈活的擴充套件 Kubernetes ,你可以執行一個與主 API Server 並行的使用者 API Servers 。我們將在本博文的以後部分中詳細介紹如何編寫 UAS ,並編寫一個 custom controller 完整使用 CRD 。https://www.huaweicloud.com/product/cce.html
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31543630/viewspace-2213245/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 深度剖析Kubernetes API Server三部曲 - part 1APIServer
- 深度剖析Kubernetes API Server三部曲 - part 2APIServer
- 資深專家深度剖析Kubernetes API Server第3章(共3章)APIServer
- 資深專家深度剖析Kubernetes API Server第2章(共3章)APIServer
- 資深專家深度剖析Kubernetes API Server第1章(共3章)APIServer
- Tinyalsa PCM API 實現深度剖析API
- Kubernetes API server工作原理APIServer
- Datatable Scroller (Server Side) Part:3ServerIDE
- Kubernetes安裝之六:配置master之api-serverASTAPIServer
- kubernetes實踐之四十五:API Server原理分析APIServer
- offsetParent、offsetLeft/offsetTop深度剖析
- 深度剖析一站式分散式事務方案Seata(Fescar)-Server分散式Server
- 深度剖析一站式分散式事務方案 Seata(Fescar)-Server分散式Server
- kubernetes實戰篇之通過api-server訪問dashboardAPIServer
- 《The Rust Programming language》程式碼練習(part 3 簡單web server)RustWebServer
- 深度剖析Reflect + 實戰案例
- spark核心原始碼深度剖析Spark原始碼
- ThreadLocal原始碼深度剖析thread原始碼
- URL Schemes深度剖析(上)Scheme
- 深度剖析WhatsApp傳奇APP
- Hadoop-Drill深度剖析Hadoop
- API Schema in kubernetesAPI
- 使用 Kubernetes APIAPI
- Kubernetes深入學習之二:編譯和部署映象(api-server)編譯APIServer
- 從3DS到Switch,深度剖析《動物之森》的設計理念3D
- 深度剖析分散式事務效能分散式
- Kafka面試知識點深度剖析Kafka面試
- AndroidToast問題深度剖析(一)AndroidAST
- C語言深度剖析-筆記C語言筆記
- cursor_sharing=similar深度剖析MILA
- buffer busy wait 的深度剖析AI
- Kubernetes Metrics Server元件Server元件
- 4-Kubernetes APIAPI
- Kubernetes API 基礎API
- 剖析Unreal Engine超真實人類的渲染技術Part 3 - 毛髮渲染及其它Unreal
- Android視訊開發進階(part3-Android的Media API)AndroidAPI
- 剖析SQL Server執行計劃SQLServer
- OpenHarmony 3GPP協議開發深度剖析——一文讀懂RIL協議