基于operator sdk轻松编写一个k8s自定义资源管理应用

本文涉及的产品
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
简介: operator 是一种 kubernetes 的扩展形式,可以帮助用户以 Kubernetes 的声明式 API 风格自定义来管理应用及服务,operator已经成为分布式应用在k8s集群部署的事实标准了,在云原生时代系统想迁移到k8s集群上编写operator应用是必不可少的能力,这里介绍用 CoreOS 的 operator framework 工具如何快速构建一个 operator 应用。

在说 operator 之前让我们先来了解下什么是 CRD (自定义资源描述,Custom Resource Definition)。

CRD

在 Kubernetes 中我们使用的 Deployment, DamenSet,StatefulSet, Service,Ingress, ConfigMap, Secret 这些都是资源,而对这些资源的创建、更新、删除的动作都会被成为为事件(Event),Kubernetes 的 Controller Manager 负责事件监听,并触发相应的动作来满足期望(Spec),这种方式也就是声明式,即用户只需要关心应用程序的最终状态。当我们在使用中发现现有的这些资源不能满足我们的需求的时候,Kubernetes 提供了自定义资源(Custom Resource)和 opertor 为应用程序提供基于 kuberntes 扩展。
CRD 则是对自定义资源的描述(Custom Resource Definition),也就是介绍这个资源有什么属性呀,这些属性的类型是什么,结构是怎样的这类。

我们看一个postgres-operator的CRD:

apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: postgresqls.acid.zalan.do
  labels:
    app.kubernetes.io/name: postgres-operator
  annotations:
    "helm.sh/hook": crd-install
spec:
  group: acid.zalan.do
  names:
    kind: postgresql
    listKind: postgresqlList
    plural: postgresqls
    singular: postgresql
    shortNames:
    - pg
  additionalPrinterColumns:
  - name: Team
    type: string
    description: Team responsible for Postgres CLuster
    JSONPath: .spec.teamId
  - name: Version
    type: string
    description: PostgreSQL version
    JSONPath: .spec.postgresql.version
  - name: Pods
    type: integer
    description: Number of Pods per Postgres cluster
    JSONPath: .spec.numberOfInstances
  - name: Volume
    type: string
    description: Size of the bound volume
    JSONPath: .spec.volume.size
...

从上面的 CRD 文件可以看到 CRD 主要包括apiVersionkindmetadataspec四个部分。其中最关键的是apiVersionkindapiVersion表示资源所属组织和版本,apiVersion一般由APIGourpVersion组成,这里的 APIGourp 是apiextensions.k8s.io,Version 是v1beta1,相关信息可以通过kubectl api-resoures查看。kind 表示资源类型,这里是CustomResourceDefinition,表示是一个自定义的资源描述。

operator是什么

CoreOS 在 2016 年底提出了 Operator 的概念,当时的一段官方定义如下:

An Operator represents human operational knowledge in software, to reliably manage an application.

operator 是一种 kubernetes 的扩展形式,利用自定义资源对象(Custom Resource)来管理应用和组件,允许用户以 Kubernetes 的声明式 API 风格来管理应用及服务。operator 定义了一组在 Kubernetes 集群中打包和部署复杂业务应用的方法,operator主要是为解决特定应用或服务关于如何运行、部署及出现问题时如何处理提供的一种特定的自定义方式。比如:

  • 按需部署应用服务(总不能用一大堆configmap来管理吧,也会很混乱~w(゚Д゚)w)
  • 实现应用状态的备份和还原,完成版本升级,比如
  • 数据库 schema 或额外的配置设置的改动
  • 为分布式应用进行master选举,例如etcd,或者master-slave架构的mysql集群。

operator SDK

operator SDK —— operator framework,是 CoreOS 公司开发和维护的用于快速创建 operator 的工具,可以帮助我们快速构建 operator 应用,类似的工具还有:

  • KUDO (Kubernetes 通用声明式 Operator)
  • kubebuilder,kubernetes SIG 在维护的一个项目
  • Metacontroller,可与 Webhook 结合使用,以实现自己的功能。

