如何擴充套件Kubernetes API?

danny_2018發表於2022-07-01

Django是一個通用的Web框架,而Kubernetes則是一個容器編排器。顯然,不同的專案根本不應該進行比較。然而,在本系列文章中,我試圖揭開Kubernetes的神秘面紗,並展示它的API是一個非常普通的HTTP API,並且可以以相當熟悉的方式進行擴充套件。

有很多方法可以用自定義功能擴充套件Kubernetes,從編寫kubectl外掛到實現排程器擴充套件。詳細的擴充套件點列表可以在官方文件中找到,但如果有一個基於這種方法的排名,我敢打賭開發自定義控制器或運算子,如果你願意的話,會勝出。

Kubernetes控制器背後的思想很簡單,但很強大——你描述系統的理想狀態,將其持久化到Kubernetes,然後等待控制器完成它們的工作,使叢集的實際狀態足夠接近理想狀態(或報告故障)。

然而,雖然控制器得到了很多媒體的關注,但在我看來,編寫自定義控制器大多數時候應該被視為擴充套件Kubernetes API更廣泛任務的一部分(可能是可選的)。但是要注意到這一點,需要對典型的工作流相當的熟悉。

自定義控制器

雖然Kubernetes社群提供了一個更廣泛、更通用的控制器定義,但在與Kubernetes控制器打交道一年多後,我提出了以下解釋,涵蓋了迄今為止我見過的大多數自定義控制器:

控制器實際上是一個主動協調過程(讀取:無限迴圈),它讀取所需的狀態並相應地更新實際狀態。

然而,一個控制器通常被繫結到單一的Kubernetes資源型別。我們稱它為控制器的主要資源。

控制器偵聽系統事件:最重要的是,建立或修改主資源物件,但也改變其他(次要或擁有)資源、計時器事件,等等。

無論事件的性質如何,總是可以將事件歸因於一個或多個主資源型別的物件。

事件發生後,控制器會從API中逐一讀取相應的主要資源物件,檢查各物件的規範屬性(即所需狀態),應用變更來讓系統更接近於所需狀態,再使用此狀態反過來更新各個物件。

控制器可以將任何資源型別作為其主要資源,包括pods、jobs或services等內建資源。問題是,大多數(如果不是所有的話)內建資源已經有相應的內建控制器。因此,定製控制器通常是為定製資源編寫的,以避免多個控制器更新共享物件的狀態。

但從本質上講,什麼是資源?用Kubernetes自己的話說:

資源是Kubernetes API中的一個端點,它儲存特定型別的API物件集合;例如,內建的Pods資源包含一個Pod物件的集合。

因此,如果資源僅僅是Kubernetes API端點,那麼為資源編寫控制器只是一種將請求處理程式繫結到API端點的奇特方式!

每當有對主要資源端點的建立或修改請求時,(特別是)控制器的邏輯就會被觸發。觸發控制迴圈迭代的主資源型別的例項作為請求引數(物件的規格欄位)和響應狀態(物件的狀態欄位)的資料傳輸物件。

基於控制器的處理程式與更傳統的請求處理程式之間的主要區別在於處理與實際的API請求是非同步發生的。建立或修改Kubernetes物件的API請求(如POST、PUT、PATCH)只是為控制器排程工作(透過記錄意圖),而獲取物件的API請求(GET、WATCH)用於返回處理狀態。

自定義資源

如果向Kubernetes API新增請求處理程式是透過編寫控制器進行的,那麼如何新增新的API端點呢?

在回答這個問題之前,重要的是要理解Kubernetes API中有兩種型別的端點:

第一種型別是服務於Kubernetes物件集合(即持久的Kubernetes實體)的端點,如Pods、ConfigMaps、Services等。絕大多數API端點都屬於這種型別。

第二種基本上是其他所有東西。像/metrics、/logs或/apis這樣的端點是其他型別端點的最突出的例子。這些端點要麼被嵌入到Kubernetes API伺服器中,要麼使用API聚合層實現。

