从零开始入门 K8s | Kubernetes API 编程利器:Operator 和 Operator Framework

简介: 本文将从实践出发,结合案例来说明,如何借助 Operator 开发框架来扩展 Kubernetes API。内容主要分为三个部分:首先会简单介绍一下 Operator 相关的知识;然后会介绍 Operator 开发框架并结合案例来详细说明整个开发过程;最后会结合案例的工作流程来重新说明 Operator 是如何工作的。

作者  |  夙兴  阿里巴巴高级工程师

本文整理自《CNCF x Alibaba 云原生技术公开课》第 24 讲,点击“阅读原文”直达课程页面。

关注“阿里巴巴云原生”公众号,回复关键词“入门”,即可下载从零入门 K8s 系列文章 PPT。

导读:本文将从实践出发,结合案例来说明,如何借助 Operator 开发框架来扩展 Kubernetes API。内容主要分为三个部分:首先会简单介绍一下 Operator 相关的知识;然后会介绍 Operator 开发框架并结合案例来详细说明整个开发过程;最后会结合案例的工作流程来重新说明 Operator 是如何工作的。

一、operator 概述

基本概念

首先介绍一下本文内容所涉及到的基本概念。

  • CRD (Custom Resource Definition): 允许用户自定义 Kubernetes 资源,是一个类型;
  • CR (Custom Resourse): CRD 的一个具体实例;
  • webhook: 它本质上是一种 HTTP 回调,会注册到 apiserver 上。在 apiserver 特定事件发生时,会查询已注册的 webhook,并把相应的消息转发过去。

按照处理类型的不同,一般可以将其分为两类:一类可能会修改传入对象,称为 mutating webhook;一类则会只读传入对象,称为 validating webhook。

  • 工作队列: controller 的核心组件。它会监控集群内的资源变化,并把相关的对象,包括它的动作与 key,例如 Pod 的一个 Create 动作,作为一个事件存储于该队列中;
  • controller :它会循环地处理上述工作队列,按照各自的逻辑把集群状态向预期状态推动。不同的 controller 处理的类型不同,比如 replicaset controller 关注的是副本数,会处理一些 Pod 相关的事件;
  • operator:operator 是描述、部署和管理 kubernetes 应用的一套机制,从实现上来说,可以将其理解为 CRD 配合可选的 webhook 与 controller 来实现用户业务逻辑,即 operator = CRD + webhook + controller。

常见的 operator 工作模式

1.png

工作流程:

  1. 用户创建一个自定义资源 (CRD);
  2. apiserver 根据自己注册的一个 pass 列表,把该 CRD 的请求转发给 webhook;
  3. webhook 一般会完成该 CRD 的缺省值设定和参数检验。webhook 处理完之后,相应的 CR 会被写入数据库,返回给用户;
  4. 与此同时,controller 会在后台监测该自定义资源,按照业务逻辑,处理与该自定义资源相关联的特殊操作;
  5. 上述处理一般会引起集群内的状态变化,controller 会监测这些关联的变化,把这些变化记录到 CRD 的状态中。

这里是从 High-Level 大概介绍一下,后面会结合案例重新梳理。

二、operator framework 实战

operator framework 概述

在开始之前,首先介绍一下 operator framework。 它实际上给用户提供了 webhook 和 controller 的框架,它的主要意义在于帮助开发者屏蔽了一些通用的底层细节,不需要开发者再去实现消息通知触发、失败重新入队等,只需关注被管理应用的运维逻辑实现即可。

主流的 operator framework 主要有两个:kubebuilderoperator-sdk

两者实际上并没有本质的区别,它们的核心都是使用官方的 controller-tools 和 controller-runtime。不过细节上稍有不同,比如 kubebuilder 有着更为完善的测试与部署以及代码生成的脚手架等;而 operator-sdk 对 ansible operator 这类上层操作的支持更好一些。

kuberbuildere 实战

这里的实战选用的是 kuberbuilder。案例选用的是阿里云对外开放的 kruise 项目下的 SidercarSet。

SidercarSet 的功能就是负责给 Pod 插入 sidecar 容器(也称为辅助容器),例如可以插入一些监控,日志采集来丰富这个 Pod 的功能,然后根据插入的状态、Pod 的状态反过来更新 SidercarSet 以记录这些辅助容器的状态。

Step 1: 初始化

操作:新建一个 gitlab 项目,运行 "kubebuilder init --domain=kruise.io"。

参数解读:domain 指定了后续注册 CRD 对象的 Group 域名。

效果解读:拉取依赖代码库、生成代码框架、生成 Makefile/Dockerfile 等工具文件。