如果希望查看 Operator 生态,可以上 operatorhub.io ,也可以将自己创建的应用发布上去。

operator 安装

安装 operator sdk:

export RELEASE_VERSION=v0.13.0
curl -LO https://github.com/operator-framework/operator-sdk/releases/download/${RELEASE_VERSION}/operator-sdk-${RELEASE_VERSION}-x86_64-linux-gnu
chmod +x operator-sdk-${RELEASE_VERSION}-x86_64-linux-gnu && sudo mkdir -p /usr/local/bin/ && sudo cp operator-sdk-${RELEASE_VERSION}-x86_64-linux-gnu /usr/local/bin/operator-sdk && rm operator-sdk-${RELEASE_VERSION}-x86_64-linux-gnu

基于模板创建项目

用operator sdk 创建项目模板,这里用官方提供的一个sample-controller的模板:

operator-sdk new <controller-name> --repo github.com/kubernetes/sample-controller

项目结构目录创建完成,如下:

$ operator-sdk new test-controller --repo github.com/kubernetes/sample-controller
$ tree
.
├── build
│   ├── bin
│   │   ├── entrypoint
│   │   └── user_setup
│   └── Dockerfile
├── cmd
│   └── manager
│       └── main.go
├── deploy
│   ├── operator.yaml
│   ├── role_binding.yaml
│   ├── role.yaml
│   └── service_account.yaml
├── go.mod
├── go.sum
├── pkg
│   ├── apis
│   │   └── apis.go
│   └── controller
│       └── controller.go
├── tools.go
└── version
    └── version.go

创建CRD

创建CRD:

operator-sdk add api --api-version=<api的版本> --kind=<类型名称>

创建CRD后,多出来了文件夹:

$ operator-sdk add api --api-version=test.k8s.realibox.com/v1 --kind=Realibox

INFO[0000] Generating api version test.k8s.realibox.com/v1 for kind Realibox. 
INFO[0000] Created pkg/apis/test/group.go               
INFO[0002] Created pkg/apis/test/v1/realibox_types.go   
INFO[0002] Created pkg/apis/addtoscheme_test_v1.go      
INFO[0002] Created pkg/apis/test/v1/register.go         
INFO[0002] Created pkg/apis/test/v1/doc.go              
INFO[0002] Created deploy/crds/test.k8s.realibox.com_v1_realibox_cr.yaml 
INFO[0004] Created deploy/crds/test.k8s.realibox.com_realiboxes_crd.yaml 
INFO[0004] Running deepcopy code-generation for Custom Resource group versions: [test:[v1], ] 
INFO[0014] Code-generation complete.                    
INFO[0014] Running CRD generation for Custom Resource group versions: [test:[v1], ] 
INFO[0014] Created deploy/crds/test.k8s.realibox.com_realiboxes_crd.yaml 
INFO[0014] CRD generation complete.                     
INFO[0014] API generation complete.      

$ tree
...
├── pkg
│   ├── apis
│   │   ├── addtoscheme_test_v1.go
│   │   ├── apis.go
│   │   └── test
│   │       ├── group.go
│   │       └── v1
│   │           ├── doc.go
│   │           ├── realibox_types.go
│   │           ├── register.go
│   │           └── zz_generated.deepcopy.go
│   └── controller
│       └── controller.go
...

