开箱即用的 Java Kubernetes Operator 运行时

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
简介: 本文介绍了如何快速上手使用 Java 开发 Operator,感兴趣的读者可以根据官方实例在本地开发环境体验。

本篇分享的内容难度为“初学者/Beginner”级别,以下是阅读本文前推荐您了解的背景知识:

  • Java 语言编程基础;
  • 了解过 Kubernetes 平台上的 Operator/Controller 工作机制;

也可以同步参考 Kubernetes 官方博客内容:https://kubernetes.io/blog/2019/11/26/develop-a-kubernetes-controller-in-java

图为何子波和金敏在 KubeCon NA2019 大会分享后的交流

图为何子波和金敏在 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 大会现场演示
图为何子波和金敏在 KubeCon NA2019 大会现场演示

随着 Operator 的受众越来越多,社区也衍生出了面向 Operator 开发提效的工具链项目比如 operator-sdkkubebuildermetacontroller 等等优秀的开源项目。可是这些项目大都是面向 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

构造出一个 Informer  实例

(如何构造出一个 Operator 实例) https://github.com/kubernetes-client/java/blob/master/examples/src/main/java/io/kubernetes/client/examples/ControllerExample.java

如何构造出一个 Operator 实例

开发 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

相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
相关文章
|
2月前
|
Java
使用IDEA创建项目运行我的第一个JAVA文件输出Helloword
本文介绍了如何使用IDEA(IntelliJ IDEA)创建一个新的Java项目,并运行一个简单的Java程序输出"Hello Word"。文章详细展示了创建项目的步骤,包括选择JDK版本、设置项目名称和路径、创建包和类,以及编写和运行代码。最后,还展示了如何通过IDEA的运行功能来执行程序并查看输出结果。
101 4
使用IDEA创建项目运行我的第一个JAVA文件输出Helloword
|
1月前
|
Java
Java关键字 —— super 详细解释!一看就懂 有代码实例运行!
文章详细解释了Java关键字`super`的用途,包括访问父类的成员变量、调用父类的构造方法和方法,并提供了相应的代码实例。
96 5
Java关键字 —— super 详细解释!一看就懂 有代码实例运行!
|
1月前
|
Java Apache Maven
Java百项管理之新闻管理系统 熟悉java语法——大学生作业 有源码!!!可运行!!!
文章提供了使用Apache POI库在Java中创建和读取Excel文件的详细代码示例,包括写入数据到Excel和从Excel读取数据的方法。
56 6
Java百项管理之新闻管理系统 熟悉java语法——大学生作业 有源码!!!可运行!!!
|
2月前
|
Java Linux
java基础(3)安装好JDK后使用javac.exe编译java文件、java.exe运行编译好的类
本文介绍了如何在安装JDK后使用`javac.exe`编译Java文件,以及使用`java.exe`运行编译好的类文件。涵盖了JDK的安装、环境变量配置、编写Java程序、使用命令行编译和运行程序的步骤,并提供了解决中文乱码的方法。
51 2
|
15天前
|
Kubernetes 监控 Cloud Native
|
1月前
|
Java
jvm复习,深入理解java虚拟机一:运行时数据区域
这篇文章深入探讨了Java虚拟机的运行时数据区域,包括程序计数器、Java虚拟机栈、本地方法栈、Java堆、方法区、元空间和运行时常量池,并讨论了它们的作用、特点以及与垃圾回收的关系。
60 19
jvm复习,深入理解java虚拟机一:运行时数据区域
|
25天前
|
存储 SQL 小程序
JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))
这篇文章详细介绍了Java虚拟机(JVM)的运行时数据区域和JVM指令集,包括程序计数器、虚拟机栈、本地方法栈、直接内存、方法区和堆,以及栈帧的组成部分和执行流程。
25 2
JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))
|
1月前
|
分布式计算 大数据 Java
大数据-86 Spark 集群 WordCount 用 Scala & Java 调用Spark 编译并打包上传运行 梦开始的地方
大数据-86 Spark 集群 WordCount 用 Scala & Java 调用Spark 编译并打包上传运行 梦开始的地方
17 1
大数据-86 Spark 集群 WordCount 用 Scala & Java 调用Spark 编译并打包上传运行 梦开始的地方
|
21天前
|
IDE Java 编译器
Java:如何确定编译和运行时类路径是否一致
类路径(Classpath)是JVM用于查找类文件的路径列表,对编译和运行Java程序至关重要。编译时通过`javac -classpath`指定,运行时通过`java -classpath`指定。IDE如Eclipse和IntelliJ IDEA也提供界面管理类路径。确保编译和运行时类路径一致,特别是外部库和项目内部类的路径设置。
|
1月前
|
Kubernetes Docker 容器
容器运行时Containerd k8s
容器运行时Containerd k8s
35 2