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

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

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

作者 |Nicolas Frnkel

译者 |天道酬勤责编 | 徐威龙

封图|CSDN 下载于视觉中国

在本文中,我们将开始开发自己的Kubernetes控制器。

技术栈可以是Python、NodeJS或Ruby。因为这个博客被命名为为“ Java极客”,因此选择Java是很正常的。

作为一个用例,$ o u / { q |我们将实现sidecar模式:每当一个pod被调度时,sida & uecar pod也会随之被调度。如果将前者删除,则后者也必须删除。

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

选择合适的工具

为了用Java执行REST调用,首先需要生成绑定。有几种方法可以做到这些。最繁琐的操作是手动执行此操作:需要仔细掌握所有6 | | J ~ D G e可能的JSON请求和响应组合,开发相应的Java对象,选择JSONR R ) h V r序列化框架以及HTTP客户端。第二个最佳选择是使用专有代码生成器,例如Swagger(https://swagger.io/)或Apiary(https://apiary.io/)。这就要求API提供程序以一种可能的格式提供模型。不利的一面是,需要使用相关工具。有时,格式或多% o (或少是开放的,例如OpenAPI规范(https://swagger.io/specification/)。在这种情况下,可以从实} K T 2 ^ t b ~ K现该格式的工具G M P r v 3 P =中选择工具。| K $ |最好的情况下,可能已经提供了绑定。

Kubernetes就是这种情况:该项目为各种语言提供了自己的绑定(https://kubernF 3 M h Y I -etes.io/docs/reference/using-api/client-libraries/)。问题在于语言包装器与REST n ! Y K API非常接近k X ` T ^,对于作者来说太熟悉了。例如,这是列出所有名称空间中所S R G有pod的方式:

ApiClientclient=Config.defaultClieV ; x S 5 Vnt();
CoreV1Apicore=newCoreV1Api(cl5 $ k 6 2 x :ient);
V1PodListpods=
core.listPodForAllNamespaces(null,null,null,null,null,null,nulY $ & 0 Q !l,null);

注意:所有的null参数需要传递。

这就是“包装器代码非常接近REST API”的意思。幸运的是,还有另一个选择。Fabric8组织在Github上提供了流C l 5 [ : G畅的Java API。与上述代码等效的代码是:

KubernetesClientcG ) Vlient=newDefaultKubernetesClient();
PodListpods=client.pods().inAnyNamespace().list();
注意:无需传递无用的null参数。

Fabric8o [ = I ] v 2组织在Github上提供了流畅的a H 7 N A G A eJava API:

https:/G p F X/github.com/fabric8io/kubernetes-client)= ` (

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

Fabric8快速概述

简单来说,使用Fabric8的API,所有Kubernetes资源都可以在KubernetesClient实例上使用,例如:

  • client.namespaces()

  • client.services()

  • client.~ B W L snodes()

根据资源的性质,它的作用域可以是一个名称空间,也可以不是:

  • client.pods().3 ~ ` a / _ CinAny$ n ` e BNamespace(): C ] v o i ? #

  • client.pods().inNamespaca u & I d & Re("ns")

此时,可以调用这个动作:

列出所有名称空间中的所有Pod:

client.pods().inAnyNamespace().listF | 7 U  ` ~ =();

o C T ( x i除名称空间ns中的所有pod:

client.pods().delete(client.pods().inNamespav k { 7 Ace("ns").list().getItems());
创建一个名U 2 2为ns的新名称空间:
client.namesQ q T 5 G P _paces()
.createNew()
.withApiVersiw N C 8 @ G _ 3on("v1")
.withNewMetadata()
.withNs 1 ? g came("ns")
.endMetadata()
.doW [ 4ne();

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

实现控制循环

注意,Kubernetes控制器只是一个控制循环,它监视集c J T ! b i 8 o群的状态,并将其与所需状态进行协调。为了能够调度/删除事件,需要使用Observer模式。应用程Y L p j V序将订阅此类事件,当他们发生时,相关回调将被触发。

下图是一个非常简单的API图:F V ) 4 Z 3 ! 7

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

要真正实现一个监视程序,只需执行x # q $ ~以下几B a | V行代码:

pue d R 3blE r  _ h q Y (icclassDummyWatcherimplementsWatcher<Pod>{
@Override
publicvoideventReceived(Actionact- K 2 +ion,Podpod){
switch(action){U N 7 ]
caseADDED://注意1
break;
caseMODIFIED://注意2
break;
caseDELETED://注意3
breaH _ 1 ] B x Jk;
caseERROR://注意4
break;
}
}
@Override
publicvoido! - ~nClose(KubernetesClientExceptioncn u l # F K 9ause){
//s e Q 8注意5
}
}
c8 } f g P u Plient.pods()
.inAnt V g c - ) |yNamespace()
.watch(DummyWatcher());
注意:
  1. 添加新pod时起作用

  2. 修改现有pod时起作用

  3. 删除pod时起作用

  4. 发生错误时起作用

  5. 清理任何资源。如果客户端正确关闭,cause将为null

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

