关注微信公众号《云原生CTO》更多云原生干货等你来探索
专注于 云原生技术
分享
提供优质 云原生开发
视频技术培训
面试技巧
,及技术疑难问题 解答

云原生技术分享不仅仅局限于Go
、Rust
、Python
、Istio
、containerd
、CoreDNS
、Envoy
、etcd
、Fluentd
、Harbor
、Helm
、Jaeger
、Kubernetes
、Open Policy Agent
、Prometheus
、Rook
、TiKV
、TUF
、Vitess
、Argo
、Buildpacks
、CloudEvents
、CNI
、Contour
、Cortex
、CRI-O
、Falco
、Flux
、gRPC
、KubeEdge
、Linkerd
、NATS
、Notary
、OpenTracing
、Operator Framework
、SPIFFE
、SPIRE
和 Thanos
等


Kubernetes 自定义资源定义 — 用 Java 实现(第 1 部分)
在这篇文章中,我们将深入探讨自定义资源定义,因为它是扩展 K8S
系统的一种方式。
我们将首先描述CRD
的用例,编写CRD
的一些技巧,最后您将学习如何使用Java
生成CRD
,而不是手工编辑它。
这篇文章将演示如何在没有YAML
的情况下使用Java
来构建CRD
来实现Controller
和CRD
,为你的CRD
运行一个自定义控制器,并一步一步详细介绍控制器的实现。
如果你需要使用CRD
,这篇文章不会深入探讨,请阅读K8S
的文档,这里会有一些简单的介绍。
https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/#should-i-add-a-custom-resource-to-my-kubernetes-cluster
知识小课堂
如果你希望深入理解k8s
的CRD
、CR
、operator
、kubebuilder
、operator-sdk
、client-go
等相关k8s
二次开发相关的知识,则需要大量的知识积累及动手实践,目前往往这些看起来容易让很多人陷入困境,没有关系,目前我们正在开展关于k8s
二次开发的相关课程体系,如果你希望对此有深一步的了解,可以选择进入课程入口了解详情🔎

所有的示例代码都可以从GitHub repo
下载
https://github.com/hinyinlam-pivotal/Sample-MySQL-CRD
什么是自定义资源定义?
大多数情况下,使用带有内置资源的K8S
就足够了,所有内置资源都具有结构良好且全面的YAML
。

这些YAML
可能非常冗长,例如,如果您有一个想要部署的MySQL
集群,它将需要在YAML
文件中包含StatefulSet、Service、leader
选举、负载平衡、扩展、健康检查、监控、日志收集和许多其他属性。
CRD

有一个CRD
来描述特定于MySQL
数据库的上下文是很好的:
#一个自定义资源定义
#但是我会告诉你如何实现它
#让我们称之为“FirstMySQL.yaml”
apiVersion: database.hinlam.io/v1alpha1
kind: MySQL
metadata:
name: mysql-cluster-a
namespace: default
spec:
mysql-version: 8.0
mysql-db-encoding: utf8
cluster-size: 5
autoscaling:
by: IO
scale-out: 0.8 #80%
scale-in: 0.2 #20%
resource-limits:
CPU: 2
RAM: 10G
Disk: 200G
然后你可以有一个自定义控制器MySQL Controller
读取该资源对象和生产所需StatefulSet
,volume
,service
等,从k8s
用户的角度来看,他们只是遵循这种MySQL
的规范,然后他们会神奇地得到一个MySQL
服务器集群工作。
通过这样做,FirstMySQL.Yaml
变得上下文感知及特定要求的方式运行,而不是用普通的乐高积木构建整个基础设施。
与自定义控制器相结合,可以执行智能操作,包括重新包装您自己的现有系统,将您的日常操作任务交给控制器(operator
模式),提供第三方和外部资源。
让我们看看如何使用YAML
和一些Java
代码来创建CRD
。
在API服务器中创建CRD
CustomResourceDefinition
是一个格式良好的YAML/JSON
,用来告诉API
服务器有一个自定义类型。
#让我们调用这个文件'crd.yml',顺便说一下,这个文件是无效的…仅就概念而言:
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: mysqls.database.hinlam.io
spec:
group: database.hinlam.io
names:
kind: MySQL
plural: mysqls
shortNames:
- ms
singular: mysql
scope: Namespaced
versions:
- name: v1alpha1
served: true
storage: true
这是简单的!一旦你的CRD
创建成功,你可以通过kubectl api-resources
验证:

现在你可以使用kubectl -f mysql.yaml
创建MySQL
资源了。当然mysql.yml
是一个意图记录,所以在未来,我们仍然需要一个控制器来响应这个MySQL
记录。
使用Java生成自定义资源定义
我们将生成一个YAML
文件crd
。最新的Java Client 9.0.1
刚刚发布,因此简单的方法是将以下内容包含到您的pom.xml
中:
<!-- If you just want to talk to K8S -->
<dependency>
<groupId>io.kubernetes</groupId>
<artifactId>client-java</artifactId>
<version>9.0.2</version>
</dependency>
<!--This is write yourself a controller dependencies-->
<dependency>
<groupId>io.kubernetes</groupId>
<artifactId>client-java-extended</artifactId>
<version>9.0.2</version>
</dependency>
我的Github repo
有这个部分的所有代码,只是我将一步一步地剖析它:
第1步:我们从CustomResourceDefinition
的聚合对象开始:
https://github.com/hinyinlam-pivotal/Sample-MySQL-CRD
V1CustomResourceDefinition crd = new V1CustomResourceDefinitionBuilder()
.withApiVersion("apiextensions.k8s.io/v1")
.withKind("CustomResourceDefinition")
.withMetadata(crdMeta)
.withSpec(crdSpec)
.withStatus(crdStatus)
.build();
假设您知道在crdMeta
中放入什么,让我们关注crdSpec
步骤2:创建crdSpec
:
V1CustomResourceDefinitionSpec crdSpec = new V1CustomResourceDefinitionSpecBuilder()
.withGroup(groupName)
.withVersions(crdV1)
.withScope("Namespaced")
.withNames(names)
.build();
步骤3:创建从属名称:
V1CustomResourceDefinitionNames names = new V1CustomResourceDefinitionNamesBuilder()
.withKind(kindName)
.withSingular(singular)
.withPlural(plural)
.withShortNames("ms")
.withCategories("hinlamdb", "all")
.build();
步骤4:Profit
!
所以现在你可以使用之前文章中介绍的技术来转储对象crd
:
YAML.dump(crd)
错误警报!
YAML dump
对in
中的布尔值不起作用,因此YAML.dump(crd)
将会有丢失的值。这是一个众所周知的问题,并已记录:
https://github.com/kubernetes-client/java/issues/340
如下所示的临时解决方案(可能不适用于某些场景)
//Since Gson serialization is not affected, so we can convert to JSON
Gson gson = new Gson();
String json = gson.toJson(crd);
//you can uses the JSON output in kubectl, so optionally, use the snakeYAML’s function to convert JSON to YAML
org.yaml.snakeyaml.Yaml yaml = new org.yaml.snakeyaml.Yaml();
Object result = yaml.load(json);
String output = yaml.dumpAsMap(result);
//Now you've got the YAML
你会得到这样的结果:
#This is a version without validation
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: mysqls.database.hinlam.io
spec:
group: database.hinlam.io
names:
categories:
- hinlamdb
- all
kind: MySQL
plural: mysqls
shortNames:
- ms
singular: mysql
scope: Namespaced
versions:
- additionalPrinterColumns:
- description: Size of a cluster
jsonPath: .spec.cluster-size
name: ClusterSize
type: integer
name: v1alpha1
served: true
storage: true
subresources:
scale:
specReplicasPath: .spec.cluster-size
statusReplicasPath: .status.cluster-size
status:
clusterSize: 0
这是非常小的,但同样,一个更复杂的版本可以在GitHub Gist
中找到
现在,你已经读到:
什么是CRD 使用Java生成CRD 然而,您意识到您可以创建任何无效的 MySQL
类型的对象,而kubectl
甚至不会警告您,为什么呢?
apiVersion: database.hinlam.io/v1alpha1
kind: MySQL
metadata:
name: mysql-cluster-a
namespace: default
spec:
INVALID_KEY: INVALID_VALUE
autoscaling:
by: INVALID_VALUE
scale-out: 1.2
scale-in: 0.0 #20%
testing: value
CRD的验证
我们可以告诉API
服务器在创建资源时验证所有新的CRD
。还记得XML
由XML Schema
验证的日子吗?同样的情况也发生在CRD
中:我们描述了如何根据OpenAPI3Schema
验证提交的资源(例如:MySQL.yaml
)。首先阅读Swagger
网站上的OpenAPI3
规范,它提供了一种描述所需值、映射、数组、对象类型的方法。一般来说,我们可以在YAML
中描述验证:
https://swagger.io/docs/specification/data-models/

K8S Java Client
提供了所有必需的OpenAPIV3Schema
类,让您开始构建验证的生成:

您可以看一下生成验证对象的示例代码。
https://gist.github.com/hinyinlam-pivotal/a56a6fdd2ff2b2985562a95dac094517#file-getcrdvalidation-java
验证模式类似于XML
的XSD
验证——它很长很复杂,并且在YAML
中使用手动编辑会导致出错。用YAML
编写一个只有20-40
行代码的模式可能会非常快,但对于复杂的CRD
,使用Java Client
生成它将确保属性和值之间的所有关系更容易正确。
从XML
的历史中可以看出,它还有很大的改进空间——自动生成验证代码作为启动的地方怎么样?很有趣,但这肯定超出了这篇博文的范围。
总结
CRD
是根据您的特定行为定制K8S
的构建块,它还可以作为复杂系统的抽象和封装。
到目前为止,您应该对构建您的CRD
有信心,甚至可以考虑Operator Framework
。
https://github.com/operator-framework
更重要的是,通过以编程方式生成CRD YAML
,您已经为扩展K8S
的可重用和易于维护的方法打开了一扇门。
5.3 文档
github [1]
参考资料
github: https://blog.hinlam.com/kubernetes-custom-resource-definition-implement-in-java-part-1-a9e726e78c98




