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

2020 年 3 月 27 日 CSDN

作者 | Nicolas Fränkel

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

封图 | CSDN 下载于视觉中国

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

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

作为一个用例,我们将实现sidecar模式:每当一个pod被调度时,sidecar pod也会随之被调度。如果将前者删除,则后者也必须删除。


选择合适的工具

 

为了用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(nullnullnullnullnullnullnullnull);  

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

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

  
  
    

KubernetesClient client = new DefaultKubernetesClient();
PodList pods = client.pods().inAnyNamespace().list();    

注意:无需传递无用的null参数。

Fabric8组织在Github上提供了流畅的Java API:

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


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();

实现控制循环


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

下图是一个非常简单的API图:       

要真正实现一个监视程序,只需执行以下几行代码:

  
  
    

public class DummyWatcher implements Watcher<Pod{

  @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将为null


具体细节

 

现在,我们拥有了实现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。

 

结论

 

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

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

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

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

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

【End】

推荐阅读 
支撑千万规模类别分类技术,百度飞桨定义工业级深度学习框架
清华学霸组团的工业 AIoT 创企再获数千万融资:玩家应推动在边缘 AI 芯片上跑算法
生物学的机器学习:使用K-Means和PCA进行基因组序列分析 COVID-19接下来如何突变?

字节跳动武汉招聘 2000 人,距离大厂 Offer,你还差这篇 Java 干货!| 原力计划

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

人人都能读懂的「以太坊2.0分片设计」

你点的每一个在看,我认真当成了喜欢


点击阅读原文,快快参与吧!

登录查看更多
0

相关内容

PODS会议是一个领先的国际论坛,数据库研究人员、从业人员、开发人员和用户可以探讨前沿思想和成果,并交流技术、工具和经验。会议包括一个引人入胜的技术程序,其中包括研究和工业讲座,教程,演示和重点讲习班。它还举办海报会议,以了解创新技术,与公司和发行商会面的工业展览,以及由领先公司的代表参加的行业职业小组。 官网地址:http://dblp.uni-trier.de/db/conf/pods/
【实用书】Python爬虫Web抓取数据,第二版,306页pdf
专知会员服务
115+阅读 · 2020年5月10日
【新书】Java企业微服务,Enterprise Java Microservices,272页pdf
【书籍推荐】简洁的Python编程(Clean Python),附274页pdf
专知会员服务
173+阅读 · 2020年1月1日
【干货】大数据入门指南:Hadoop、Hive、Spark、 Storm等
专知会员服务
94+阅读 · 2019年12月4日
机器学习相关资源(框架、库、软件)大列表
专知会员服务
38+阅读 · 2019年10月9日
在K8S上运行Kafka合适吗?会遇到哪些陷阱?
DBAplus社群
9+阅读 · 2019年9月4日
用Now轻松部署无服务器Node应用程序
前端之巅
16+阅读 · 2019年6月19日
手把手教你用Python做一个哄女友神器,小白可上手
网易智能菌
5+阅读 · 2019年6月15日
浅谈 Kubernetes 在生产环境中的架构
DevOps时代
11+阅读 · 2019年5月8日
使用 C# 和 Blazor 进行全栈开发
DotNet
6+阅读 · 2019年4月15日
去哪儿网开源DNS管理系统OpenDnsdb
运维帮
21+阅读 · 2019年1月22日
.NET Core 环境下构建强大且易用的规则引擎
Python 杠上 Java、C/C++,赢面有几成?
CSDN
6+阅读 · 2018年4月12日
Continual Unsupervised Representation Learning
Arxiv
7+阅读 · 2019年10月31日
VrR-VG: Refocusing Visually-Relevant Relationships
Arxiv
6+阅读 · 2019年8月26日
Arxiv
5+阅读 · 2018年6月12日
Arxiv
3+阅读 · 2018年3月2日
VIP会员
相关资讯
在K8S上运行Kafka合适吗?会遇到哪些陷阱?
DBAplus社群
9+阅读 · 2019年9月4日
用Now轻松部署无服务器Node应用程序
前端之巅
16+阅读 · 2019年6月19日
手把手教你用Python做一个哄女友神器,小白可上手
网易智能菌
5+阅读 · 2019年6月15日
浅谈 Kubernetes 在生产环境中的架构
DevOps时代
11+阅读 · 2019年5月8日
使用 C# 和 Blazor 进行全栈开发
DotNet
6+阅读 · 2019年4月15日
去哪儿网开源DNS管理系统OpenDnsdb
运维帮
21+阅读 · 2019年1月22日
.NET Core 环境下构建强大且易用的规则引擎
Python 杠上 Java、C/C++,赢面有几成?
CSDN
6+阅读 · 2018年4月12日
Top
微信扫码咨询专知VIP会员