做者 | 陳顯鷺 阿里巴巴高級技術專家編程
本文整理自《CNCF x Alibaba 雲原生技術公開課》第 23 講,點擊「閱讀原文」直達課程頁面。<br />關注「阿里巴巴雲原生」公衆號,回覆關鍵詞**「入門」**,便可下載從零入門 K8s 系列文章 PPT。api
導讀:在 Kubernetes 裏面, API 編程範式也就是 Custom Resources Definition(CRD)。咱們常講的 CRD,其實指的就是用戶自定義資源。爲何會存在用戶自定義資源問題呢?本文將會從其需求來源出發,對此概念進行逐步深刻的講解。安全
首先咱們先來看一下 API 編程範式的需求來源。架構
在 Kubernetes 裏面, API 編程範式也就是 Custom Resources Definition(CRD)。咱們常講的 CRD,其實指的就是用戶自定義資源。app
爲何會有用戶自定義資源問題呢?less
隨着 Kubernetes 使用的愈來愈多,用戶自定義資源的需求也會愈來愈多。而 Kubernetes 提供的聚合各個子資源的功能,已經不能知足日益增加的普遍需求了。用戶但願提供一種用戶自定義的資源,把各個子資源所有聚合起來。但 Kubernetes 原生資源的擴展和使用比較複雜,所以誕生了用戶自定義資源這麼一個功能。函數
咱們首先具體地介紹一下 CRD 是什麼。微服務
CRD 功能是在 Kubernetes 1.7 版本被引入的,用戶能夠根據本身的需求添加自定義的 Kubernetes 對象資源。值得注意的是,這裏用戶本身添加的 Kubernetes 對象資源都是 native 的、都是一等公民,和 Kubernetes 中自帶的、原生的那些 Pod、Deployment 是一樣的對象資源。在 Kubernetes 的 API Server 看來,它們都是存在於 etcd 中的一等資源。spa
同時,自定義資源和原生內置的資源同樣,均可以用 kubectl 來去建立、查看,也享有 RBAC、安全功能。用戶能夠開發自定義控制器來感知或者操做自定義資源的變化。架構設計
下面咱們來看一個簡單的 CRD 實例。下圖是一個 CRD 的定義。
首先最上面的 apiVersion 就是指 CRD 的一個 apiVersion 聲明,聲明它是一個 CRD 的需求或者說定義的 Schema。
kind 就是 CustomResourcesDefinition,指 CRD。name 是一個用戶自定義資源中本身自定義的一個名字。通常咱們建議使用「頂級域名.xxx.APIGroup」這樣的格式,好比這裏就是 foos.samplecontroller.k8s.io。
spec 用於指定該 CRD 的 group、version。好比在建立 Pod 或者 Deployment 時,它的 group 可能爲 apps/v1 或者 apps/v1beta1 之類,這裏咱們也一樣須要去定義 CRD 的 group。
下圖就是上圖所定義的 CRD 的一個實例。
咱們來看一個包含校驗的 CRD 定義:
能夠看到這個定義更加複雜了,validation 以前的字段咱們就再也不贅述了,單獨看校驗這一段。
它首先是一個 openAPIV3Schema 的定義,spec 中則定義了有哪些資源,以 replicas 爲例,這裏將 replicas 定義爲一個 integer 的資源,最小值爲 1,最大值是 10。那麼,當咱們再次使用這個 CRD 的時候,若是咱們給出的 replicas 不是 int 值,或者去寫一個 -1,或者大於 10 的值,這個 CRD 對象就不會被提交到 API Server,API Server 會直接報錯,告訴你不知足所定義的參數條件。
再來看一下帶有狀態字段的 CRD 定義。
咱們在使用一些 Deployment 或 Pod 的時候,部署完成以後可能要去查看當前部署的狀態、是否更新等等。這些都是經過增長狀態字段來實現的。另外,Kubernetes 在 1.12 版本以前,尚未狀態字段。
狀態其實是一個自定義資源的子資源,它的好處在於,對該字段的更新並不會觸發 Deployment 或 Pod 的從新部署。咱們知道對於某些 Deployment 和 Pod,只要修改了某些 spec,它就會從新建立一個新的 Deployment 或者 Pod 出來。可是狀態資源並不會被從新建立,它只是用來回應當前 Pod 的整個狀態。上圖中的 CRD 聲明中它的子資源的狀態很是簡單,就是一個 key:value 的格式。在 "{}" 裏寫什麼,都是自定義的。
以一個 Deployment 的狀態字段爲例,它包含 availableReplicas、當前的狀態(好比更新到第幾個版本了、上一個版本是何時)等等這些信息。在用戶自定義 CRD 的時候,也能夠進行一些複雜的操做來告訴別的用戶它當前的狀態如何。
下面咱們來具體演示一下 CRD。
咱們這裏有兩個資源:crd.yaml 和 example-foo.yaml。
首先建立一下這個 CRD 的 Schema 讓咱們的 Kubernetes Server 知道該 CRD 究竟是什麼樣的。建立的方式很是簡單,就是 "kuberctl create -f crd.yaml"。
經過 "kuberctl get crd" 能夠看到剛纔的 CRD 已經被建立成功了。
這個時候咱們就能夠去建立對應的資源 "kuberctl create -f example-foo.yaml":
下面來看一下它裏面到底有什麼東西 "kubectl get foo example-foo -o yaml" :
能夠看到它是一個 Foo 的資源,spec 就是咱們剛纔所定義的,被選中的部分是基本上全部的 Kubernetes 的 metadata 資源中都會有的。所以,建立該資源和咱們正常建立一個 Pod 的區別並不大,可是這個資源不是一個 Pod,也不是 Kubernetes 自己內置的資源,這就是一個咱們本身建立的資源。從使用方式和使用體驗上來講,和 Kubernetes 內置資源的使用幾乎一致。
只定義一個 CRD 其實沒有什麼做用,它只會被 API Server 簡單地計入到 etcd 中。如何依據這個 CRD 定義的資源和 Schema 來作一些複雜的操做,則是由 Controller,也就是控制器來實現的。<br /> <br />Controller 實際上是 Kubernetes 提供的一種可插拔式的方法來擴展或者控制聲明式的 Kubernetes 資源。它是 Kubernetes 的大腦,負責大部分資源的控制操做。以 Deployment 爲例,它就是經過 kube-controller-manager 來部署的。
好比說聲明一個 Deployment 有 replicas、有 2 個 Pod,那麼 kube-controller-manager 在觀察 etcd 時接收到了該請求以後,就會去建立兩個對應的 Pod 的副本,而且它會去實時地觀察着這些 Pod 的狀態,若是這些 Pod 發生變化了、回滾了、失敗了、重啓了等等,它都會去作一些對應的操做。
因此 Controller 纔是控制整個 Kubernetes 資源最終表現出來的狀態的大腦。
用戶聲明完成 CRD 以後,也須要建立一個控制器來完成對應的目標。好比以前的 Foo,它但願去建立一個 Deployment,replicas 爲 1,這就須要咱們建立一個控制器用於建立對應的 Deployment 才能真正實現 CRD 的功能。
這裏以 kube-controller-manager 爲例。
如上圖所示,左側是一個 Informer,它的機制就是經過去 watch kube-apiserver,而 kube-apiserver 會去監督全部 etcd 中資源的建立、更新與刪除。Informer 主要有兩個方法:一個是 ListFunc;一個是 WatchFunc。
Informer 接收到了對象的需求以後,就會調用對應的函數(好比圖中的三個函數 AddFunc, UpdateFunc 以及 DeleteFunc),並將其按照 key 值的格式放到一個隊列中去,key 值的命名規則就是 "namespace/name",name 就是對應的資源的名字。好比咱們剛纔所說的在 default 的 namespace 中建立一個 foo 類型的資源,那麼它的 key 值就是 "default/example-foo"。Controller 從隊列中拿到一個對象以後,就會去作相應的操做。
下圖就是控制器的工做流程。
首先,經過 kube-apiserver 來推送事件,好比 Added, Updated, Deleted;而後進入到 Controller 的 ListAndWatch() 循環中;ListAndWatch 中有一個先入先出的隊列,在操做的時候就將其 Pop() 出來;而後去找對應的 Handler。Handler 會將其交給對應的函數(好比 Add(), Update(), Delete())。
一個函數通常會有多個 Worker。多個 Worker 的意思是說好比同時有好幾個對象進來,那麼這個 Controller 可能會同時啓動五個、十個這樣的 Worker 來並行地執行,每一個 Worker 能夠處理不一樣的對象實例。
工做完成以後,即把對應的對象建立出來以後,就把這個 key 丟掉,表明已經處理完成。若是處理過程當中有什麼問題,就直接報錯,打出一個事件來,再把這個 key 從新放回到隊列中,下一個 Worker 就能夠接收過來繼續進行相同的處理。
本文的主要內容就到此爲止了,這裏爲你們簡單總結一下:
「阿里巴巴雲原生關注微服務、Serverless、容器、Service Mesh 等技術領域、聚焦雲原生流行技術趨勢、雲原生大規模的落地實踐,作最懂雲原生開發者的技術圈。」