用 Java 開發自己的 Kubernetes 控制器,想試試嗎?

用 Java 開發自己的 Kubernetes 控制器,想試試嗎?

用 Java 開發自己的 Kubernetes 控制器,想試試嗎?

作者 | Nicolas Fränkel

譯者 | 天道酬勤,責編 | 徐威龍

封圖 | CSDN 下載於視覺中國

在本文中,我們將開始開發自己的Kubernetes控制器。

技術棧可以是Python、NodeJS或Ruby。因為這個博客被命名為為“ Java極客”,因此選擇Java是很正常的。

作為一個用例,我們將實現sidecar模式:每當一個pod被調度時,sidecar pod也會隨之被調度。如果將前者刪除,則後者也必須刪除。

用 Java 开发自己的 Kubernetes 控制器,想试试吗?

選擇合適的工具

為了用Java執行REST調用,首先需要生成綁定。有幾種方法可以做到這些。最繁瑣的操作是手動執行此操作:需要仔細掌握所有可能的JSON請求和響應組合,開發相應的Java對象,選擇JSON序列化框架以及HTTP客戶端。第二個最佳選擇是使用專有代碼生成器,例如Swagger(https://swagger.io/)或Apiary(https://apiary.io/)。這就要求API提供程序以一種可能的格式提供模型。不利的一面是,需要使用相關工具。有時,格式或多或少是開放的,例如OpenAPI規範(https://swagger.io/specification/)。在這種情況下,可以從實現該格式的工具中選擇工具。在最好的情況下,可能已經提供了綁定。

Kubernetes就是這種情況:該項目為各種語言提供了自己的綁定(https://kubernetes.io/docs/reference/using-api/client-libraries/)。問題在於語言包裝器與REST API非常接近,對於作者來說太熟悉了。例如,這是列出所有名稱空間中所有pod的方式:

ApiClient client = Config.defaultClient;

CoreV1Api core = new CoreV1Api(client);

V1PodList pods =

core.listPodForAllNamespaces(, , , , , , , );

注意:所有的參數需要傳遞。

這就是“包裝器代碼非常接近REST API”的意思。幸運的是,還有另一個選擇。Fabric8組織在Github上提供了流暢的Java API。與上述代碼等效的代碼是:

KubernetesClient client = new DefaultKubernetesClient;

PodList pods = client.pods.inAnyNamespace.list;

注意:無需傳遞無用的參數。

Fabric8組織在Github上提供了流暢的Java API:

https://github.com/fabric8io/kubernetes-client)

用 Java 开发自己的 Kubernetes 控制器,想试试吗?

Fabric8快速概述

簡單來說,使用Fabric8的API,所有Kubernetes資源都可以在KubernetesClient實例上使用,例如:

  • client.namespaces

  • client.services

  • client.nodes

根據資源的性質,它的作用域可以是一個名稱空間,也可以不是:

  • client.pods.inAnyNamespace

  • client.pods.inNamespace("ns")

此時,可以調用這個動作:

列出所有名稱空間中的所有Pod:

client.pods.inAnyNamespace.list;

刪除名稱空間ns中的所有pod:

client.pods.delete(client.pods.inNamespace("ns").list.getItems);

創建一個名為ns的新名稱空間:

client.namespaces
.createNew
.withApiVersion("v1")
.withNewMetadata
.withName("ns")
.endMetadata
.done;

用 Java 开发自己的 Kubernetes 控制器,想试试吗?

實現控制循環

注意,Kubernetes控制器只是一個控制循環,它監視集群的狀態,並將其與所需狀態進行協調。為了能夠調度/刪除事件,需要使用Observer模式。應用程序將訂閱此類事件,當他們發生時,相關回調將被觸發。

下圖是一個非常簡單的API圖:

用 Java 开发自己的 Kubernetes 控制器,想试试吗?

要真正實現一個監視程序,只需執行以下幾行代碼:

 

public class DummyWatcher implements Watcher {

@Override

public void eventReceived(Action action, Pod pod) {

switch (action) {

case ADDED: //注意1

break;

case MODIFIED: //注意2

break;

case DELETED: //注意3

break;

case ERROR: //注意4

break;

}

}

@Override

public void onClose(KubernetesClientException cause) {

//注意5

}

}

client.pods

.inAnyNamespace

.watch(DummyWatcher);

注意:

  1. 添加新pod時起作用

  2. 修改現有pod時起作用

  3. 刪除pod時起作用

  4. 發生錯誤時起作用

  5. 清理任何資源。如果客戶端正確關閉,cause將為

用 Java 开发自己的 Kubernetes 控制器,想试试吗?

具體細節

現在,我們擁有了實現sidecar模式所需的一切。我不會展示全部代碼,它可以在GitHub上找到:https://github.com/nfrankel/jvm-controller,但需要重點強調一些關鍵內容。

1) 標記sidecar

從本質上講,觀察者需要在添加新的pod時添加一個sidecar pod,並在移除它時刪除它。這種基本方法行不通:如果安排了sidecar pod,則將觸發觀察者,並向sidecar添加新的sidecar pod。而且這種情況還會持續下去。因此,標記sidecar pod至關重要。檢測到此類pod時,不應觸發創建邏輯。

有幾種標記sidecar pod的方法:

  • 在sidecar pod的名稱後加上特定的字符串,例如sidecar

  • 添加如下特定標籤:

client.pods

.inNamespace("ns")

.createNew

.withNewMetadata

.addToLabels("sidecar", "true")

.endMetadata

.done;

2) 連同pod一起移除sidecar

pod應只有一個sidecar。如上所述,應在添加Pod時創建它,而在刪除後者時應刪除它。

因此,應將對主pod的引用添加到sidecar中。這樣,當pod被刪除時,如果它不是一個sidecar,我們應該找到分配的sidecar並將其刪除。

第一種簡單的方法是在刪除主pod時顯式刪除sidecar。但是,這是一項繁重的工作,需要花很多時間。Kubernetes允許將pod的生命週期綁定到另一個Pod的生命週期。然後,刪除邏輯由Kubernetes本身處理。這由ownerReference的概念支持。

該API使其易於實現:

client.pods

.inNamespace("ns")

.createNew

.withNewMetadata

.addNewOwnerReference

.withApiVersion("v1")

.withKind("Pod")

.withName(podName)

.withUid(pod.getMetadata.getUid)

.endOwnerReference

.endMetadata

.done;

3) 始終保持一個sidecar

添加一個sidecar並不意味著它將永遠保持這種方式。例如,可以刪除屬於部署的pod。部署的目標是重新創建一個pod,以達到所需的副本數量。

同樣,如果在保留主pod的同時刪除了sidecar,則應使用正確的引用生成一個新的sidecar。

用 Java 开发自己的 Kubernetes 控制器,想试试吗?

結論

在這篇文章中,我們描述瞭如何在JVM上使用Java語言實現Kubernetes控制器。藉助Fabric8的API,實現的操作非常簡單。主要問題來自調度/刪除邏輯中的極端情況。在本系列的下一篇(也是最後一篇)文章中,我們將最終看到如何部署和運行代碼。

這篇文章的完整源代碼可以在Github上以Maven格式找到:

https://github.com/nfrankel/jvm-controller

希望這篇文章對你有用,歡迎評論區和我們討論。

原文:https://blog.frankel.ch/your-own-kubernetes-controller/2/


分享到:


相關文章: