# CRD 资源

CRD 是 CustomResourceDefinition 的简写，即 **自定义资源**。

当开发者向 Kubernetes API 服务器提交了 CRD 对象后，即定义了一种新的自定义资源类型（例如新资源类型名为 `Website`），此时我们就可以通过提交 JSON 或 YAML 文件的方式创建该新资源类型实例。

## 案例

假设我们需要一个自定义的 `Website` 资源，希望该资源对象包含 `Service` 和 `Pod` 两种基础资源对象，通过创建 Website 对象，可以直接构建出一个网站，如下图：

![自定义 Website 资源类型](https://2906552408-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M6Ub8CloS5kJszh6xSR%2Fsync%2Fcc579d88c648ed7a4b453b83c8e7952976309d6c.png?generation=1595775076597990\&alt=media)

### 创建 CRD 对象

根据上述需求，向 API 服务器构建 CRD 对象，该 CRD 对象将创建一种名为 Website 的新的资源类型，该资源是 `命名空间级` 资源，其 `apiVersion` 为 `extensions.example.com/v1`：

```yaml
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition    # CRD 资源
metadata:
  name: websites.extensions.example.com    # CRD 对象名
spec:
  scope: Namespaced    # 新资源是命名空间级资源
  group: extensions.example.com    # 资源所属组
  version: v1    # 资源所属组中的版本
  names:
    kind: Website    # 新资源名
    singular: website    # 单数形式
    plural: websites    # 复数形式
```

> `spec.names.singular` 和 `spec.names.plural` 中指定的值是当使用 `kubectl get` 时后面跟的资源名

### 创建自定义资源的控制器

上述步骤已经为 Kubernetes 集群添加了名为 `Website` 的新资源类型，在用户提交创建该资源对象前，我们需要构建 `Website` 资源的控制器，由控制器处理来自用户的关于 `Website` 资源对象的请求，完成具体功能实现。

![Website 控制器创建网站对象，并创建 Deployment 和 Service](https://2906552408-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M6Ub8CloS5kJszh6xSR%2Fsync%2F9ff340f1f4bb1e589f5b7aac189e3f27b6c8b796.png?generation=1595775077052533\&alt=media)

Website 控制器会读取用户请求中的 `kubia` 对象的各项参数，并构建出名为 `kubia` 的 Website 资源对象实例，并构建 Deployment 和 Service 对象，对外提供网站服务。

在完成控制器的编码后，可以将其打包至容器中，在 Kubernetes 中托管给 Deployment 运行。

在控制器部署完成后，当用户每次创建 Website 对象时，API 服务器会向控制器发送 **ADDED** 监听事件；当用户删除 Website 对象时，API 服务器则会发送 **DELETED** 监听事件。

### 创建自定义资源对象

基于上述构建的新资源类型 `Website`，可以进而构建新资源对象，这里构建一个名为 `kubia` 的对象，在 YAML 配置文件中指定网站所需的 HTML、CSS 等文件所在的 Git 仓库地址：

```yaml
apiVersion: extensions.example.com/v1    # Website 资源所属 API 组
kind: Website    # 资源类型为 Website
metadata:
  name: kubia    # 资源对象名
spec:
  gitRepo: https://github.com/luksa/kubia-website-example.git    # 网站配置文件所在 Git 仓库地址
```

{% hint style="danger" %}
🚀 在本例中，自定义资源的 YAML 配置清单是没有指定的，即对资源对象的 **校验** 都交给了自定义资源控制器，这样带来的后果是，错误不会在用户提交给 API 服务器之后就返回，而是由控制器写入对象指定字段中，再由用户查看获得。

🚀 如果想让 API 服务器验证自定义对象，需要在 API 服务器中启用 `CustomResourceValidation` 特性，并在 CRD 中指定一个 **JSON scheme**。
{% endhint %}

构建出的 Pod 会从 Git 仓库中将需要的 HTML 等代码文件拉取至本地，然后运行 Nginx 进行网站代理，进而提供网站服务：

![Pod 从 Git 仓库中拉取网站代码文件，由 Nginx 进行代理](https://2906552408-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M6Ub8CloS5kJszh6xSR%2Fsync%2Ff445ed38320854b8eedcf78b1ce744d3c4ba4e3a.png?generation=1595775077077956\&alt=media)
