天天看點

開箱即用的 Java Kubernetes Operator 運作時

本篇分享的内容難度為“初學者/Beginner”級别,以下是閱讀本文前推薦您了解的背景知識:

  • Java 語言程式設計基礎;
  • 了解過 Kubernetes 平台上的 Operator/Controller 工作機制;

也可以同步參考 Kubernetes 官方部落格内容:

https://kubernetes.io/blog/2019/11/26/develop-a-kubernetes-controller-in-java

圖為何子波和金敏在 KubeCon NA2019 大會分享後的交流

何子波 螞蟻金服技術專家:

_(adohe@github) _Kubernetes 維護者,SIG CLI Co-Chair(包括 Kubectl 及其擴充插件,Kustomize 以及用戶端運作時),同時關注安全容器,多租戶等領域。

金敏 螞蟻金服軟體工程師:

_(yue9944882@github) _Kubernetes SIG API-Machinery 維護者及其子領域 Owner(CRD 服務實作,APIAggregation SDK 套件,控制面流控,OpenAPIv2/3,Java SDK 等),同時也是 OpenAPI 開源生态工具鍊

openapitools.org

 的 Techincal Committee。

本文根據兩位在 KubeCon NA2019 的分享内容整理。本次演講與大家分享螞蟻金服金融科技擴充雲原生 Java 能力到雲的實踐和改造,并将收獲的産出回饋開放給 Kubernetes 社群。

分享概要

在 Kubernetes 平台上開發部署運作 Operator 已經是在 Kubernetes 上拓展開發能力的預設範式。最早是 CoreOS 的工程師們創新提出了 Operator 的開發理念并且在社群收獲了良好的反響,在經過一段時間的波折、打磨和實踐之後,我們今天才看到豐富多樣的 Operator 層出不窮。實際上 Operator 的效力往往要結合 Kubernetes API 的擴充能力才能更好發揮。是以其廣泛傳播反過來錘煉演進了 Kubernetes 上 CustomResourceDefinition 承載第三方 API 模型的能力。水漲船高,這也是社群集中投入人力從 v1.14 開始啟動 Extensibility GA Sprint 小組沖刺 Kubernetes 擴充性建設的推動原因。

圖為何子波和金敏在 KubeCon NA2019 大會現場示範

随着 Operator 的閱聽人越來越多,社群也衍生出了面向 Operator 開發提效的工具鍊項目比如 

operator-sdk

kubebuilder metacontroller

 等等優秀的開源項目。可是這些項目大都是面向 Go 語言研發者的,雖然越來越多的研發者向 Go 靠擾已是事實,但是 Go 語言尚不及其他主流程式設計語言成熟,倒是慢慢鋪開的 Kubernetes 等其他開源項目的工業實踐在“倒逼”Go 語言底層庫的修複和穩固,比如 http2 的底層網絡庫[1]。與此相似的,我們最早内部孵化的 Java 語言的 Operator 運作時架構也是被實際業務“倒逼”出來的,并在 Kubernetes 社群露頭試水之初便收獲了許多回報推動發展直到今天走到全面開放。

你為什麼需要使用 Java 開發 Operator

如果你在猶豫不決是否要使用 Java 開發 Operator 并應用到實際中來,我們從以下幾個方面進行對比看看哪一點是足夠吸引你嘗鮮:

  • 适配存量系統:如果在登陸 Kubernetes 之前你的基礎設施底層系統都是通過 Java 開發的,那麼恭喜你已經有了使用 Java Operator 的天然土壤。反過來把存量系統接口逐個“翻譯”為 Go 語言既消耗大量人力又引出持續同步維護 Go 語言庫的成本。
  • 堆記憶體快照:相比于 Java,Go 語言很難将運作中的程式的記憶體進行完整的快照分析,PProf 相關工具鍊能做的隻是将記憶體的使用概況彙總輸出,雖然也可以幫助分析鎖定出洩漏的對象類型,但是粒度有限。反過來 Java 程式的堆記憶體進行快照分析已經具有成熟的工具鍊支援,研發者通過一份完整的堆快照可以直接鎖定出比如 WorkQueue 中積壓的内容,甚至限流器中逐個 Key 的瞬時狀态,也可以在 Operator 靜默不響應的場景下快速鎖定問題。
  • 性能診斷/線上調試:結合比如 JMX Exporter 等工具鍊的幫助,我們直接将 Java 虛拟機的細節運作狀态以 Prometheus Metrics 的形式收集起來,雖然 Go 程式也可以暴露出其運作時的 Metrics,但是對比後我們發現 Java 的 Metrics 在分析 GC 狀态和堆分布上更加強大。除此之外,Java Operator 的遠端調試更加友善上手。
  • 線程模型:與 Java 顯著不同的是,Go 語言中的 Routine 不具有直接從外部“殺死”的功能,你需要結合 Channel/Context 等模型間接實作。而在 Java 虛拟機上的線程模型有和作業系統類似的生命周期管理,開發者可以白盒的操作幹涉線程的生命周期。這對于某些業務場景是重要的。
  • OOP 範型程式設計接口: Go 語言本身的設計哲學是不認可面向對象程式設計的,盡管好處很多但是在 API 模型繁多的 Kubernetes 項目中,維護者不得己轉向使用代碼生成器批量為這些模型生成大量模版代碼。Java 的優勢之一是範型程式設計,這可以徹底取代代碼生成器的工作,同一套代碼可以自由地适配在各種模型,比如 Pod 到 Service 等等。
  • 第三方研發者庫生态:經過數十年的演進,Java 積累的第三方工具庫遠比 Go 語言豐富的多,至少目前而已可以算得上是一個優勢。