我们来看一下它具体生成的内容_(为了方便演示,实际生成文件做了部分删减):

2.png

具体的内容大家可以在实战的时候自己进行详细的确认。

Step 2: 创建 API

操作:运行 "kubebuilder create api --group apps --version v1alpha1 --kind SidecarSet --namespace=false"
实际上不仅会创建 API,也就是 CRD,还会生成 Controller 的框架。

参数解读:- group 加上之前的 domian 即此 CRD 的 Group: apps.kruise.io;

  • version 一般分三种,按社区标准:

    • v1alpha1: 此 api 不稳定,CRD 可能废弃、字段可能随时调整,不要依赖;
    • v1beta1: api 已稳定,会保证向后兼容,特性可能会调整;
    • v1: api 和特性都已稳定;
  • kind: 此 CRD 的类型,类似于社区原生的 Service 的概念;
  • namespaced: 此 CRD 是全局唯一还是 namespace 唯一,类似 node 和 Pod。

它的参数基本可以分为两类。group, version, kind 基本上对应了 CRD 元信息的三个重要组成部分。这里给出了一些常见的标准,大家实际使用的时候可以参考一下。namespaced 则用于指定我们刚刚创建的 CRD 时全局唯一的(如 node)还是 namespace 唯一的(如 Pod)。这里用了 false,即指定 SidecarSet 为全局唯一的。

效果解读

生成了 CRD 和 controller 的框架,后面需要手工填充代码。

实际结果如下图所示:

3.png

我们重点关注是图中蓝色字体部分。sidecarset_types.go 就是定义 CRD 的地方,需要我们填充。sidecarset_controller.go 则用于定义 controller,同样需要进行填充。

Step 3: 填充 CRD

1. 生成的 CRD 位于 "pkg/apis/apps/v1alpha1/sidecarset_types.go",通常需要进行如下两个操作

(1) 调整注释

code generator 依赖注释生成代码,因此有时需要调整注释。以下列出了本次实战中 SidecarSet 需要调整的注释:

+genclient:nonNamespaced: 生成非 namespace 对象;
+kubebuilder:subresource:status: 生成 status 子资源;
+kubebuilder:printcolumn:name="MATCHED",type='integer',JSONPath=".status.matchedPods",description="xxx": kubectl get sidecarset: 后续展示相关。

(2) 填充字段

填充字段是令用户的 CRD 实际生效、实际有意义的重要部分。

  • SidecarSetSpec: 填充 CRD 描述信息;
  • SidecarSetStatus: 填充 CRD 状态信息。

 2. 填充完运行 make 重新生成代码即可

需要注意的是,研发人员无需参与 CRD 的 grpc 接口、编解码等 controller 的底层实现。

实际的填充如下图所示:

4.png

SidecarSet 的功能是给 Pod 注入 Sidecar,为了完成该功能,我们在 SidecarSetSpec(左图) 定义了两个主要信息:一个是用于选择哪些 Pod 需要被注入的 Selector;一个是定义 Sidecar 容器的 Containers。

在 SidecarSetStatus(右图)中定义了状态信息,MatchedPods 反映的是该 SidecarSet 实际匹配了多少 Pod,UpdatedPods 反映的是已经注入了多少,ReadyPods 反映的则是有多少 Pod 已经正常工作了。

完整的内容可以参考该文档

Step 4: 生成 webhook 框架

1. 生成 mutating webhook,运行

"kubebuilder alpha webhook --group apps --version v1alpha1 --kind SidecarSet --type=mutating --operations=create"

"kubebuilder alpha webhook --group core --version v1 --kind Pod --type=mutating --operations=create"

2. 生成 validating webhook,运行

"kubebuilder alpha webhook --group apps --version v1alpha1 --kind SidecarSet --type=validating --operations=create,update"

参数解读

  • group/kind 描述需要处理的资源对象;
  • type 描述需要生成哪种类型的框架;
  • operations 描述关注资源对象的哪些操作。

效果解读

  • 生成了 webhook 框架,后面需要手工填充代码

实际生成结果如下图所示:

5.png

我们执行了三条命令,分别生成了三个不同的需要填充的 handler 中(上图蓝色字体部分)。这里先不提,在下一步填充操作中再对其详细讲解。

Step 5: 填充 webhook

生成的 webhook handler 分别位于:

    • pkg/webhook/default_server/sidecarset/mutating/xxx_handler.go
    • pkg/webhook/default_server/sidecarset/validating/xxx_handler.go
    • pkg/webhook/default_server/pod/mutating/xxx_handler.go

