kubernetes自定义资源对象再极大程度提升了API Server的可扩展性,让企业可以根据业务需求经过CRD编写controller或者operator来实现生产中各类特殊场景。随着k8s的版本升级,CRD的功能也愈来愈完善,下面对其中几点进行说明。html
如下验证kubernetes版本为1.13.2,docker版本:18.09.5前端
在项目中用自定义资源对象时,若是建立自定义资源时某些字段不符合要求,会致使监听该资源对象的controller或者operator出现异常,解析结构体报错,因此Validation这个功能很是实用,在建立时就进行校验,减小后面的排错和异常处理的麻烦。java
能够经过 OpenAPI v3 schema验证自定义对象是否符合标准 。此外,如下限制适用于 schema:node
default
、nullable
、discriminator
、readOnly
、writeOnly
、xml
、 deprecated
和 $ref
不能设置。 uniqueItems
不能设置为 true。 additionalProperties
不能设置为 false。 可使用 kube-apiserverCustomResourceValidation
上的功能门(feature gate)禁用此功能:python
--feature-gates=CustomResourceValidation=false复制代码
从如下特性门参数说明地址,能够看到Validation功能在k8s 1.8版本就已经有了,可是CustomResourceValidation特性门是默认false,1.9Beta以后版本默认为truegit
如下示例将大概对该功能进行应用和说明,在如下示例中,CustomResourceDefinition 对自定义对象应用如下验证:github
spec.replicas
为必填项,类型为integer,值为大于等于0小于50的偶数(2的倍数); spec.repository
为必填项; spec.version
为必填项; spec.pause
为boolean类型; spec.updateStrategy
为object类型,该object中有type、pipeline、assignStrategies属性; spec.updateStrategy.type
为string类型,并且只能为"AssignReceive", "AutoReceive"两个枚举值; spec.updateStrategy.pipeline
为string类型,并且为正整数的字符串,符合正则表达式^([1-9][0-9]*){1,3}$
; spec.updateStrategy.assignStrategies
为array类型,其元素为object类型(包含slots和fromReplicas属性); spec.updateStrategy.assignStrategies.slots
为1-16384的正整数; spec.updateStrategy.assignStrategies.fromReplicas
为字符串,符合正则表达式^[a-z0-9,]{3,}$
,即至少匹配3位a-z或者0-9或者逗号的字符串; spec.pod
为array类型,其元素为object类型(包含configmap、monitorImage、initImage、middlewareImage字段); spec.pod.configmap
、spec.pod.monitorImage
、spec.pod.initImage
、spec.pod.middlewareImage
为string类型;且用required指定configmap、initImage、middlewareImage字段为必填项。 将如下内容保存到 redis-cluster-crd.yaml
:golang
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: redisclusters.redis.middleware.hc.cn
spec:
group: redis.middleware.hc.cn
versions:
- name: v1alpha1
# 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
scope: Namespaced
names:
kind: RedisCluster
singular: rediscluster
listKind: RedisClusterList
plural: redisclusters
shortNames:
- rec
# 执行kubectl get all时会查到pod、service、该crd等属于all categories的资源对象
categories:
- all
validation:
# openAPIV3Schema 适用于验证自定义对象的 schema。
openAPIV3Schema:
properties:
spec:
required: ["replicas", "repository", "version"]
properties:
pause:
type: boolean
replicas:
type: integer
minimum: 0
maximum: 50
# 偶数
multipleOf: 2
updateStrategy:
type: object
properties:
type:
type: string
# 枚举
enum: ["AssignReceive", "AutoReceive"]
pipeline:
type: string
pattern: '^([1-9][0-9]*){1,3}$'
assignStrategies:
type: array
items:
type: object
properties:
slots:
type: integer
minimum: 1
maximum: 16384
fromReplicas:
type: string
# 至少匹配3位,a-z或者0-9或者,
pattern: '^[a-z0-9,]{3,}$'
pod:
type: array
items:
type: object
required: ["configmap", "middlewareImage", "initImage"]
properties:
configmap:
type: string
monitorImage:
type: string
initImage:
type: string
middlewareImage:
type: string复制代码
建立它:面试
kubectl create -f redis-cluster-crd.yaml复制代码
默认不加validation时,在建立自定义资源对象时,不会校验,有些字段没有了(如spec.replicas
)均可以正常被建立,为了减小排错的难度和operator、controller的麻烦的检验,因此在建立自定义资源定义时,就把validation加上。以上的检验应该覆盖到了常见的检验场景,其余场景能够本身摸索。具体还能够参考kubernetes源码,1.13.2版本kubernetes源码位于types.go第327行CustomResourceValidation结构体:正则表达式
$GOPATH/src/k8s.io/kubernetes/staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/types.go复制代码
将如下YAML保存到redis-cluster-cr.yaml
:
apiVersion: redis.middleware.hc.cn/v1alpha1
kind: RedisCluster
metadata:
name: example000-redis-cluster
namespace: kube-system
spec:
# 表明redis集群的个数
replicas: 3
# 表明是否进入维修状态
pause: true
repository: library/redis
# 镜像版本,便于后续多版本特化支持
version: 3.2.6
#redis集群升级策略
updateStrategy:
# 升级类型为AutoReceive(自动分配,不用AssignStrategies), AssignReceive(指定值分配,须要用AssignStrategies)
type: AssignReceive1
pipeline: "100a"
assignStrategies:
-
slots: 0
fromReplicas: nodeId1
-
# 从nodeId3,nodeId4一共分配1000个卡槽
slots: 1000
# 多个nodeId用逗号分隔
fromReplicas: nodeId3,nodeId4
# redis 实例配置详情
pod:
# 配置文件模板名
- configmap: example000-redis-cluster-config
# 监控镜像
monitorImage: redis-exporter:v1
# 初始化镜像
#initImage: redis-init:v1
# 中间件容器镜像
middlewareImage: redis-trib:3.2.6复制代码
并建立它:
kubectl create -f redis-cluster-cr.yaml复制代码
会发现报如下错误:
# kubectl apply -f redis-cluster-cr.yaml
The RedisCluster "example000-redis-cluster" is invalid: []: Invalid value: map[string]interface {}{"apiVersion":"redis.middleware.hc.cn/v1alpha1", "kind":"RedisCluster", "metadata":map[string]interface {}{"namespace":"kube-system", "uid":"b0946031-766b-11e9-b457-000c295db389", "resourceVersion":"44231", "generation":19, "creationTimestamp":"2019-05-14T17:14:10Z", "annotations":map[string]interface {}{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"redis.middleware.hc.cn/v1alpha1\",\"kind\":\"RedisCluster\",\"metadata\":{\"annotations\":{},\"name\":\"example000-redis-cluster\",\"namespace\":\"kube-system\"},\"spec\":{\"pause\":true,\"pod\":[{\"configmap\":\"example000-redis-cluster-config\",\"middlewareImage\":\"redis-trib:3.2.6\",\"monitorImage\":\"redis-exporter:v1\"}],\"replicas\":3,\"repository\":\"library/redis\",\"updateStrategy\":{\"assignStrategies\":[{\"fromReplicas\":\"nodeId1\",\"slots\":0},{\"fromReplicas\":\"nodeId3,nodeId4\",\"slots\":1000}],\"pipeline\":\"100a\",\"type\":\"AssignReceive1\"},\"version\":\"3.2.6\"}}\n"}, "name":"example000-redis-cluster"}, "spec":map[string]interface {}{"version":"3.2.6", "pause":true, "pod":[]interface {}{map[string]interface {}{"middlewareImage":"redis-trib:3.2.6", "monitorImage":"redis-exporter:v1", "configmap":"example000-redis-cluster-config"}}, "replicas":3, "repository":"library/redis", "updateStrategy":map[string]interface {}{"assignStrategies":[]interface {}{map[string]interface {}{"fromReplicas":"nodeId1", "slots":0}, map[string]interface {}{"fromReplicas":"nodeId3,nodeId4", "slots":1000}}, "pipeline":"100a", "type":"AssignReceive1"}}}: validation failure list:
spec.updateStrategy.assignStrategies.fromReplicas in body should match '^[a-z0-9,]{3,}$'
spec.updateStrategy.assignStrategies.slots in body should be greater than or equal to 1
spec.updateStrategy.pipeline in body should match '^([1-9][0-9]*){1,3}$'
spec.updateStrategy.type in body should be one of [AssignReceive AutoReceive]
spec.pod.initImage in body is required
spec.replicas in body should be a multiple of 2复制代码
若是全部字段都符合校验逻辑,才能够建立对象。
将如下 YAML 保存到 redis-cluster-cr.yaml
:
apiVersion: redis.middleware.hc.cn/v1alpha1
kind: RedisCluster
metadata:
name: example000-redis-cluster
namespace: kube-system
spec:
# 表明redis集群的个数
replicas: 6
# 表明是否进入维修状态
pause: true
repository: library/redis
# 镜像版本,便于后续多版本特化支持
version: 3.2.6
#redis集群升级策略
updateStrategy:
# 升级类型为AutoReceive(自动分配,不用AssignStrategies), AssignReceive(指定值分配,须要用AssignStrategies)
type: AssignReceive
pipeline: "100"
assignStrategies:
-
slots: 1
fromReplicas: all
-
# 从nodeId3,nodeId4一共分配1000个卡槽
slots: 1000
# 多个nodeId用逗号分隔
fromReplicas: node1,node2
# redis 实例配置详情
pod:
# 配置文件模板名
- configmap: example000-redis-cluster-config
# 监控镜像
monitorImage: redis-exporter:v1
# 初始化镜像
initImage: redis-init:v1
# 中间件容器镜像
middlewareImage: redis-trib:3.2.6复制代码
并建立它,发现才能够建立:
# kubectl apply -f redis-cluster-cr.yaml
rediscluster.redis.middleware.hc.cn/example000-redis-cluster configured复制代码
类别是自定义资源所属的分组资源的列表(例如 all
)。您可使用 kubectl get
列出属于该类别的资源。此功能可用于 v1.10 及以上k8s版本自定义资源。
如下示例添加 all
CustomResourceDefinition 中的类别列表,并说明如何使用 kubectl get all
输出自定义资源 。
将如下 内容保存到 redis-cluster-crd.yaml
中执行kubectl apply -f redis-cluster-crd.yaml
:
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: redisclusters.redis.middleware.hc.cn
spec:
group: redis.middleware.hc.cn
versions:
- name: v1alpha1
# 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
scope: Namespaced
names:
kind: RedisCluster
singular: rediscluster
listKind: RedisClusterList
plural: redisclusters
shortNames:
- rec
# 执行kubectl get all时会查到pod、service、该crd等属于all categories的资源对象
categories:
- all复制代码
将如下内容保存到redis-cluster-cr.yaml
中执行kubectl apply -f redis-cluster-cr.yaml
:
apiVersion: redis.middleware.hc.cn/v1alpha1
kind: RedisCluster
metadata:
name: example000-redis-cluster
namespace: kube-system
spec:
# 表明redis集群的个数
replicas: 6
# 表明是否进入维修状态
pause: true
repository: library/redis
# 镜像版本,便于后续多版本特化支持
version: 3.2.6
#redis集群升级策略
updateStrategy:
# 升级类型为AutoReceive(自动分配,不用AssignStrategies), AssignReceive(指定值分配,须要用AssignStrategies)
type: AssignReceive
pipeline: "100"
assignStrategies:
-
slots: 2000
fromReplicas: nodeId1
-
# 从nodeId3,nodeId4一共分配1000个卡槽
slots: 1000
# 多个nodeId用逗号分隔
fromReplicas: nodeId3,nodeId4
# redis 实例配置详情
pod:
# 配置文件模板名
- configmap: example000-redis-cluster-config
# 监控镜像
monitorImage: redis-exporter:v1
# 初始化镜像
initImage: redis-init:v1
# 中间件容器镜像
middlewareImage: redis-trib:3.2.6复制代码
执行kubectl get all时会查到pod、service、该crd等属于all categories的资源对象。(这个可能得等几分钟才能生效)
启用状态子资源后,将公开自定义资源的子资源 /status
。
.status
和 .spec
JSONPath 表示。 PUT /status
对子资源的请求采用自定义资源对象,并忽略除状态节以外的任何更改。 PUT /status
对子资源的请求仅验证自定义资源的状态节。 PUT/ POST/ PATCH
请求自定义资源忽略更改状态节。 .metadata.generation
的值。 在code-generator生成代码时会生成,以下方法:
// RedisClusterInterface has methods to work with RedisCluster resources.
type RedisClusterInterface interface {
Create(*v1alpha1.RedisCluster) (*v1alpha1.RedisCluster, error)
Update(*v1alpha1.RedisCluster) (*v1alpha1.RedisCluster, error)
UpdateStatus(*v1alpha1.RedisCluster) (*v1alpha1.RedisCluster, error)
......
}复制代码
启用 scale 子资源后,将公开自定义资源的子资源 /scale
。该 autoscaling/v1.Scale 对象做为有效负载发送 /scale。
要启用 scale 子资源,CustomResourceDefinition 中须要定义如下值。
在如下示例中,启用了status 和 scale 子资源。
将如下内容保存到redis-cluster-crd.yaml
并建立 kubectl apply -f redis-cluster-crd.yaml
:
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: redisclusters.redis.middleware.hc.cn
spec:
group: redis.middleware.hc.cn
versions:
- name: v1alpha1
# 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
scope: Namespaced
names:
kind: RedisCluster
singular: rediscluster
listKind: RedisClusterList
plural: redisclusters
shortNames:
- rec
# 执行kubectl get all时会查到pod、service、该crd等属于all categories的资源对象
categories:
- all
subresources:
# status enables the status subresource.
status: {}
scale:
# specReplicasPath defines the JSONPath inside of a custom resource that corresponds to Scale.Spec.Replicas.
specReplicasPath: .spec.replicas
# statusReplicasPath defines the JSONPath inside of a custom resource that corresponds to Scale.Status.Replicas.
statusReplicasPath: .status.replicas
# labelSelectorPath defines the JSONPath inside of a custom resource that corresponds to Scale.Status.Selector.
labelSelectorPath: .status.labelSelector复制代码
建立 CustomResourceDefinition 对象后,您能够建立自定义对象。
若是您将如下 YAML 保存到 redis-cluster-cr.yaml
:
apiVersion: redis.middleware.hc.cn/v1alpha1
kind: RedisCluster
metadata:
name: example000-redis-cluster
namespace: kube-system
spec:
# 表明redis集群的个数
replicas: 6
# 表明是否进入维修状态
pause: true
repository: library/redis
# 镜像版本,便于后续多版本特化支持
version: 3.2.6
#redis集群升级策略
updateStrategy:
# 升级类型为AutoReceive(自动分配,不用AssignStrategies), AssignReceive(指定值分配,须要用AssignStrategies)
type: AssignReceive
pipeline: "100"
assignStrategies:
-
slots: 2000
fromReplicas: nodeId1
-
# 从nodeId3,nodeId4一共分配1000个卡槽
slots: 1000
# 多个nodeId用逗号分隔
fromReplicas: nodeId3,nodeId4
# redis 实例配置详情
pod:
# 配置文件模板名
- configmap: example000-redis-cluster-config
# 监控镜像
monitorImage: redis-exporter:v1
# 初始化镜像
initImage: redis-init:v1
# 中间件容器镜像
middlewareImage: redis-trib:3.2.6复制代码
并建立它:
kubectl create -f redis-cluster-cr.yaml复制代码
而后在如下位置建立新的命名空间 RESTful API 端点:
/apis/redis.middleware.hc.cn/v1alpha1/namespaces/kube-system/redisclusters/example000-redis-cluster/status复制代码
和
/apis/redis.middleware.hc.cn/v1alpha1/namespaces/kube-system/redisclusters/example000-redis-cluster/scale复制代码
可使用该 kubectl scale
命令缩放自定义资源。例如,以上建立的自定义资源的的 .spec.replicas
设置为 10:
# kubectl get rec --all-namespaces
NAMESPACE NAME DESIRED PAUSE AGE
kube-system example000-redis-cluster 6 true 10h
# kubectl scale --replicas=10 rec/example000-redis-cluster -nkube-system
rediscluster.redis.middleware.hc.cn/example000-redis-cluster scaled
# kubectl get rec --all-namespaces
NAMESPACE NAME DESIRED PAUSE AGE
kube-system example000-redis-cluster 10 true 10h
# kubectl get rec example000-redis-cluster -n kube-system -o jsonpath='{.spec.replicas}'
10复制代码
从 Kubernetes 1.11 开始,kubectl 使用服务器端打印。服务器决定 kubectl get
命令显示哪些列。您可使用 CustomResourceDefinition 自定义这些列。下面的示例将输出 Spec
、Replicas
和 Age
列。
redis-cluster-crd.yaml
。 apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: redisclusters.redis.middleware.hc.cn
spec:
group: redis.middleware.hc.cn
versions:
- name: v1alpha1
# 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
scope: Namespaced
names:
kind: RedisCluster
singular: rediscluster
listKind: RedisClusterList
plural: redisclusters
shortNames:
- rec
# 执行kubectl get all时会查到pod、service、该crd等属于all categories的资源对象
categories:
- all
additionalPrinterColumns:
- name: DESIRED
type: integer
description: The number of statefulset managed by the this redisCluster
JSONPath: .spec.replicas
# boolean,date,integer,number,string
- name: PAUSE
type: boolean
description: Whether this redisCluster's grandson (pod) will not be managed by statefulset
JSONPath: .spec.pause复制代码
kubectl create -f redis-cluster-crd.yaml复制代码
redis-cluster-cr.yaml
实例。 kubectl get rec --all-namespaces复制代码
请注意 NAME
、NAMESPACE
, DESIRED
、PAUSE
和 AGE
在输出列,而且都被转成了大写字母:
[root@master-192 redis-container]# kubectl get rec --all-namespaces
NAMESPACE NAME DESIRED PAUSE AGE
kube-system example000-redis-cluster 6 true 10h复制代码
NAME
和NAMESPACE
列是隐含的,不须要在 CustomResourceDefinition 中定义。
在golang编写的operator代码中建立该结构体:
//建立CRD
func CreateRedisClusterCRD(extensionCRClient *extensionsclient.Clientset) error {
//add CustomResourceValidation due to guarantee redis operator work normally
labelSelectorPath := ".status.labelSelector"
replicasMinimum := float64(0)
replicasMaximum := float64(50)
replicasMultipleOf := float64(2)
slotsMinimum := float64(1)
slotsMaximum := float64(16384)
assignStr := "AssignReceive"
autoStr := "AutoReceive"
assignJson, _ := json.Marshal(assignStr)
autoJson, _ := json.Marshal(autoStr)
crd := &v1beta1.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{
Name: "redisclusters." + v1alpha1.SchemeGroupVersion.Group,
},
Spec: v1beta1.CustomResourceDefinitionSpec{
Group: v1alpha1.SchemeGroupVersion.Group,
Versions: []v1beta1.CustomResourceDefinitionVersion {
{
// Served is a flag enabling/disabling this version from being served via REST APIs
Served: true,
Name: v1alpha1.SchemeGroupVersion.Version,
// Storage flags the version as storage version. There must be exactly one flagged as storage version
Storage: true,
},
},
Scope: v1beta1.NamespaceScoped,
Names: v1beta1.CustomResourceDefinitionNames{
Kind: "RedisCluster",
ListKind: "RedisClusterList",
Plural: "redisclusters",
Singular: "rediscluster",
ShortNames: []string{"rec"},
Categories: []string{"all"},
},
Subresources: &v1beta1.CustomResourceSubresources {
Status: &v1beta1.CustomResourceSubresourceStatus {},
Scale: &v1beta1.CustomResourceSubresourceScale {
SpecReplicasPath: ".spec.replicas",
StatusReplicasPath: ".status.replicas",
LabelSelectorPath: &labelSelectorPath,
},
},
AdditionalPrinterColumns: []v1beta1.CustomResourceColumnDefinition{
{
Name: "DESIRED",
Type: "integer",
Description: "The number of statefulset managed by the this redisCluster",
JSONPath: ".spec.replicas",
},
{
Name: "PAUSE",
Type: "boolean",
Description: "Whether this redisCluster's grandson (pod) will not be managed by statefulset",
JSONPath: ".spec.pause",
},
{
Name: "AGE",
Type: "date",
JSONPath: ".metadata.creationTimestamp",
},
},
Validation: &v1beta1.CustomResourceValidation {
OpenAPIV3Schema: &v1beta1.JSONSchemaProps {
Properties: map[string]v1beta1.JSONSchemaProps {
"spec": {
Required: []string{"replicas", "repository", "version"},
Properties: map[string]v1beta1.JSONSchemaProps{
"pause": {
Type: "boolean",
},
"replicas": {
Type: "integer",
Minimum: &replicasMinimum,
Maximum: &replicasMaximum,
MultipleOf: &replicasMultipleOf,
},
"updateStrategy": {
Type: "object",
Properties: map[string]v1beta1.JSONSchemaProps{
"type": {
Type: "string",
Enum: []v1beta1.JSON {
{
//这里必须是JSON格式的字符串
Raw: assignJson,
},
{
Raw: autoJson,
},
},
},
"pipeline": {
Type: "string",
Pattern: `^([1-9][0-9]*){1,3}$`,
},
"assignStrategies": {
Type: "array",
Items: &v1beta1.JSONSchemaPropsOrArray{
Schema: &v1beta1.JSONSchemaProps{
Type: "object",
Properties: map[string]v1beta1.JSONSchemaProps{
"slots": {
Type: "integer",
Minimum: &slotsMinimum,
Maximum: &slotsMaximum,
},
"fromReplicas": {
Type: "string",
Pattern: `^[a-z0-9,]{3,}$`,
},
},
},
},
},
},
},
},
},
"pod": {
Type: "array",
Items: &v1beta1.JSONSchemaPropsOrArray {
Schema: &v1beta1.JSONSchemaProps {
Type: "object",
Required: []string{"replicas", "repository", "version"},
Properties: map[string]v1beta1.JSONSchemaProps{
"configmap": {
Type: "string",
},
"monitorImage": {
Type: "string",
},
"initImage": {
Type: "string",
},
"middlewareImage": {
Type: "string",
},
},
},
},
},
},
},
},
},
}
_, err := extensionCRClient.ApiextensionsV1beta1().CustomResourceDefinitions().Create(crd)
return err
}
复制代码
官方Extend the Kubernetes API with CustomResourceDefinitions:
https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions/
feature-gates参数说明:
https://kubernetes.io/docs/reference/command-line-tools-reference/feature-gates/
CustomResourceDefinition中文文档:
https://kubernetes.feisky.xyz/cha-jian-kuo-zhan/api/customresourcedefinition
swagger和openAPI: 数据类型:
https://www.breakyizhan.com/swagger/2969.html
正则表达式:
https://www.cnblogs.com/afarmer/archive/2011/08/29/2158860.html
------------
本公众号免费提供csdn下载服务,海量IT学习资源,若是你准备入IT坑,励志成为优秀的程序猿,那么这些资源很适合你,包括但不限于java、go、python、springcloud、elk、嵌入式 、大数据、面试资料、前端 等资源。同时咱们组建了一个技术交流群,里面有不少大佬,会不定时分享技术文章,若是你想来一块儿学习提升,能够公众号后台回复【2】,免费邀请加技术交流群互相学习提升,会不按期分享编程IT相关资源。
扫码关注,精彩内容第一时间推给你