test 文件夹下面放得就是 CRD,我们通过pkg/apis/test/v1/*_types.go文件定义我们的CRD结构,主要是SpecStatus

vim pkg/apis/test/v1/realibox_types.go
...
// RealiboxSpec defines the desired state of Realibox
type RealiboxSpec struct {
        // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
        // Important: Run "operator-sdk generate k8s" to regenerate code after modifying this file
        // Add custom validation using kubebuilder tags: https://book-v1.book.kubebuilder.io/beyond_basics/generating_crd.html
}

type RealiboxStatus struct {
    // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
    // Important: Run "operator-sdk generate k8s" to regenerate code after modifying this file
    // Add custom validation using kubebuilder tags: https://book-v1.book.kubebuilder.io/beyond_basics/generating_crd.html
}
...

这里我们只改Spec字段,将RealiboxSpec结构体改为:

type RealiboxSpec struct {
    Domain string `json:"domain,omitempty"`
    OSS string `json:"oss,omitempty"`
    Size    string `json:"size,omitempty"`
}

更新CRD文件:

operator-sdk generate k8s
operator-sdk generate crds

CRD本质是一种k8s的资源,因此要使用crd,需要在K8s集群上创建CRD:

kubectl apply -f deploy/crds/test.k8s.realibox.com_realiboxes_crd.yaml

查看集群CRD:

$ kubectl get crd
NAME                                      CREATED AT
clusterauthtokens.cluster.cattle.io       2020-08-29T06:41:42Z
clusteruserattributes.cluster.cattle.io   2020-08-29T06:41:42Z
realiboxes.test.k8s.realibox.com          2020-08-29T07:57:44Z

编写controller

创建好 CRD 后,我们可以编写 controller 了,先创建一个 controller 监听和核对新创建的realibox资源类型:

命令行说明:

operator-sdk add controller --api-version=<api的版本> --kind=<类型名称>

运行结果:

$ operator-sdk add controller --api-version=test.k8s.realibox.com/v1 --kind=Realibox

$ tree
...
├── pkg
│   ├── apis
│   │   ├── addtoscheme_test_v1.go
│   │   ├── apis.go
│   │   └── test
│   │       ├── group.go
│   │       └── v1
│   │           ├── doc.go
│   │           ├── realibox_types.go
│   │           ├── register.go
│   │           └── zz_generated.deepcopy.go
│   └── controller
│       ├── add_realibox.go
│       ├── controller.go
│       └── realibox
│           └── realibox_controller.go
...

pkg/controller目录下生成了controller代码,在pkg/controller/realibox/realibox_controller.go编写代码逻辑即可,在这里,我将CR信息在创建pod之前打印到日志里:

...
func (r *ReconcileRealibox) Reconcile(request reconcile.Request) (reconcile.Result, error) {
  ...
    reqLogger.Info(fmt.Sprintf("Domain: %v created, oss info:%v, size: %v",instance.Spec.Domain,instance.Spec.OSS, instance.Spec.Size))
    // Define a new Pod object
    pod := newPodForCR(instance)

    ...
}
...

下面就可以运行 controller 了。

注:如果希望对集群进行更多地复杂操作,可以使用client-go来操作 Kubernetes 的资源,client-go是一个对 Kubernetes API 进行封装的库,由 Kubernetes 官方提供,还是十分好用的。

运行 controller

运行controller有两种方法,可以在本地直接运行controller,也可以打包到k8s运行。

本地运行controller

在本地运行controller直接go run就可以了:

export WATCH_NAMESPACE=default
go run cmd/manager/main.go

注意:不管是在本地运行还是远程运行都需要先在集群中创建CRD

运行好后我们可以编写一个CR资源,提交到k8s集群中:

apiVersion: test.k8s.realibox.com/v1
kind: Realibox
metadata:
  name: example-realibox
spec:
  domain: "realibox.com"
  oss: "aliyun.com"
  size: "3Gb"

通过kubectl提交到集群,可以看到controller程序已经收到CR注册内容打印出来了:

...
{"level":"info","ts":1598689291.273161,"logger":"controller_realibox","msg":"Domain: realibox.com created, oss info:aliyun.com, size: 3Gb","Request.Namespace":"default","Request.Name":"example-realibox"}
{"level":"info","ts":1598689291.2731829,"logger":"controller_realibox","msg":"Skip reconcile: Pod already exists","Request.Namespace":"default","Request.Name":"example-realibox","Pod.Namespace":"default","Pod.Name":"example-realibox-pod"}
...

打包提交到k8s运行

如果我们controller完成,我们可以将其打包放到k8s上运行:

打包镜像

这里用的阿里云镜像仓库:

operator-sdk build registry.cn-shenzhen.aliyuncs.com/shikanon/realibox-operator-test:v0.1  --image-builder docker

将打包好镜像上传镜像仓库:

docker login --username=shikanon@foxmail.com registry.cn-shenzhen.aliyuncs.com
docker push registry.cn-shenzhen.aliyuncs.com/shikanon/realibox-operator-test:v0.1

更改deploy/operator.yaml里面的镜像名称:

...
    spec:
      serviceAccountName: test-controller
      containers:
        - name: test-controller
          # Replace this with the built image name
          image: registry.cn-shenzhen.aliyuncs.com/shikanon/realibox-operator-test:v0.1
          command:
          - test-controller
          imagePullPolicy: Always
...

将deploy下的YAML文件提交到集群中

kubectl apply -f deploy/service_account.yaml
kubectl apply -f deploy/role.yaml
kubectl apply -f deploy/role_binding.yaml
kubectl apply -f deploy/operator.yaml

查看状态,确保全部成功:

$ kubectl get all
NAME                                   READY   STATUS    RESTARTS   AGE
pod/test-controller-75bf886d9c-whjdn   1/1     Running   0          23s

NAME                              TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)             AGE
service/kubernetes                ClusterIP   10.43.0.1       <none>        443/TCP             123m
service/test-controller-metrics   ClusterIP   10.43.100.251   <none>        8383/TCP,8686/TCP   12s

NAME                              READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/test-controller   1/1     1            1           23s

NAME                                         DESIRED   CURRENT   READY   AGE
replicaset.apps/test-controller-75bf886d9c   1         1         1       23s

提交CR

这和单机运行是一样的,编写一个CR提交到集群,然后可以通过controller的pod日志查看到变化:

$ kubectl logs -f test-controller-75bf886d9c-whjdn
...
{"level":"info","ts":1598690827.2699623,"logger":"controller_realibox","msg":"Reconciling Realibox","Request.Namespace":"default","Request.Name":"example-realibox"}
{"level":"info","ts":1598690827.270006,"logger":"controller_realibox","msg":"Domain: realibox.com created, oss info:aliyun.com, size: 3Gb","Request.Namespace":"default","Request.Name":"example-realibox"}
{"level":"info","ts":1598690827.2700245,"logger":"controller_realibox","msg":"Skip reconcile: Pod already exists","Request.Namespace":"default","Request.Name":"example-realibox","Pod.Namespace":"default","Pod.Name":"example-realibox-pod"}
...

参考文献

相关实践学习
容器服务Serverless版ACK Serverless 快速入门:在线魔方应用部署和监控
通过本实验,您将了解到容器服务Serverless版ACK Serverless 的基本产品能力,即可以实现快速部署一个在线魔方应用,并借助阿里云容器服务成熟的产品生态,实现在线应用的企业级监控,提升应用稳定性。
云原生实践公开课
课程大纲 开篇:如何学习并实践云原生技术 基础篇: 5 步上手 Kubernetes 进阶篇:生产环境下的 K8s 实践 相关的阿里云产品:容器服务&nbsp;ACK 容器服务&nbsp;Kubernetes&nbsp;版(简称&nbsp;ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情:&nbsp;https://www.aliyun.com/product/kubernetes
目录
相关文章
|
24天前
|
Kubernetes 开发者 Docker
构建高效微服务架构:Docker与Kubernetes的协同应用
【5月更文挑战第30天】 在当今软件开发领域,微服务架构已成为实现系统模块化、提升可维护性及扩展性的关键策略。本文深入探讨了如何通过Docker容器化技术和Kubernetes集群管理,共同构建一个既高效又可靠的后端微服务环境。我们将剖析Docker和Kubernetes的核心功能,以及它们如何相辅相成,支撑起现代化的云原生应用程序部署和管理。文章还将提供具体实践案例,帮助开发者理解将理论应用于实际开发过程中的步骤和考虑因素。
|
26天前
|
Kubernetes Cloud Native 开发者
构建高效的云原生应用:Docker与Kubernetes的完美搭档
【5月更文挑战第29天】 在现代软件开发领域,"云原生"这一术语已经成为高效、可扩展和弹性的代名词。本文将深入探讨如何通过Docker容器化技术和Kubernetes集群管理工具实现云原生应用的构建和管理。我们将剖析Docker的核心原理,揭示其轻量级和易于部署的特点,并进一步探索Kubernetes如何为这些容器提供编排,保证应用的高可用性与自动扩缩容。文章不仅讨论了二者的技术细节,还提供了实践案例,帮助开发者理解并运用这些技术构建和维护自己的云原生应用。
|
1月前
|
存储 Kubernetes API
使用Kubernetes管理容器化应用的深度解析
【5月更文挑战第20天】本文深度解析Kubernetes在管理容器化应用中的作用。Kubernetes是一个开源平台,用于自动化部署、扩展和管理容器,提供API对象描述应用资源并维持其期望状态。核心组件包括负责集群控制的Master节点(含API Server、Scheduler、Controller Manager和Etcd)和运行Pod的工作节点Node(含Kubelet、Kube-Proxy和容器运行时环境)。
|
13天前
|
编解码 运维 Serverless
Serverless 应用引擎产品使用合集之如何使用SDK
阿里云Serverless 应用引擎(SAE)提供了完整的微服务应用生命周期管理能力,包括应用部署、服务治理、开发运维、资源管理等功能,并通过扩展功能支持多环境管理、API Gateway、事件驱动等高级应用场景,帮助企业快速构建、部署、运维和扩展微服务架构,实现Serverless化的应用部署与运维模式。以下是对SAE产品使用合集的概述,包括应用管理、服务治理、开发运维、资源管理等方面。
|
13天前
|
Kubernetes 前端开发 Serverless
Serverless 应用引擎产品使用合集之如何调用Kubernetes集群内服务
阿里云Serverless 应用引擎(SAE)提供了完整的微服务应用生命周期管理能力,包括应用部署、服务治理、开发运维、资源管理等功能,并通过扩展功能支持多环境管理、API Gateway、事件驱动等高级应用场景,帮助企业快速构建、部署、运维和扩展微服务架构,实现Serverless化的应用部署与运维模式。以下是对SAE产品使用合集的概述,包括应用管理、服务治理、开发运维、资源管理等方面。
|
1月前
|
Kubernetes Cloud Native 持续交付
【Docker专栏】Kubernetes与Docker:协同构建云原生应用
【5月更文挑战第7天】本文探讨了Docker和Kubernetes如何协同构建和管理云原生应用。Docker提供容器化技术,Kubernetes则负责容器的部署和管理。两者结合实现快速部署、自动扩展和高可用性。通过编写Dockerfile创建镜像,然后在Kubernetes中定义部署和服务进行应用暴露。实战部分展示了如何部署简单Web应用,包括编写Dockerfile、构建镜像、创建Kubernetes部署配置以及暴露服务。Kubernetes还具备自动扩展、滚动更新和健康检查等高级特性,为云原生应用管理提供全面支持。
【Docker专栏】Kubernetes与Docker:协同构建云原生应用
|
26天前
|
弹性计算 Kubernetes 监控
【阿里云弹性计算】阿里云 ECS 与 Kubernetes 集成:轻松管理容器化应用
【5月更文挑战第28天】阿里云ECS与Kubernetes集成,打造强大容器管理平台,简化应用部署,实现弹性扩展和高效资源管理。通过Kubernetes声明式配置在ECS上快速部署,适用于微服务和大规模Web应用。结合监控服务确保安全与性能,未来将深化集成,满足更多业务需求,引领容器化应用管理新趋势。
205 2
|
28天前
|
运维 Kubernetes Linux
Kubernetes详解(二十一)——ReplicaSet控制器实战应用
Kubernetes详解(二十一)——ReplicaSet控制器实战应用
59 2
|
8天前
|
SQL Kubernetes 数据处理
实时计算 Flink版产品使用问题之在 flink-conf.yaml 中定义的配置在某些情况下未被正确应用到 K8s 上运行的任务管理器(JobManager)和任务管理节点(TaskManager),是什么导致的
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
|
1月前
|
Kubernetes 网络协议 应用服务中间件
Kubernetes详解(十七)——Pod存活性探针应用实战
Kubernetes详解(十七)——Pod存活性探针应用实战
46 4

热门文章

最新文章