需要改写、填充的一般包括以下两个部分: 

  • 是否需要注入 K8s client:取决于除了传入的 CRD 以外是否还需要其它资源。在本实战中,不仅要关注 SidecarSet,同时还要注入 Pod,因此需要注入 K8s client;
  • 填充 webhook 的关键方法:即 mutatingSidecarSetFn 或 validatingSidecarSetFn。由于待操作资源对象指针已经传入,因此直接调整该对象属性即可完成 hook 的工作。

我们来看一下实际的填充结果。

6.png

因为第四步我们定义了三个:sidecarset mutating、sidecarset mutaing、pod mutating。

先来看上图左侧的 sidecarset mutating,首先是 setDefaultSidecarSet 把默认值设置好,这也是 mutaing 最常做的事情。

上图右侧 validating 也是非常的标准,也是对 SidecarSet 一些字段进行校验。

关于 pod mutaing 这里没有做展示,这里面有些不同,这里面的 mutaingSidecarSetFn 不是进行默认值设置,而是获取 setDefaultSidecarSet 的数值,然后注入到 Pod 里面。

Step 6: 填充 controller

生成的 controller 框架位于 pkg/controller/sidecarset/sidecarset_controller.go。主要有三点需要进行修改: 

  • 修改权限注释。框架会自动生成形如 //+kuberbuilder:rbac;groups=apps,resources=deployments/status,verbs=get;update;path 的注释,我们可以按照自己的需求修改,该注释最终会生成 rbac 规则;

 

  • 增加入队逻辑。缺省的代码框架会填充 CRD 本身的入队逻辑(如 SidecarSet 对象的增删改都会加入工作队列),如果需要关联资源对象的触发机制(如 SidecarSet 也需关注 Pod 的变化),则需手工新增它的入队逻辑;

 

  • 填充业务逻辑。修改 Reconcile 函数,循环处理工作队列。Reconcile 函数主要完成「根据 Spec 完成业务逻辑」和「将业务逻辑结果反馈回 status」两部分。需要注意的是,如果 Reconcile 函数出错返回 err,默认会重新入队。

我们来看一下 SidecarSet 的 Controller 的填充结果:

7.png

addPod 中先取回该 Pod 对应的 SidecarSet 并将其加入队列以便 Reconcile 进行处理。

Reconcile 将 SidercarSet 取出之后,根据 Selector 选择匹配的 Pod,最后根据 Pod 当前的状态信息计算出集群的状态,然后回填到 CRD 的状态中。

三、SidecarSet 的工作流程

最后我们再来重新梳理一下 SidecarSet 的工作流程以便我们理解 operator 是如何工作的。

8.png

  1. 用户创建一个 SidecarSet;
  2. webhook 收到该 SidecarSet 之后,会进行缺省值设置和配置项校验。这两个操作完成之后,会完成真正的入库,并返回给用户;
  3. 用户创建一个 Pod;
  4. webhook 会拿回对应的 SidecarSet,并从中取出 container 注入 Pod 中,因此 Pod 在实际入库时就已带有了刚刚的 sidecar;
  5. controller 在后台不停地轮询,查看集群的状态变化。第 4 步中的注入会触发 SidecarSet 的入队,controller 就会令 SidecarSet 的 UpdatedPods 加 1。

以上就是 SidecarSet 前期一个简单的功能实现。

这里我们再补充一个问题。一般的 webhook 由 controller 来完成业务逻辑、状态更新,但这个不是一定的,两者之一可以不是必须的。在以上的示例中就是由 webhook 完成主要的业务逻辑,无需 controller 的参与。

四、本文总结

本文的主要内容就到此为止了,这里为大家简单总结一下:

  • Operator 是 CRD 配合 可选的 webhook 和 controller,在 Kubernetes 体系下扩展用户业务逻辑的一套机制;
  • kubebuilder 是社区认可度很高的一种官方、标准化 Operator 框架;
  • 按照上文实战步骤,填充用户自定义代码,就可以很方便的实现一个 Operator。

直播海报.png

阿里巴巴云原生关注微服务、Serverless、容器、Service Mesh 等技术领域、聚焦云原生流行技术趋势、云原生大规模的落地实践,做最懂云原生开发者的技术圈。”

