前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >如何构建 Kubernetes CRD Controller

如何构建 Kubernetes CRD Controller

作者头像
CS实验室
发布2021-03-22 12:39:07
1.9K0
发布2021-03-22 12:39:07
举报
文章被收录于专栏:CS实验室

前一篇文章(《如何使用 CRD 拓展 Kubernetes 集群》)通过一个 Demo 讲解 CRD 是什么,以及可以提供什么能力,本文继续基于这个 Demo(https://github.com/Coderhypo/KubeService ),来讲解一下如何构建一个 CRD Controller。

CRD Controller

对于 CRD(CustomResourceDefinition)本身来说,你把它理解为只是一个 OpenApi 的 Schema 一点也不过分,因为这也是它唯一的能力和作用,而对于广义的说法:“利用 CRD 实现了 xx 功能”,真正承担功能实现的,其实说的是 CRD Controller。

Kubernetes 本身就自带了一堆 Controller,Master 节点上的三大核心组件之一:Controller Manager,其实就是一堆 Controller 的集合。

Controller Manger 里有不少 Controller 和我们要实现的 CRD Controller 本质上做的事其实是一样,就是对特定资源进行管理。

而且 Kubernetes 中不同的 Controller 间的通讯方式也非常有意思,以通过 Deployment 创建 Pod 举例:

用户通过 Kubectl 创建 Deployment,APIServer 会对该请求进行权限、准入认证,然后将 Deployment 的资源存储到 ETCD 中,因为 Kubernetes 通过 ETCD 实现了 List-Watch 机制,因此对 Deployment 相关事件感兴趣的 Deployment Controller 会受到资源的 ADD 事件并处理,即为该 Deployment 创建 RS。

RS 创建请求在被 APIServer 接收之后,RS 的 ADD 事件将被发布,因此 ReplicaSet Controller 将会接收到该事件,并进行后续处理:即创建 Pod。

因此可以看到,得益于 Kubernetes 基于事件的工作方式,创建受 Deployment 管理的 Pod 这个动作,Deployment Controller 和 ReplicaSet Controller 都参与执行,但是这两个 Controller 之间并没有直接通讯。

也正是因为其基于事件的工作方式,我们可以自定义 Controller 来处理感兴趣的事件,包括但不局限于 CR 的创建、修改等。

Kubebuilder 和 Operator-SDK

对于 CRD Controller 的构建,有几个主流的工具,一个是 coreOS 开源的 Operator-SDK(https://github.com/operator-framework/operator-sdk ),另一个是 K8s 兴趣小组维护的 Kubebuilder(https://github.com/kubernetes-sigs/kubebuilder )。

Operator-SDK 是 Operator 框架的一部分,Operator 社区比较成熟而且活跃,甚至还有自己的 Hub(https://operatorhub.io/ ) 来让大家探索、分享有趣的 Operator。

Kubebuilder 与其说是个 SDK 不如说是一个代码生成器,通过符合格式的注释和数据结构来生成一个可运行的 Controller。在使用下来最大的感觉是基础设施还不是很完善,比如文档,在写这个 Demo 很多场景还是靠翻代码才找到怎么解决。

Kubebuilder quick start

可能得益于 Kubebuilder 偏代码生成器,所以使用 Kubebuilder 从零到一创建一个 Controller 是非常简单,想必会有很多文章或 topic 会以 “x 分钟创建 CRD Controller” 为题吧。

官方入门文档可见:https://book.kubebuilder.io/quick-start.html

创建项目

首先通过 Kubebuilder init 命令初始化项目, --domain flag arg 来指定 api group。

代码语言:javascript
复制
kubebuilder init --domain o0w0o.cn --owner "Hypo"

当项目创建好之后,会提醒你是否下载依赖,然后你会发现大半个 Kubernetes 的代码已经在你 GOPATH 里了 ┑( ̄Д  ̄)┍。

创建 Api

当项目创建好就可以创建 api:

代码语言:javascript
复制
kubebuilder create api --group app --version v1 --kind App
kubebuilder create api --group app --version v1 --kind MicroService

创建 api 的同时你会发现 Kubebuilder 会帮你创建一些目录和源代码文件:

  1. pkg.apis 里面包含了资源 AppMicroService 的默认数据结构
  2. pkg.controller 里面 AppMicroService 的两个默认 Controller

resource type

Kubebuilder 已经帮你创建和默认的结构:

代码语言:javascript
复制
// MicroService is the Schema for the microservices API
// +k8s:openapi-gen=true
type MicroService struct {
    metav1.TypeMeta   `json:",inline"`
    metav1.ObjectMeta `json:"metadata,omitempty"`

    Spec   MicroServiceSpec   `json:"spec,omitempty"`
    Status MicroServiceStatus `json:"status,omitempty"`
}

你要做的只是拓展,以 MicroService 举例:

代码语言:javascript
复制
type Canary struct {
    // +kubebuilder:validation:Maximum=100
    // +kubebuilder:validation:Minimum=1
    Weight int `json:"weight"`

    // +optional
    CanaryIngressName string `json:"canaryIngressName,omitempty"`

    // +optional
    Header string `json:"header,omitempty"`

    // +optional
    HeaderValue string `json:"headerValue,omitempty"`

    // +optional
    Cookie string `json:"cookie,omitempty"`
}

type DeployVersion struct {
    Name     string                `json:"name"`
    Template appsv1.DeploymentSpec `json:"template"`

    // +optional
    ServiceName string `json:"serviceName,omitempty"`

    // +optional
    Canary *Canary `json:"canary,omitempty"`
}

type ServiceLoadBalance struct {
    Name string             `json:"name"`
    Spec corev1.ServiceSpec `json:"spec"`
}

type IngressLoadBalance struct {
    Name string                        `json:"name"`
    Spec extensionsv1beta1.IngressSpec `json:"spec"`
}

type LoadBalance struct {
    // +optional
    Service *ServiceLoadBalance `json:"service,omitempty"`
    // +optional
    Ingress *IngressLoadBalance `json:"ingress,omitempty"`
}

// MicroServiceSpec defines the desired state of MicroService
type MicroServiceSpec struct {
    // +optional
    LoadBalance        *LoadBalance    `json:"loadBalance,omitempty"`
    Versions           []DeployVersion `json:"versions"`
    CurrentVersionName string          `json:"currentVersionName"`
}

完整的代码见:https://github.com/Coderhypo/KubeService/blob/master/pkg/apis/app/v1/microservice_types.go

controller 逻辑

如果之前没有了解过 Kubernetes 控制器的代码,可能会对默认生成的 Controller 很奇怪,默认 MicroService Controller 名为 ReconcileMicroService,其只有一个主要方法就是:

代码语言:javascript
复制
func (r *ReconcileMicroService) Reconcile(request reconcile.Request) (reconcile.Result, error)

在使这个 Controller Work 之前,需要 pkg.controller.microservice.micriservice_controller.go中的 add 方法中注册要关注的事件,当任何感兴趣的事件发生时, Reconcile 便会被调用,这个函数的职责,就像 Deployment Controller 的 syncHandler 一样,当有事件发生时,去比对当前资源的状态和预期的状态是否一致,如果不一致,就去矫正。

比如 MicroService 通过 Deployment 管理版本, Reconcile 就要判断每个版本的 Deployment 是否存在,是否符合预期,不过不存在,就去创建,如果不符合,就去纠正。

具体 ReconcileMicroService 代码可见:https://github.com/Coderhypo/KubeService/blob/master/pkg/controller/microservice/microservice_controller.go

运行

当 CR 的结构已经确定和 Controller 代码完成之后,便可以尝试试运行一下。Kubebuilder 可以通过本地 kubeconfig 配置的集群试运行(对于快速创建一个开发集群推荐 minikube)。

首先记得在 main.go 中的 init 方法中添加 schema:

代码语言:javascript
复制
func init() {
    _ = corev1.AddToScheme(scheme)
    _ = appsv1.AddToScheme(scheme)
    _ = extensionsv1beta1.AddToScheme(scheme)
    _ = apis.AddToScheme(scheme)
    // +kubebuilder:scaffold:scheme
}

然后使 Kubebuilder 重新生成代码:

代码语言:javascript
复制
make

然后将 config/crd 下的 CRD yaml 应用到当前集群:

代码语言:javascript
复制
make install

在本地运行 CRD Controller(直接执行 main 函数也可以):

代码语言:javascript
复制
make run
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-08-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 CS实验室 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • CRD Controller
  • Kubebuilder 和 Operator-SDK
  • Kubebuilder quick start
    • 创建项目
      • 创建 Api
        • resource type
          • controller 逻辑
            • 运行
            相关产品与服务
            容器服务
            腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档