一、Customer Resource
自定义资源是Kubernetes API的扩展,本文将讨什么时候应该向Kubernetes集群添加自定义资源以及何时使用独立服务。它描述了添加自定义资源的两种方法以及如何在它们之间进行选择。
1.1 自定义资源概述
资源就是Kubernetes API集合中的某个的对象。例如,内置pods资源包含Pod对象的集合。
自定义资源是扩展了Kubernetes API,但在默认的API集合中是不可用的,因为没有对应的controller处理业务逻辑。使用自定义资源,不仅可以解耦大多数的自研功能,还可用使得Kubernetes更加模块化。
自定义资源可以通过动态注册的方法,于正在running的集群中创建、删除和更新,并且与集群本身的资源是相互独立的。当自定义资源被创建,就可以通过kubectl创建和访问对象,和对内置资源的操作完全一致。
1.2 是否需要自定义资源
在创建新的API时,应该考虑与Kubernetes的API聚合,还是让API独立运行。
API聚合 | API独立 |
---|---|
声明式 | 非声明式 |
kubectl可读可写 | 不需要kubectl支持 |
接受k8s的REST限制 | 特定API路径 |
可限定为cluster或者namespace | 不适用namespace |
重用k8s API支持的功能 | 不需要这些功能 |
1.3 声明式API VS 命令式API
在声明式API,通过具有以下特性:
- 对象颗粒度小
- 基础结构的定义
- 读写多,更新少,操作主要为CRUD
- API表期望状态
命令式API,通过具有以下特性:
- 同步响应
- RPC调用
- 大量数据存储(大对象或多对象)
- 高带宽访问
- 操作非CRUD
- API不易抽象
二、Customer Resource Definition
Kubernetes提供了两种向集群添加自定义资源的方法:
- 创建自定义API server并聚合到API中
- CRDs
2.1 Customer Resource Definition介绍
通过CRD创建自定义资源,只要符合CRD结构体定义,均可以被Kubernetes所接收,以下是CRD的定义:
type CustomResourceDefinition struct {
//Kind,APIVersion
metav1.TypeMeta
//metadata
metav1.ObjectMeta
//spec
Spec CustomResourceDefinitionSpec
//status
Status CustomResourceDefinitionStatus
}
type CustomResourceDefinitionSpec struct {
Group string
Version string
//Plural,Singular,ShortNames,Kind,ListKind,Categories
Names CustomResourceDefinitionNames
//cluster or namespace
Scope ResourceScope
//validation methods
Validation *CustomResourceValidation
//status,scale(spec.replicas,status.replicas,status.labelSelector)
Subresources *CustomResourceSubresources
//name,serve,storage
Versions []CustomResourceDefinitionVersion
//定义额外显示的列
AdditionalPrinterColumns []CustomResourceColumnDefinition
//不同版本之间的转换
Conversion *CustomResourceConversion
}
type CustomResourceDefinitionStatus struct {
//描述资源的当前状态,即status.conditions
Conditions []CustomResourceDefinitionCondition
//与spec.names类似,即status.acceptNames
AcceptedNames CustomResourceDefinitionNames
//资源曾经存在的版本,可在etcd中存储,供迁移用
StoredVersions []string
}
2.2 CRD定义示例
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
# 名称必须符合下面的格式:<plural>.<group>
name: clusterversions.paas
spec:
# REST API使用的组名称:/apis/<group>/<version>
group: paas
# REST API使用的版本号:/apis/<group>/<version>
versions:
- name: v1alpha1
serve: true
storage: true
# Namespaced或Cluster
scope: Cluster
names:
# URL中使用的复数名称: /apis/<group>/<version>/<plural>
plural: clusterversions
# CLI中使用的单数名称
singular: clusterversion
# CamelCased格式的单数类型。在清单文件中使用
kind: ClusterVersion
# CLI中使用的资源简称
shortNames:
- cv
# 校验方法
validation:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
#类型校验
cronSpec:
type: string
image:
type: string
replicas:
type: integer
2.3 Customer Controller
只定义资源,不实现资源控制器是没有任何意义的。自定义控制器能够完成业务逻辑,最主要是依赖client-go库的各个组件的交互。下图展示它们之间的关系:
通过图示,可以看到几个核心组件的交互流程,蓝色表示client-go,黄色是自定义controller,各组件作用介绍如下:
2.3.1 client-go组件
-
Reflector:reflector用来watch特定的k8s API资源。具体的实现是通过
ListAndWatch
的方法,watch可以是k8s内建的资源或者是自定义的资源。当reflector
通过watch API接收到有关新资源实例存在的通知时,它使用相应的列表API获取新创建的对象,并将其放入watchHandler
函数内的Delta FIFO
队列中。 -
Informer:informer从
Delta FIFO
队列中弹出对象。执行此操作的功能是processLoop
。base controller
的作用是保存对象以供以后检索,并调用我们的控制器将对象传递给它。 -
Indexer:索引器提供对象的索引功能。典型的索引用例是基于对象标签创建索引。
Indexer
可以根据多个索引函数维护索引。Indexer使用线程安全的数据存储来存储对象及其键。 在Store
中定义了一个名为MetaNamespaceKeyFunc
的默认函数,该函数生成对象的键作为该对象的namespace/name组合。
2.3.2 自定义controller组件
-
Informer reference:指的是
Informer
实例的引用,定义如何使用自定义资源对象。 自定义控制器代码需要创建对应的Informer
。 -
Indexer reference:自定义控制器对
Indexer
实例的引用。自定义控制器需要创建对应的Indexer
。 - Resource Event Handlers:资源事件回调函数,当它想要将对象传递给控制器时,它将被调用。 编写这些函数的典型模式是获取调度对象的key,并将该key排入工作队列以进行进一步处理。
- Work queue:任务队列。 编写资源事件处理程序函数以提取传递的对象的key并将其添加到任务队列。
-
Process Item:处理任务队列中对象的函数, 这些函数通常使用
Indexer
引用或Listing
包装器来重试与该key对应的对象。
简单的说,整个处理流程大概为:Reflector通过检测 Kubernetes API来跟踪该扩展资源类型的变化,一旦发现有变化,就将该Object存储队列中,Informer循环取出该Object并将其存入Indexer进行检索,同时触发Callback回调函数,并将变更的Object Key信息放入到工作队列中,此时自定义Controller里面的Process Item就会获取工作队列里面的Key,并从Indexer中获取Key对应的Object,从而进行相关的业务处理。
三、sample-controller使用
3.1 资源创建
3.1.1 foo.crd.yaml
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: foos.samplecontroller.k8s.io
spec:
group: samplecontroller.k8s.io
version: v1alpha1
names:
kind: Foo
plural: foos
scope: Namespaced
3.1.2 example.foo.yaml
apiVersion: samplecontroller.k8s.io/v1alpha1
kind: Foo
metadata:
name: example-foo
namespace: fst-manage
spec:
deploymentName: example-foo
replicas: 1
namespace: fst-manage
3.2 sample-controller部署
3.2.1 编译
go build -o $GOPATH/src/k8s.io/kubernetes/staging/src/k8s.io/sample-controller .
3.2.2 启动
sudo ./sample-controller -kubeconfig=/opt/kube-agent/kubernetes/kubelet/kubeconfig
3.2.3 检查结果
kubectl get po -n fst-manage -o wide |grep foo
curl podId:80