热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

如何用clientgo拓展Kubernetes的API【转载】

本文是转载信息如下,如有侵权,立删,原作者信息章骏 |才云科技云开源软件工程师毕业于武汉大学软件工程专业,之前就职于百度,担任算法策略研发工程师,主要负责搜索相关性的指标。加入才云

本文是转载信息如下,如有侵权,立删,原作者信息

章骏 | 才云科技云开源软件工程师
毕业于武汉大学软件工程专业,之前就职于百度,担任算法策略研发工程师,主要负责搜索相关性的指标。加入才云科技后,现主要负责负载均衡和灰度发布的工作。
 

今天给大家介绍一下如何使用 client-go 来拓展 Kubernetes API,写一个 Kubernetes 的控制器。

client-go 是 Kubernetes 官方推出的一个库,方便我们来调用 Kubernetes 的 RESTful API。

控制流
Overview首先,控制器需要与 kubernetes apiserver 进行通讯,则需要一个 client, 这个 client 需要有以下的信息:

  • apiserver 的地址以及连接 apiserver 的认证信息,如用户名密码或者 token。
  • kubernetes 的 API resource 的 group 和 version,以及结构体的定义。
  • 一个 serializer 来控制序列化与反序列化 apiserver 的结果。

然后你就可以用这个 client 去 apiserver list/watch 特定的类型的资源。
一般是建议使用 client-go 中提供的 informer 来 watch 资源的变更而不是轮询 apiserver,因为 informer 的方式性能更好。
Controller

下面这张图很好的展示了一个 controller 的工作流程和原理,典型的 controller 一般会有一个或者多个 informer 来跟踪 resource,把最新的状态反映到本地的 cache 中。配图:来自徐超大神分享

如何用 client-go 拓展 Kubernetes 的 API 【转载】

 

1. Controller 使用 informer 来 list/watch apiserver,然后将资源存储于本地的 cache 中。
2. 如果 informer 监听到了资源的变化(创建/更新/删除),就会调用事先注册的 ResourceEventHandler 回调函数。
3. 在 ResourceEventHandler 回调函数中,其实只是做了一些很简单的过滤,然后将关心变更的 Object 放到 workqueue 里面。

4. Controller 从 workqueue 里面取出 Object,启动一个 worker 来执行自己的业务逻辑,业务逻辑通常是计算目前集群的状态和用户希望达到的状态有多大的区别,然后孜孜不倦地让 apiserver 将状态演化到用户希望达到的状态,比如为 deployment 创建新的 pods,或者是扩容/缩容 deployment。
5. 在worker中就可以使用 lister 来获取 resource,而不用频繁的访问 apiserver,因为 apiserver 中 resource 的变更都会反映到本地的 cache 中。

Clients


下面介绍 client-go 中的三种 client。
ClientsetClientset 是我们最常用的 client,你可以在它里面找到 kubernetes 目前所有原生资源对应的 client。 获取方式一般是,指定 group 然后指定特定的 version,然后根据 resource 名字来获取到对应的 client。
Dynamic ClientDynamic client 是一种动态的 client,它能同时处理 kubernetes 所有的资源。并且同时,它也不同于 clientset,dynamic client 返回的对象是一个 map[string]interface{},如果一个 controller 中需要控制所有的 API,可以使用dynamic client,目前它被用在了 garbage collector 和 namespace controller。
RESTClientRESTClient 是 clientset 和 dynamic client 的基础,前面这两个 client 本质上都是 RESTClient,它提供了一些 RESTful 的函数如 Get(),Put(),Post(),Delete()。由 Codec 来提供序列化和反序列化的功能。
如何选择 Client 的类型呢?
如果你的 Controller 只是需要控制 Kubernetes 原生的资源,如 Pods,Nodes,Deployments等,那么 clientset 就够用了。
如果你需要使用 ThirdPartyResource 来拓展 Kubernetes 的 API,那么需要使用 Dynamic Client 或 RESTClient。
需要注意的是,Dynamic Client 目前只支持 JSON 的序列化和反序列化。

在1.7+版本需要将 ThirdPartyResource 迁移到 CustomResourceDefinition