示例代碼速覽

下面兩張代碼片段為你展示了具體開發 Java Operator 所需要的全部工作,相信接觸過 Kubernetes Client-Go 的開發者通過名字大緻了解如何使用了:

(如何構造出一個 Informer 執行個體) 

https://github.com/kubernetes-client/java/blob/master/examples/src/main/java/io/kubernetes/client/examples/InformerExample.java

(如何構造出一個 Operator 執行個體) 

https://github.com/kubernetes-client/java/blob/master/examples/src/main/java/io/kubernetes/client/examples/ControllerExample.java

開發 Java Operator 需要額外注意什麼

僅僅是通過代碼開發 Operator 顯然不是大結局,你還需要注意其他的問題,以下是我們在實際運用的獲得的經驗總結:

  • 嚴謹管理 CRD Yaml 定義:如最開始提到的,當 Java Operator 操作的是自定義資源比如 CRD 時,我們自然需要操作/維護該 CRD 對應的 Java 模型。這首先引入了 CRD Yaml 的良好維護的問題(具體細則這裡暫不贅述),另外還有如何将 CRD Yaml 映射為 Java 模型的問題。關于後者我們既可以手動維護管理,也可以通過代碼生成器将你的 CRD Yaml 一步轉換為嚴絲合縫對應的 Java 模型。Kubernetes 的核心是 API 模型。社群自身對于 API 的變更是作為最高優先級進行稽核,當我們自行拓展管理 API 模型時更應當謹慎細緻。
  • 關注 Operator 的關停步驟:目前 Go 語言的 Operator 是不存在優雅退出的,然而這不代表我們不需要。在 Java 的線程管理模型下我們可以更細粒度地調整 Operator 關停時的行為,比如完整釋放隊列中的任務後再下線。
  • 把 Operator 解耦為獨立部署的元件:開發 Java 程式時開發者往往傾向于将 Operator 聲明為例如 “Spring Bean”并注入到某個 RPC 服務中。但這其實是不推薦的,因為 Operator 的生命周期應該是在其續約“Lease 租期”中斷時退出重新開機,而 RPC 服務的重新開機操作往往成本更高。兩者并不對拍。

未來的拓展/行進路線

除了不斷的将 Client-Go 現有的能力平行移植到 Java 用戶端之外,我們還規劃了以下内容作為未來的行進路線:

  • 大規模叢集下的 Operator 拓展能力;
  • 适配 Kuberentes 社群标準的多叢集的擴充能力;
  • Operator 下的分布式對象/任務追蹤;

結束語

本文介紹了如何快速上手使用 Java 開發 Operator,感興趣的讀者可以根據官方執行個體在本地開發環境體驗。Kubernetes 社群的 Java 用戶端可以發展至今離不開社群的貢獻和回報,也感謝紅帽的 Fabric8 用戶端的協助得以讓開發者收獲更流暢的開發接口體驗。對 Kubernetes 社群的 Java 未來發展有更多想法和建議朋友歡迎在我們的倉庫留下足迹:

https://github.com/kubernetes-client/java

。同時也歡迎緻力于雲原生領域的小夥伴們加入我們,我們一起探索和創新!

[1] 更多上下文參考:

https://github.com/kubernetes/client-go/issues/374

[2] 通過 CRD Yaml 生成 Java 模型參考:

https://github.com/kubernetes-client/java/blob/master/docs/generate-model-from-third-party-resources.md