在 6 月底 KubeCon 回来之后,就打算写几篇关于 CRD 的文章,还在 Twitter 上给人做了些许改进 CRD 相关文档的承诺,零零碎碎的事很多,直到现在才有时间落笔。不过在这一个多月里,我做了一个关于 CRD 的内部分享,两个 CRD Demo,向同事、客户数人解释 CRD 是什么东西,反而让我对这个东西更加的清晰。
我会分两到三篇文章介绍 CRD,这是第一篇,简单聊一下什么是 CRD。
太长不看版:
- CRD 本身是 Kubernetes 的一种资源,允许我们自己自定义新的资源类型
- 除了 CRD 我们还要提供一个 controller 以实现自己的逻辑
- CRD 允许我们基于已有的 Kube 资源,拓展集群能力
- CRD 可以使我们自己定义一套成体系的规范,自造概念
什么是 CRD
CRD 本身是一种 Kubernetes 内置的资源类型,是 CustomResourceDefinition 的缩写,可以通过 kubectl get
命令查看集群内定义的 CRD 资源。
# kubectl get crd
NAME CREATED AT
apps.app.o0w0o.cn 2019-07-25T07:02:47Z
microservices.app.o0w0o.cn 2019-07-25T07:02:47Z
当和人聊 CRD 聊多了的之后,发现大家对 CRD 有一些常见的误区,因此,有些概念需要提前明确:
- 在 Kubernetes,所有的东西都叫做资源(Resource),就是 Yaml 里 Kind 那项所描述的
- 但除了常见的 Deployment 之类的内置资源之外,Kube 允许用户自定义资源(Custom Resource),也就是 CR
- CRD 其实并不是自定义资源,而是我们自定义资源的定义(来描述我们定义的资源是什么样子)
对于一个 CRD 来说,其本质就是一个 Open Api 的 schema,就像 Kuber Blog 的一篇文章(https://kubernetes.io/blog/2019/06/20/crd-structural-schema/ )讲到的,无论 R 还是 CR 都需要 Yaml 来描述,但是,如何确保 Yaml 描述的资源是规范的、合法的,那就是 schema 要做的事情,CRD 就其功能来讲,就是想集群注册一种新资源,并告知 ApiServer,这种资源怎么怎么被合法的定义。
控制器模式
在具体讲 CRD 之前先简单讲解一下控制器模式。对 Kubernetes 有过了解的就知道,我们可以通过创建 Deployment 来管理 Pod,而其实 Deployment 并没有直接创建 Pod,而是 Deployment 管理 RS,而 RS 管理 Pod,这其实就是控制器模式。
控制器模式允许基于已有的资源定义更高阶的控制器,来实现更复杂的能力,当然,具体的细节要更复杂,推荐我司杨老湿的文章 《浅析 Kubernetes 控制器的工作原理》(https://www.yangcs.net/posts/a-deep-dive-into-kubernetes-controllers/ )
CRD 能做什么
一般情况下,我们利用 CRD 所定义的 CR 就是一个新的控制器,我们可以自定义控制器的逻辑,来做一些 Kubernetes 集群原生不支持的功能。
拿一个具体的例子来讲,我用 Kubebulder 创建了一个简单的 CRD(https://github.com/Coderhypo/KubeService ),尝试在 Kubernetes 集群内置微服务管理。
我创建了两种资源,一个叫 App
,负责管理整个应用的生命周期,另一个叫 MicroService
,负责管理微服务的生命周期。
具体的逻辑结构可以这样理解:
App 可以直接管理多个 MicroService
,并且,每个 MicroService
支持多个版本,得益于控制器模式,MicroService
可以为每个版本创建一个 Deployment
,使得可以多个版本同时被部署。
如果只是管理应用的部署未免有些简单,MicroService
支持为每个微服务创建 Service
和 Ingress
,以实现四层负载均衡和七层负载均衡:
并且,如果开启负载均衡的功能,MicroService
将为每个版本都创建一个 Service
,因此,一个服务将拥有 n + 1 个 SVC,其中 n 是每个版本都拥有一个,而额外的 1 是微服务创建之后就不会再变动(名字和 clusterIP)的 SVC,而这个 SVC 的 Selector 会始终保持和 CurrentVersion 的 SVC 一致。
换句话讲,有一个稳定的 SVC 可以对其他组件提供当前版本的服务,而其他组件也有途径访问到特定版本的服务。这个 SVC + CurrentVersion 就非常轻松的实现了蓝绿发布的能力。
除了 SVC 外,MicroService
还基于 nginx ingress controller 的能力,实现了灰度发布的功能,同过修改 LoadBalance 里 canary
的配置,可以实现按 比例 / header / cookie 进行灰度发布。
这个例子中,App
和 MicroService
并没有创造 “新能力”,而只是通过对 Kubernetes 已有资源进行组合,就实现了新功能。
但是除了快速对微服务进行蓝绿、灰度之外,App
和 MicroService
还有没有新的价值呢,另一个看不到的价值就是管理的标准化,之前对应用下的任何操作都需要被翻译为 “Kube 语言”,即对那个 Deployment 或者 Ingress 管理,现在可以有一个统一的入口规范化管理。
总结
以一个简单的小 Demo 来描述什么是 CRD 很容易以偏概全,就我目前的思考,我认为 CRD 有两个非常重要的能力:
首先是功能上,CRD 使得 Kubernetes 已有的资源和能力变成了乐高积木,我们很轻松就可以利用这些积木拓展 Kubernetes 原生不具备的能力。
其次是产品上,基于 Kubernetes 做的产品无法避免的需要让我们将产品术语向 Kube 术语靠拢,比如一个服务就是一个 Deployment,一个实例就是一个 Pod 之类。但是 CRD 允许我们自己基于产品创建概念(或者说资源),让 Kube 已有的资源为我们的概念服务,这可以使产品更专注与解决的场景,而不是如何思考如何将场景应用到 Kubernetes。