如何使用 CRD 拓展 Kubernetes 集群

2019/7/27 posted in  Kubernetes

在 6 月底 KubeCon 回来之后,就打算写几篇关于 CRD 的文章,还在 Twitter 上给人做了些许改进 CRD 相关文档的承诺,零零碎碎的事很多,直到现在才有时间落笔。不过在这一个多月里,我做了一个关于 CRD 的内部分享,两个 CRD Demo,向同事、客户数人解释 CRD 是什么东西,反而让我对这个东西更加的清晰。

我会分两到三篇文章介绍 CRD,这是第一篇,简单聊一下什么是 CRD。

太长不看版

  1. CRD 本身是 Kubernetes 的一种资源,允许我们自己自定义新的资源类型
  2. 除了 CRD 我们还要提供一个 controller 以实现自己的逻辑
  3. CRD 允许我们基于已有的 Kube 资源,拓展集群能力
  4. 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 有一些常见的误区,因此,有些概念需要提前明确:

  1. 在 Kubernetes,所有的东西都叫做资源(Resource),就是 Yaml 里 Kind 那项所描述的
  2. 但除了常见的 Deployment 之类的内置资源之外,Kube 允许用户自定义资源(Custom Resource),也就是 CR
  3. 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 支持为每个微服务创建 ServiceIngress,以实现四层负载均衡和七层负载均衡:

并且,如果开启负载均衡的功能,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 进行灰度发布。

这个例子中,AppMicroService 并没有创造 “新能力”,而只是通过对 Kubernetes 已有资源进行组合,就实现了新功能。

但是除了快速对微服务进行蓝绿、灰度之外,AppMicroService 还有没有新的价值呢,另一个看不到的价值就是管理的标准化,之前对应用下的任何操作都需要被翻译为 “Kube 语言”,即对那个 Deployment 或者 Ingress 管理,现在可以有一个统一的入口规范化管理。

总结

以一个简单的小 Demo 来描述什么是 CRD 很容易以偏概全,就我目前的思考,我认为 CRD 有两个非常重要的能力:

首先是功能上,CRD 使得 Kubernetes 已有的资源和能力变成了乐高积木,我们很轻松就可以利用这些积木拓展 Kubernetes 原生不具备的能力。

其次是产品上,基于 Kubernetes 做的产品无法避免的需要让我们将产品术语向 Kube 术语靠拢,比如一个服务就是一个 Deployment,一个实例就是一个 Pod 之类。但是 CRD 允许我们自己基于产品创建概念(或者说资源),让 Kube 已有的资源为我们的概念服务,这可以使产品更专注与解决的场景,而不是如何思考如何将场景应用到 Kubernetes。