控制器通常使用第一種型別的端點。那麼,如何將服務於使用者定義物件型別的新端點新增到API中呢?

首先,需要編寫CustomResourceDefinition(CRD)。CRD本身是一個描述新的自定義資源的物件。最重要的是,CRD應該包含新資源型別的名稱和版本化物件模式(即欄位)。

然後,需要將CRD提交給叢集。將CRD應用到叢集會建立一個服務於自定義資源型別的新的Kubernetes API端點。就這麼簡單!

自定義資源型別的物件的外觀和行為很像內建的Kubernetes物件,它們受益於常見的API特性(CRUD、欄位驗證、發現等),同時,它們具有解決自定義用例所需的屬性。

自定義資源本身可能很有用。透過註冊一個新的資源,你立即獲得(一些有限的)永續性,開箱即用的欄位驗證,RBAC,等等。然而,大多數情況下,自定義資源的建立伴隨著自定義控制器。

准入鉤子(Webhooks)

回到請求處理……

Kubernetes控制器的超能力歸因於它們的非同步特性,但這也是它們最大的侷限性。對Kubernetes API的建立、修改或刪除物件的請求作為意圖的記錄工作——實際的處理邏輯被延遲到下一次控制迴圈迭代。但是如果需要同步請求處理呢?

這在Kubernetes也是可能的!但為此,你需要介入Kubernetes API伺服器的資源請求處理。

當請求到達API伺服器時,在更改持久化到etcd(或類似的)之前,會經過以下幾個階段:

身份驗證和授權

准入控制

物件模式驗證

驗證許可

上面的大部分(或者全部?)階段都可以用自定義邏輯進行擴充套件!

因此,配置一個許可webhook將使Kubernetes API伺服器在實際持久化它之前,將資源例項(包裝在一個稱為AdmissionReview的信封中)傳送到一個自定義HTTPS端點。

呼叫一個許可webhook端點會阻塞Kubernetes API伺服器的請求處理。准入webhook的實現可以執行任意的驗證邏輯,用非平凡的預設值填充物件的屬性,對物件進行標籤或註釋,甚至修改其他Kubernetes資源或對外部系統進行更改!

一般來說,應該避免webhook處理程式中的副作用。在webhook中,不可能知道物件實際上是會被處理鏈持久化還是拒絕。如果對資源的操作被其中一個檢查拒絕,則需要以某種方式恢復前面步驟所做的任何更改。

因此,webhook是將同步請求處理程式繫結到Kubernetes API端點的一種簡單方法。這就完成了Kubernetes API與任何其他傳統HTTP API在特性上的同一性。

總結

讓我們試著把所有東西都放在一張圖上。下面是Kubernetes API擴充套件工作流的描述:

希望大家現在已經清楚,自定義控制器只是擴充套件Kubernetes API這一更大任務的一部分。

我希望,在以上的解釋之後,你也注意到Kubernetes與我們都熟悉的老式技術沒有什麼不同:

Kubernetes自定義資源只是一種向API新增新的HTTP端點的方法。

Kubernetes自定義控制器是一種將非同步處理程式繫結到API端點的方法。

Kubernetes Admission Webhooks是一種將同步處理程式繫結到相同API端點的方法。

所以,Kubernetes和Django並沒有太大的不同。

不過,認真地說,用熟悉的東西做類比通常能幫助我更快地理解新概念。但是,當僅僅理解是不夠的,需要流利的表達時,練習通常會幫助我將概念內化為真正的概念。然而,這是另一篇文章的主題。請繼續關注!

來自 “ 分散式實驗室 ”, 原文作者:分散式實驗室;原文連結:https://mp.weixin.qq.com/s/Ss2uXk-VwgdOgmSatZ5gEw,如有侵權,請聯絡管理員刪除。

相關文章