Informer
最佳实践

  • 等待所有的 cache 同步完成: 这是为了避免生成大量无用的资源,比如 replica set controller 需要watch replica sets 和 pods, 在 cache 还没有同步完之前,controller 可能为一个 replica set 创建了大量重复的 pods,因为这个时候 controller 觉得目前还没有任何的 pods。
  • 修改 resource 对象前先 deepcopy 一份: 在 Informer 这个模型中,我们的 resource 一般是从本地 cache 中取出的,而本地的 cache 对于用户来说应该是 read-only 的,因为它可能是与其他的 informer 共享的,如果你直接修改 cache 中的对象,可能会引起读写的竞争。
  • 处理 DeletedFinalStateUnknown 类型对象: 当你的收到一个删除事件时,这个对象有可能不是你想要的类型,即它可能是一个 DeletedFinalStateUnknown,你需要单独处理它。
  • 注意 informer 的 resync 行为, informer 会定期从 apiserver resync 资源,这时候会收到大量重复的更新事件,这个事件有一个特点就是更新的 Object 的 ResourceVersion 是一样的,将这种不必要的更新过滤掉。
  • 在创建事件中注意 Object 已经被删除的情况: 在 Controller 重启的过程中,可能会有一些对象被删除了,重启后,Controller 会收到这些已删除对象的创建事件,请把这些对象正确地删除。
  • SharedInformer: 建议使用 SharedInformer, 它会在多个 Informer ***享一个本地 cache,这里有一 个 factory 来方便你编写一个新的 Informer。

Factory:在 client-go 中提供了一个 SharedInformerFactory 来简化 informer 的构建,具体代码在:https://github.com/kubernetes/client-go/blob/v3.0.0/informers/factory.go#L54
Lister
Lister 是用来帮助我们访问本地 cache 的一个组件。

Workqueue
Workqueue 是一个简单的 queue 提供了以下的特性:

  • 公平性:每个item 按顺序处理。
  • 严格性:一个 item 不会被并发地多次处理,而且一个相同的 item 被多次加入 queue 的话也只会处理一次。
  • 支持多个生产者和消费者:它允许一个正在被处理的 item 再次加入队列。

我们建议使用 RateLimitingQueue,它相比普通的 workqueue 多了以下的功能: 

  • 限流:可以限制一个 item 被 reenqueued 的次数。
  • 防止 hot loop:它保证了一个 item 被 reenqueued 后,不会马上被处理。

Workqueue helper:这里有一个 workqueue 的封装,来简化 queue 的操作,代码在以下位置:https://github.com/caicloud/loadbalancer-controller/blob/master/pkg/util/controller/helper.go
控制流总结
我们来总结一个控制器的整体工作流程。
1. 创建一个控制器

  • 为控制器创建 workqueue
  • 创建 informer, 为 informer 添加 callback 函数,创建 lister

2. 启动控制器

  • 启动 informer
  • 等待本地 cache sync 完成后, 启动 workers

3. 当收到变更事件后,执行 callback 

  • 等待事件触发
  • 从事件中获取变更的 Object
  • 做一些必要的检查
  • 生成 object key,一般是 namespace/name 的形式
  • 将 key 放入 workqueue 中

4. worker loop

  • 等待从 workqueue 中获取到 item,一般为 object key
  • 用 object key 通过 lister 从本地 cache 中获取到真正的 object 对象
  • 做一些检查
  • 执行真正的业务逻辑
  • 处理下一个 item

到这里已经讲完了一个完整的 Kubernetes 的 Controller 的构建过程。但是还想要多啰嗦几句关于 kubernetes 的设计原则和 API 习俗,它们是指导我们写出更加可靠的 Controller 的白皮书。
设计原则

  • 功能设计基于 level_based,这意味系统应该在给定的 desired state 和 current/observed state 情况下也能正确运行,不管这中间有多少更新的信息被丢失了。Edge-triggered 只能用来进行优化(应该有一个类似于 CAP 的理论去指导我们权衡应该轮询还是使用事件驱动的方式去控制我们的流程,在高性能,可靠性和简单些三者之间选其二)。
  • 假定我们的系统是一个开放的环境:应该不断的去验证系统假设,优雅地接受外部的事件和修改。比如用户可以随意地删除正在被 replica set 管理的 pods,而 replica set 发现了之后只是简单的重新创建一个新的pod 而已。
  • 不要为 object 建立大而全的状态机,从而把系统的行为和状态机的变迁关联起来。
  • 不要假设所有的组件都能正常运行,任何组件都有可能出错或者拒绝你的请求。etcd 可能会拒绝写入,kubelet 可能会拒绝 pod, scheduler 可能会拒绝调度,尽量进行重试或者有别的解决方案。
  • 系统组件能够自愈:比如说 cache 需要定期的进行同步,这样如果有一些 object 被错误的修改或者存储了, 删除的事件被丢失等问题能够在人类发现之前被自动修复。
  • 优雅地进行降级和熔断,优先满足最重要的功能而忽略一些无关紧要的小错误。

