暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Kubernetes 自定义资源定义 — 用 Java 实现(第 1 部分)

云原生CTO 2021-11-08
2047

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
      typeinteger
    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]

参考资料

[1]

github: https://blog.hinlam.com/kubernetes-custom-resource-definition-implement-in-java-part-1-a9e726e78c98


文章转载自云原生CTO,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论