当前位置: 首页 > news >正文

使用C#编写k8s CRD Controller

本文项目地址:k8s-crd - Repos (azure.com)

CRD

CRD指的是Custom Resource Definition。开发者更多的关注k8s对于容器的编排与调度,这也是k8s最初惊艳开发者的地方。而k8s最具价值的地方是它提供了一套标准化、跨厂商的 API、结构和语义。

k8s将它拥有的一切看作是资源,而它提供了操作资源的标准 API。我们可以使用api部署容器,进行调度,可以设置ingress 网络,可以操作volumes 做持久化存储等。

定制资源(Custom Resource)是对 Kubernetes API 的扩展。k8s内置了pod,services,configmap等资源,而用户则可以利用CRD和API,来对k8s的功能进行扩展。

声明式 API

k8s使用声明式API,声明式API与命令式API最大的区别在于:

  • 命令式API是同步的,即时的,当服务收到命令之后就会去执行,并且将结果返回。

  • 而声明式API则是向服务提交对象的配置信息,表达期望得到的对象状态,再由服务选择时机去完成。

例如,当我们使用kubectl apply 命令之后,此时可能会因令牌过期导致无法拉取image或者HelmRelease,因为k8s使用的是声明式api,用户期待的状态已经被提交,k8s会在令牌刷新成功之后最终实现用户期望。

CRD Controller

创建 CRD 不需要编程,只需要编写合规的yaml文件。

而实现CRD对象所想要的功能则需要CRD Controller来完成。编写k8s Controller并非go或者python的专利,这篇博客则是要讲如何使用C#来编写一个CRD Controller。

CRD能用来做什么?

CRD可以用来声明服务所需要或者所具有的资源。这里我们假设一个场景:

我们的服务中需要用到对象存储,来存储客户照片,或者一些大文件。通常我们会在项目中配置对象存储服务的路径,访问所需要的账号密码等,更重要的是,我们需要确定对象存储服务的类型:使用公司机房搭建的minio,还是使用云服务厂商提供的对象存储服务,配置显然是不同的。

这时我们就可以使用k8s CRD来屏蔽掉这类基础设施的实现细节。

想想看,如果我们只需要在服务的yaml中声明用来存储文件的Bucket Name和Service Name,具体使用哪种存储方式由当前所在的k8s集群来决定,存储地址自动生成在configmap中,账号密码也可以自动创建并生成secret,同时存储对象的Bucket也会自动被创建出来,是不是很方便呢?

这个只包含了Bucket Name和Service Name的yaml就是我们要创建的CRD,而这个目标则需要由对应的CRD Controller来完成。

C#实现CRD Controller

KubeOps

KubeOps是用dotnet编写的kubernetes operator SDK。和Go语言的sdk相比,它提供了相同甚至更多功能,它已经包含了对kubernetes-client/csharp 官方C# Client类库的引用。

我们可以使用命令安装KubeOps项目模板:

dotnet new --install KubeOps.Templates::*

之后我们就可以在VS中新建一个KubeOps operators 项目了。

Object Storage Operator

按约定,用来承载CRD Controller的服务一般被称为Operator,例如Helm Operator。

CRD Entity

打开刚才创建的项目,在Entities目录下编辑CRD对象对应的C#类型定义。

 [KubernetesEntity(Group = "mahua.crd.com", ApiVersion = "v1", Kind = "Bucket")]public class V1BucketEntity : CustomKubernetesEntity<V1BucketEntity.V1BucketEntitySpec, V1BucketEntity.V1BucketEntityStatus>{public class V1BucketEntitySpec{public string ServiceName { get; set; } = string.Empty;public string BucketName { get; set; } = string.Empty;}public class V1BucketEntityStatus{public string Status { get; set; } = string.Empty;}}

需要注意的是Attribute中Group相当于该CRD所在的组织类型,只有符合定义就可以了。

Kind相当于CRD的name,如同我们使用kubectl get pod -A 一样,创建CRD之后,我们就可以使用kubectl get bucket -A来查看集群当前的bucket定义。

CRD YAML

重新生成项目(自行处理掉项目中报错的地方),我们可以看到在config/crds目录下已经为我们自动生成了Bucket CRD YAML,我们可以按照CRD规范,对其进行简单修改,并部署

为CRD添加名称缩写

部署CRD YAML并测试

Mock ObjectStorageManager

我在这里Mock了一个ObjectStorageManager,在监听到集群中的Bucket资源变化时做出响应,正如前面所说的:确定对象存储服务地址;生成secret;并在对象存储服务中创建出需要的Buckcet。