具体细节

现在R * [ v N 2 } I,我们拥有了实现sidecar模式所需的一切。我不会展示全部代码,它可以在GitHub上找到:https://github.com/nfrankel/jvm-controller,但需要重点强调一些关键内容。

1) 标记sidecar

从本质上讲,观察者需要在添加新的pod时添加一个sidecar pJ g t (od,并在移除它时删除它。这种基本方法行不通:如果安u ? 6 P k e d排了sidecar pod,则将触发观察者,并向sidecar添加新的sidecar pod。而且这种情况还会持续下去。因此,标记sidecar pod至关重要。检测到此类pod时,不应触发创建逻辑。

有几种标记sidecar pod的方法:

  • 在sj z & T Z @ jidecar pod的名称后加上H 6 + ` = ^ m t c特定的字符串,例如sidecar

  • 添加如下特定标签:

client.pods()
.inNaO W Xmespace("ns")
.createNew()
.withNewMetadata()
.addToLaw ^ abels("sidecar","true")
.endMetadata()
.done();

2) 连同pod一起移除sidecar

pod应只有一个sidecar。如上所述,应在添加Pod时创建它,而在删除后者时应删除它。

因此,应将对主pod的引用添加到3 R L 1 wsidecar中。这样,当pod被删除时,如果它不X x Z H : S . *是一个sidecar,我们% & _ J n 0 Q e应该找到分配的sidecar并{ n : D .将其删除。

第一种简单的方法是在删除主pod时显式删除sidecar。但是,这是一项_ e G . @ p T $繁重的工作,需要花很多时间。Kubernetes允许将pod的生命周期绑定到另一个Pod的生命周期。然后,删除逻辑由Kubernetes本身处理。这由ownerReference的概念支持。

该API使其易于实现:

client.pods()
.inNameF : Z . 8 [space("ns")
.cj = e xreateNew()
.withNewMetadata()
.addNewOwner0 v c n * ^ TReference()
.withApiVersion("v1")
.withKind("Pod")
.withName(podName)
.w] 2 b 0 7 qithUid(pod.getMetadata().getUid())
.endOwnerReference()
.endMetadata()
.done();
3) 始终保持一个sidecar

添加一个sidecar并不意味着它将永远保持这种方式。例如,可以删除属于部署的pod。部署的目标是重新创建一个pod,以达到所需的, M j h N 4 .副本数J u M A z量。

同样,如果在保留主pod的同时删除3 = l了sidecar,则应使用正确的引用生成} / }一个新的sidecar。

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

结论

} ~ u Z . j f $ F这篇文章中,我们描述了如何在JVM上使用Java语言实h ] . g l u D .现Kubernetes控制器。借助Fabric8的API,实现的操作非常简单。主要问题来自调度/删除逻辑中的极端情况。在本系列的下一篇(也是最后一篇)文章中,我们将最终看到如何部署和运行代码。

这篇文章的完整t A F ` J +源代码可以在Github上以Maven格式找到:

https:/p H g X/github.com/nf; 2 xrankel/jvm-controlleg R i r f ^ 3 c ar

希望这篇文章对你有用,欢迎评论区和我们讨论。

原文:https://blog.frankel.q x X 3 -ch/your-own-kubernetes-cM N n ^ 2 D Yontroller/2/

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

防疫、复工如何并行?天d w E q L D e云数据推出人工智能监测方案!到底如何做到事前预防,而不是事后诸葛亮?本周四晚8点,天云数据Vw b %P陈勇为各位揭晓答案!扫描下方二维码免费报名~

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

今日福利:点击阅读原文,凭优惠码“AIP1510”都可获得价值299元的「2020 AI开发者万人大会」在线直播门票一张。

推荐阅读:为什么要在油气行业中应用 IoT?这 8 个应用场景告诉你 In 7 B C CoT 在油气行业中可以做什么
生产环境使用HBase,你必须知道的最佳实践
Java 14R g E k s p 来了!
字节跳动武汉招聘 2000  人,距离大l ~ 5 1 % S z |厂 Offer,你还差这篇 Java 干货!| 原力计划
数字合约如何将所有权下放?如何使用脚本系统将交易转换为可编3 s #程的智能合约?答案就在这P q 篇文章里!
人生苦# U 8短,不光要用Python,还要在VSCw 1 _ . D qode里用
真香,朕在看@ y l g A j & * Z了!