在研究 Service Mesh 的过程中,发现 Istio 很多参数都通过 kubernetes CRD 来管理,例如 VirtualService 和 DestinationRule,这种方式使部署在 k8s 集群上的服务的管理方式更趋向一致。
kubernetes 的资源管理方式和声明式 API 的良好设计使得在这个平台上的功能扩展变得异常容易。例如 CoreOS 推出的 Operator 框架就是一个很好的例子。
这篇文章通过一个简短的示例来演示如何创建自定义资源。
创建 CRD(CustomResourceDefinition)
这里以创建一个简单的弹性伸缩配置的 CRD 为例。将下面的内容保存在 scaling_crd.yaml
文件中。
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
# name must match the spec fields below, and be in the form: <plural>.<group>
name: scalings.control.example.com
spec:
# group name to use for REST API: /apis/<group>/<version>
group: control.example.com
# list of versions supported by this CustomResourceDefinition
versions:
- name: v1
# Each version can be enabled/disabled by Served flag.
served: true
# One and only one version must be marked as the storage version.
storage: true
# either Namespaced or Cluster
scope: Namespaced
names:
# plural name to be used in the URL: /apis/<group>/<version>/<plural>
plural: scalings
# singular name to be used as an alias on the CLI and for display
singular: scaling
# kind is normally the CamelCased singular type. Your resource manifests use this.
kind: Scaling
# shortNames allow shorter string to match your resource on the CLI
shortNames:
- sc
通过 kubectl 创建这个 CRD:
kubectl apply -f scaling_crd.yaml
创建自定义资源的对象
我们编写一个 test.yaml
文件来创建一个自定义的 Scaling
对象。
apiVersion: "control.example.io/v1"
kind: Scaling
metadata:
name: test
spec:
targetDeployment: test
minReplicas: 1
maxReplicas: 5
metricType: CPU
step: 1
scaleUp: 80
scaleDown: 40
通过 kubectl 创建:
kubectl apply -f test.yaml
提示:
scaling.control.example.io/test created
你可以通过 kubectl 查看已经创建的名为 test
的 Scaling 对象。
kubectl get scalings.control.example.io test -o yaml
会输出类似如下的结果:
apiVersion: control.example.io/v1
kind: Scaling
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"control.example.io/v1","kind":"Scaling","metadata":{"annotations":{},"name":"test","namespace":"default"},"spec":{"maxReplicas":5,"metricType":"CPU","minReplicas":1,"scaleDown":40,"scaleUp":80,"step":1,"targetDeployment":"test"}}
creationTimestamp: "2019-01-09T12:22:36Z"
generation: 1
name: test
namespace: default
resourceVersion: "1316610"
selfLink: /apis/control.example.io/v1/namespaces/default/scalings/test
uid: 28717b37-5ac2-11e9-89f8-080027a9fd96
spec:
maxReplicas: 5
metricType: CPU
minReplicas: 1
scaleDown: 40
scaleUp: 80
step: 1
targetDeployment: test
我们可以像操作 k8s 内置的 Deployment 资源一样操作我们创建的 Scaling 资源,同样可以对它进行更新和删除的操作。
参数校验
上面的 CRD 配置中我们并没有指定这个资源的 Spec,也就是说用户可以使用任意的 Spec 创建这个 Scaling 资源,这并不符合我们的要求。我们希望在用户创建 Scaling 对象时,可以像 k8s 的原生资源一样进行参数校验,如果出错的情况下,就不会去创建或更新这个对象,而是给用户错误提示。
k8s 目前提供了两种方式来实现参数校验,OpenAPI v3 schema
和 validatingadmissionwebhook
。
这里主要使用比较简单的 OpenAPI v3 schema
来实现。validatingadmissionwebhook
需要用户自己提供一个检查服务,通过创建 ValidatingWebhookConfiguration
让 APIServer 将指定的操作请求转发给这个检查服务,检查服务返回 true 或者 false,决定参数校验是否成功。
我们将之前的 CRD 配置文件 scaling_crd.yaml
做一下修改,增加参数校验的部分:
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: scalings.control.example.io
spec:
group: control.example.io
versions:
- name: v1
served: true
storage: true
scope: Namespaced
names:
plural: scalings
singular: scaling
kind: Scaling
validation:
openAPIV3Schema:
properties:
spec:
required:
- targetDeployment
- minReplicas
- maxReplicas
- metricType
- step
- scaleUp
- scaleDown
properties:
targetDeployment:
type: string
minReplicas:
type: integer
minimum: 0
maxReplicas:
type: integer
minimum: 0
metricType:
type: string
enum:
- CPU
- MEMORY
- REQUESTS
step:
type: integer
minimum: 1
scaleUp:
type: integer
scaleDown:
type: integer
minimum: 0
可以看到 spec 中增加了 validation 字段,其中定义了对各个参数的检验要求。
required
表示数组中的参数必须要设置。type string
和type integer
表示限制参数类型。minimum: 0
表示数字最小值为 0。enum
表示参数只能在指定的值中。
具体支持哪些校验方法可以通过 https://github.com/OAI/OpenAPI-Specification 查看。
更新 CRD 资源:
kubectl apply -f scaling_crd.yaml
再次修改 test.yaml
测试我们的参数校验是否生效,将 targetDeployment: test
这一行删除。
更新 Name 为 test 的 Scaling 对象。
kubectl apply -f test.yaml
可以看到错误提示输出如下:
validation failure list:
spec.targetDeployment in body is required
至此,不符合我们要求的 Scaling 对象将不被允许创建。