Kubernetes API 习俗 
Spec and status

  • Spec 表示系统希望到达的状态,Status 表示系统目前观测到的状态。
  • PUT 和 POST 的请求中应该把 Status 段的数据忽略掉,Status 只能由系统组件来修改。
  • 有一些对象可能跟 Spec 和 Status 模型相去甚远,可以吧 Spec 改成更加适合的名字。
  • 如果对象符合 Spec 和 Status 的标准的话,那么除了 type,object metadata 之外不应该有其他***的字段。
  • Status 中 phase 已经是 deprecated。因为 pahse 本质上是状态机的枚举类型,它不太符合 Kubernetes 系统设计原则, 并且阻碍系统发展,因为每当你需要往里面加一个新的 pahse 的时候你总是很难做到向后兼容性,建议使用 Condition 来代替。

Primitive types

  • 避免使用浮点数,永远不要在 Spec 中使用它们,浮点数不好规范化,在不同的语言和计算机体系结构中有 不同的精度和表示。
  • 在 Javascript 和其他的一部分语言中,所有的数字都会被转换成 float,所以数字超过了一定的大小最好使 用 string。
  • 不要使用 unsigned integers,因为不同的语言和库对它的支持不一样。
  • 不要使用枚举类型,建立一个 string 的别名类型。
  • API 中所有的 integer 都必须明确使用 Go(int32, int64), 不要使用 int,在32位和64位的操作系统中他们的位数不一样。
  • 谨慎地使用 bool 类型的字段,很多时候刚开始做 API 的时候是 true or false,但是随着系统的扩张,它可能 有多个可选值,多为未来打算。
  • 对于可选的字段,使用指针来表示,比如 *string *int32 , 这样就可以用 nil 来判断这个值是否设置了, 因为 Go 语言中string int 这些类型都有零值,你无法判断他们是没被设置还是被设置了零值。

总结
为 Kubernetes 拓展一个功能,实现一个 controller 是简单的。 但是设计一个系统,抽象出其中的设计哲学,更加值得我们学习和深思。
下面这个项目可以视为 controller 的一个例子:https://github.com/caicloud/loadbalancer-controller
References

  • Client-go:https://github.com/kubernetes/client-go/tree/master/examples
  • Kubernetes controller:https://github.com/kubernetes/kubernetes/tree/master/pkg/controller
  • Ingress controller task queue:https://github.com/kubernetes/ingress/tree/master/core/pkg/task
  • Use client go to extend Kubernetes API — Xu Chao:https://my.oschina.net/caicloud/blog/829365
  • Loadbalacner-controller:https://github.com/caicloud/loadbalancer-controller