因为KubeOps已经集成了kubernetes-client/csharp,我们可以直接在服务中注入IKubernetesClient来完成所需要的k8s操作。

        public async Task RegisterBucketAsync(V1BucketEntity bucketEntity){if (bucketEntity?.Metadata is null || bucketEntity.Spec is null){throw new ArgumentNullException();}await CreateSecretAsync(bucketEntity.Spec.ServiceName,bucketEntity.Spec.BucketName,bucketEntity.Metadata.NamespaceProperty,_environment.EnvironmentName);}private async Task RegisterBucketAsync(string serviceName, string bucketName, string @namespace, string environmentName){var secretName = GetSecretName(serviceName, bucketName);var url = MockObjectStorageUrl(environmentName);var account = MockObjectStorageAccount(serviceName);await MockCreateBucketAsync(bucketName);var secretEntity = CreateBucketSecret(@namespace, serviceName, secretName, url, account.UserName, account.Password);var secret = await _client.Get<V1Secret>(secretName, @namespace);if (secret == null){await _client.Create(secretEntity);}}

CRD Controller

因为Template已经为我们搭建好了项目基架,我们只需在BucketController当中注入需要的ObjectStorageManager服务即可。

ReconcileAsync方法会不断监视Bucket CRD的状态并执行,我们利用类库内置的IFinalizerManager服务为其添加finalizers 。

finalizers的作用我之前的博客已经提到过了K8s-Finalizers。Bucket作为基础设施用于持久化存储,有必要为其设置finalizers 。

[EntityRbac(typeof(V1BucketEntity), Verbs = RbacVerb.All)]public class BucketController : IResourceController<V1BucketEntity>{private readonly ILogger<BucketController> _logger;private readonly IFinalizerManager<V1BucketEntity> _finalizerManager;private readonly ObjectStorageManager _objectStorageManager;public BucketController(ILogger<BucketController> logger, IFinalizerManager<V1BucketEntity> finalizerManager,ObjectStorageManager objectStorageManager){_logger = logger;_finalizerManager = finalizerManager;_objectStorageManager = objectStorageManager;}public async Task<ResourceControllerResult?> ReconcileAsync(V1BucketEntity entity){_logger.LogInformation($"entity {entity.Name()} called {nameof(ReconcileAsync)}.");await _finalizerManager.RegisterFinalizerAsync<BucketFinalizer>(entity);await _objectStorageManager.RegisterBucketAsync(entity);return ResourceControllerResult.RequeueEvent(TimeSpan.FromSeconds(15));}}

验证CRD Controller

my-test-bucket.yaml

我们可以编写YAML来模拟一个需要对象存储服务的service部署后的场景。

apiVersion: "mahua.crd.com/v1"
kind: Bucket
metadata:name: my-test-bucket
spec:bucketName: "user-photo"serviceName: "my-app"

kubectl apply

我们可以注意到此时my-test-bucket是没有finalizers的,按照设计,当我们启动Operator会自动为其添加finalizers并生成secret。

Debug ObjectStorage.Operator

我们可以看到finalizers已经被添加,而且我们想要的对象存储服务的secret也自动生成了出来。

结论

这里就是通过一个简单的例子,为大家介绍k8s CRD的一些基本概念,以及如何使用C#来实现一个CRD Controller。CRD为我们扩展K8s提供了条件,在项目中我们可以根据需要来选择实现。

http://www.lryc.cn/news/4528.html

相关文章:

  • Ansible---playbook剧本
  • Delphi 中TImageCollection和TVirtualImageList 控件实现high-DPI
  • Ros中如何给UR5配置自定义工具 | 在Rviz中给UR5机器人装载定义工具 | UR5配置自定义末端执行器
  • 数据库 delete 表数据后,磁盘空间为什么还是被一直占用?
  • docker-微服务篇
  • 图像优化篇
  • 在surface go 2上安装ubuntu 20.04
  • Java:SpringMVC的使用(1)
  • 自动化测试岗位求职简历编写规范+注意事项,让你的简历脱颖而出
  • C 字符串
  • 【每日一题Day115】LC2335装满杯子需要的最短总时长 | 贪心
  • Flink流计算处理-旁路输出
  • nginx正向代理的配置和使用
  • Oracle Trace File Analyzer 介绍及简单使用
  • 面试实战篇 | 快手本地生活,结合项目谈Redis实战项目场景?MySQL InnoDB存储引擎如何工作的?策略模式?
  • Hadoop之——WordCount案例与执行本地jar包
  • 利用git reflog 命令来查看历史提交记录,并使用提交记录恢复已经被删除掉的分支
  • 【软件测试】大厂测试开发你真的了解吗?测试开发养成记......
  • Redis中的hash结构和扩容机制
  • 【C++奇技淫巧】前置自增与后置自增的区别(++i,i++)【2023.02.08】
  • 实战打靶集锦-005-HL
  • 铁路系统各专业介绍(车机工电辆)
  • 2/11考试总结
  • Java Set集合
  • 【手写 Vuex 源码】第七篇 - Vuex 的模块安装
  • EOC第六章《块与中枢派发》
  • 八、Git远程仓库操作——跨团队成员的协作
  • 算法刷题打卡第88天:字母板上的路径
  • UVa The Morning after Halloween 万圣节后的早晨 双向BFS
  • Connext DDS属性配置参考大全(3)