相关实践学习
深入解析Docker容器化技术
Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。Docker是世界领先的软件容器平台。开发人员利用Docker可以消除协作编码时“在我的机器上可正常工作”的问题。运维人员利用Docker可以在隔离容器中并行运行和管理应用,获得更好的计算密度。企业利用Docker可以构建敏捷的软件交付管道,以更快的速度、更高的安全性和可靠的信誉为Linux和Windows Server应用发布新功能。 在本套课程中,我们将全面的讲解Docker技术栈,从环境安装到容器、镜像操作以及生产环境如何部署开发的微服务应用。本课程由黑马程序员提供。     相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
相关文章
|
JSON 安全 API
电商API入门问答:开发者必知的10个基础问题
本文详解电商API的10个基础知识,涵盖定义、用途、认证、安全等内容,帮助开发者快速入门并提升开发效率。
|
缓存 监控 安全
电商API集成入门:从零开始搭建高效接口
在数字化电商时代,API集成成为企业提升效率、实现系统互联的关键。本文从零开始,逐步讲解如何搭建高效、可靠的电商API接口,适合初学者学习。内容涵盖API基础、认证安全、请求处理、性能优化等核心步骤,并提供Python代码示例与数学公式辅助理解。通过实践,读者可掌握构建优质电商API的技巧,提升用户体验与系统性能。
|
JSON 算法 API
一文掌握 1688 商品详情 API 接口:从入门到实战
1688是国内领先的综合电商批发平台,提供海量商品资源。其商品详情API助力开发者与企业获取商品的详细信息(如属性、价格、库存等),广泛应用于电商数据分析、比价系统及采购场景。API支持GET/POST请求,需传入通用参数(app_key、timestamp等)与业务参数(如product_id)。返回JSON格式数据,包含商品标题、价格、图片链接等详情,提升业务效率与决策精准度。
4676 6
|
JSON API 开发工具
电商API接口入门指南
本文介绍了API的基础知识及其在电商领域的实际应用。首先,阐释了API的概念、运作机制及参数与返回值的作用,帮助读者理解如何通过API实现软件间的交互。接着,以获取电商商品列表为例,详细讲解了从选择平台、引入SDK到编写代码调用API的全流程。示例代码采用Python语言,利用requests库发送请求并解析JSON数据,为开发者提供了清晰的实践指导。
|
11月前
|
Cloud Native 算法 API
Python API接口实战指南:从入门到精通
🌟蒋星熠Jaxonic,技术宇宙的星际旅人。深耕API开发,以Python为舟,探索RESTful、GraphQL等接口奥秘。擅长requests、aiohttp实战,专注性能优化与架构设计,用代码连接万物,谱写极客诗篇。
1992 1
Python API接口实战指南:从入门到精通
|
数据挖掘 API 开发者
京东商品详情 API 接口全攻略:从入门到精通
京东商品详情API接口是京东开放平台为开发者提供的服务,用于获取商品详细信息。通过调用接口,开发者可获得商品属性、价格、库存、促销信息等数据,适用于电商应用、价格比较工具及数据分析平台等场景。支持GET/POST请求方式,参数包括API版本、密钥等。示例代码展示了如何使用Python的requests库调用该接口,并获取JSON格式的返回数据,包含商品基本信息、价格、库存和用户评价等内容。
556 16
|
存储 安全 API
亚马逊SP-API入门:海外电商接口调用与国内平台的差异化
亚马逊 SP-API 与国内电商 API 在技术架构、安全机制及开发流程上差异显著。本文对比京东、淘宝等平台,分析接口设计、地域适配、权限管理等核心差异,并结合实战经验提供开发建议,助力开发者高效接入 SP-API,实现全球电商业务拓展。
|
11月前
|
人工智能 算法 调度
阿里云ACK托管集群Pro版共享GPU调度操作指南
本文介绍在阿里云ACK托管集群Pro版中,如何通过共享GPU调度实现显存与算力的精细化分配,涵盖前提条件、使用限制、节点池配置及任务部署全流程,提升GPU资源利用率,适用于AI训练与推理场景。
815 1
|
11月前
|
弹性计算 监控 调度
ACK One 注册集群云端节点池升级:IDC 集群一键接入云端 GPU 算力,接入效率提升 80%
ACK One注册集群节点池实现“一键接入”,免去手动编写脚本与GPU驱动安装,支持自动扩缩容与多场景调度,大幅提升K8s集群管理效率。
567 89
|
资源调度 Kubernetes 调度
从单集群到多集群的快速无损转型:ACK One 多集群应用分发
ACK One 的多集群应用分发,可以最小成本地结合您已有的单集群 CD 系统,无需对原先应用资源 YAML 进行修改,即可快速构建成多集群的 CD 系统,并同时获得强大的多集群资源调度和分发的能力。
1168 9

相关产品

  • 容器服务Kubernetes版
  • 推荐镜像

    更多