推荐阅读
  • Web开发框架概览:Java与JavaScript技术及框架综述
    Web开发涉及服务器端和客户端的协同工作。在服务器端,Java是一种优秀的编程语言,适用于构建各种功能模块,如通过Servlet实现特定服务。客户端则主要依赖HTML进行内容展示,同时借助JavaScript增强交互性和动态效果。此外,现代Web开发还广泛使用各种框架和库,如Spring Boot、React和Vue.js,以提高开发效率和应用性能。 ... [详细]
  • 在本文中,我们将为 HelloWorld 项目添加视图组件,以确保控制器返回的视图路径能够正确映射到指定页面。这一步骤将为后续的测试和开发奠定基础。首先,我们将介绍如何配置视图解析器,以便 SpringMVC 能够识别并渲染相应的视图文件。 ... [详细]
  • ZeroMQ在云计算环境下的高效消息传递库第四章学习心得
    本章节深入探讨了ZeroMQ在云计算环境中的高效消息传递机制,涵盖客户端请求-响应模式、最近最少使用(LRU)队列、心跳检测、面向服务的队列、基于磁盘的离线队列以及主从备份服务等关键技术。此外,还介绍了无中间件的请求-响应架构,强调了这些技术在提升系统性能和可靠性方面的应用价值。个人理解方面,ZeroMQ通过这些机制有效解决了分布式系统中常见的通信延迟和数据一致性问题。 ... [详细]
  • 本文介绍了 Go 语言中的高性能、可扩展、轻量级 Web 框架 Echo。Echo 框架简单易用,仅需几行代码即可启动一个高性能 HTTP 服务。 ... [详细]
  • 非计算机专业的朋友如何拿下多个Offer
    大家好,我是归辰。秋招结束后,我已顺利入职,并应公子龙的邀请,分享一些秋招面试的心得体会,希望能帮助到学弟学妹们,让他们在未来的面试中更加顺利。 ... [详细]
  • 本文详细介绍了Java代码分层的基本概念和常见分层模式,特别是MVC模式。同时探讨了不同项目需求下的分层策略,帮助读者更好地理解和应用Java分层思想。 ... [详细]
  • 在软件开发过程中,经常需要将多个项目或模块进行集成和调试,尤其是当项目依赖于第三方开源库(如Cordova、CocoaPods)时。本文介绍了如何在Xcode中高效地进行多项目联合调试,分享了一些实用的技巧和最佳实践,帮助开发者解决常见的调试难题,提高开发效率。 ... [详细]
  • 如何在PHP中准确获取服务器IP地址?
    如何在PHP中准确获取服务器IP地址? ... [详细]
  • Java Socket 关键参数详解与优化建议
    Java Socket 的 API 虽然被广泛使用,但其关键参数的用途却鲜为人知。本文详细解析了 Java Socket 中的重要参数,如 backlog 参数,它用于控制服务器等待连接请求的队列长度。此外,还探讨了其他参数如 SO_TIMEOUT、SO_REUSEADDR 等的配置方法及其对性能的影响,并提供了优化建议,帮助开发者提升网络通信的稳定性和效率。 ... [详细]
  • 优化后的标题:深入探讨网关安全:将微服务升级为OAuth2资源服务器的最佳实践
    本文深入探讨了如何将微服务升级为OAuth2资源服务器,以订单服务为例,详细介绍了在POM文件中添加 `spring-cloud-starter-oauth2` 依赖,并配置Spring Security以实现对微服务的保护。通过这一过程,不仅增强了系统的安全性,还提高了资源访问的可控性和灵活性。文章还讨论了最佳实践,包括如何配置OAuth2客户端和资源服务器,以及如何处理常见的安全问题和错误。 ... [详细]
  • 在Java分层设计模式中,典型的三层架构(3-tier application)将业务应用细分为表现层(UI)、业务逻辑层(BLL)和数据访问层(DAL)。这种分层结构不仅有助于提高代码的可维护性和可扩展性,还能有效分离关注点,使各层职责更加明确。通过合理的设计和实现,三层架构能够显著提升系统的整体性能和稳定性。 ... [详细]
  • Nginx不仅是一款轻量级的高性能Web服务器,还具备出色的负载均衡和反向代理功能。它支持复杂的正则匹配规则、动静内容分离以及灵活的URL重写功能,使得配置和管理更加便捷高效。此外,Nginx提供了多种负载均衡算法,如轮询、加权轮询、最少连接数等,以满足不同应用场景的需求。 ... [详细]
  • 2019年后蚂蚁集团与拼多多面试经验详述与深度剖析
    2019年后蚂蚁集团与拼多多面试经验详述与深度剖析 ... [详细]
  • 本文深入探讨了 Spring Cloud 微服务架构中 Gateway 组件的应用,详细介绍了其在实现高效请求路由与过滤方面的关键作用。文章首先从基本配置入手,逐步讲解了如何通过静态路由和动态路由实现灵活的服务访问控制。此外,还特别介绍了如何配置 Gateway 以自动从 Nacos 服务注册中心拉取服务列表,进一步提升系统的可维护性和扩展性。 ... [详细]
  • IIS 7及7.5版本中应用程序池的最佳配置策略与实践
    在IIS 7及7.5版本中,优化应用程序池的配置是提升Web站点性能的关键步骤。具体操作包括:首先定位到目标Web站点的应用程序池,然后通过“应用程序池”菜单找到对应的池,右键选择“高级设置”。在一般优化方案中,建议调整以下几个关键参数:1. **基本设置**: - **队列长度**:默认值为1000,可根据实际需求调整队列长度,以提高处理请求的能力。此外,还可以进一步优化其他参数,如处理器使用限制、回收策略等,以确保应用程序池的高效运行。这些优化措施有助于提升系统的稳定性和响应速度。 ... [详细]
author-avatar
努力学习的PHP程序员
什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有