内容简介:kubernetes自定义资源对象再极大程度提高了API Server的可扩展性,让企业能够根据业务需求通过CRD编写controller或者operator来实现生产中各种特殊场景。随着k8s的版本升级,CRD的功能也越来越完善,下面对其中几点进行说明。以下验证kubernetes版本为1.13.2,docker版本:18.09.5在项目中用自定义资源对象时,如果创建自定义资源时某些字段不符合要求,会导致监听该资源对象的controller或者operator出现异常,解析结构体报错,所以Validati
kubernetes自定义资源对象再极大程度提高了API Server的可扩展性,让企业能够根据业务需求通过CRD编写controller或者operator来实现生产中各种特殊场景。随着k8s的版本升级,CRD的功能也越来越完善,下面对其中几点进行说明。
以下验证kubernetes版本为1.13.2,docker版本:18.09.5
image
Validation(验证)
在项目中用自定义资源对象时,如果创建自定义资源时某些字段不符合要求,会导致监听该资源对象的controller或者operator出现异常,解析结构体报错,所以Validation这个功能非常实用,在创建时就进行校验,减少后面的排错和异常处理的麻烦。
可以通过 OpenAPI v3 schema 验证自定义对象是否符合标准 。此外,以下限制适用于 schema:
- 字段
default、nullable、discriminator、readOnly、writeOnly、xml、deprecated和$ref不能设置。 - 该字段
uniqueItems不能设置为 true。 - 该字段
additionalProperties不能设置为 false。
可以使用 kube-apiserver CustomResourceValidation 上的功能门(feature gate)禁用此功能:
--feature-gates=CustomResourceValidation=false
从以下特性门参数说明地址,可以看到Validation功能在k8s 1.8版本就已经有了,但是CustomResourceValidation特性门是默认false,1.9Beta之后版本默认为true
https://kubernetes.io/docs/reference/command-line-tools-reference/feature-gates/
image
以下示例将大概对该功能进行应用和说明,在以下示例中,CustomResourceDefinition 对自定义对象应用以下验证:
-
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 :
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
image
如果所有字段都符合校验逻辑,才可以创建对象。
将以下 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
Category(分类)
类别是自定义资源所属的分组资源的列表(例如 all )。您可以使用 kubectl get <category-name> 列出属于该类别的资源。此功能可用于 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的资源对象。(这个可能得等几分钟才能生效)
image
子资源
status子资源
启用状态子资源后,将公开自定义资源的子资源 /status 。
- 状态和规范节分别由自定义资源内的
.status和.specJSONPath 表示。 -
PUT /status对子资源的请求采用自定义资源对象,并忽略除状态节之外的任何更改。 -
PUT /status对子资源的请求仅验证自定义资源的状态节。 -
PUT/ POST/ PATCH请求自定义资源忽略更改状态节。 - 对 spec 节的任何更改都会增加
.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 子资源后,将公开自定义资源的子资源 /scale 。该 autoscaling/v1.Scale 对象作为有效负载发送 /scale。
要启用 scale 子资源,CustomResourceDefinition 中需要定义以下值。
-
SpecReplicasPath 在与之对应的自定义资源中定义 JSONPath Scale.Spec.Replicas。这是一个必需的值。.spec 只允许使用带点符号的 JSONPaths 。如果 SpecReplicasPath 自定义资源中没有值,则 /scale 子资源将在GET上返回错误。
-
StatusReplicasPath 在与之对应的自定义资源中定义 JSONPath Scale.Status.Replicas。这是一个必需的值。.stutus 只允许使用带点符号的 JSONPaths 。如果 StatusReplicasPath 自定义资源中没有值,则子资源 /scale 中的状态副本值将默认为 0。
-
LabelSelectorPath在与之对应的自定义资源中定义 JSONPath Scale.Status.Selector。这是一个可选值。必须将其设置为与 HPA 一起使用。.status 只允许使用带点符号的 JSONPaths 。如果 LabelSelectorPath 自定义资源中没有值,则子资源 /scale 中的状态选择器值将默认为空字符串。
在以下示例中,启用了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 列。
-
将 CustomResourceDefinition保存到
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 -
创建 CustomResourceDefinition:
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 中定义。
operator中应用该特性
在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坑,励志成为优秀的程序猿,那么这些资源很适合你,包括 java 、 go 、 python 、springcloud、elk、嵌入式 、大数据、面试资料、前端等资源。同时我们组建了一个技术交流群,里面有很多大佬,会不定时分享技术文章,如果你想来一起学习提高,可以关注以下公众号后回复【2】,获取。
我是小碗汤,我们一起学习,扫码关注,精彩内容第一时间推给你
扫码关注我,一起交流
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- kubernetes自定义资源对象高级功能
- Python 进阶:自定义对象实现切片功能
- Objective-C 1.0 中类与对象的定义
- Objective-C 2.0 中类与对象的定义
- powershell – 如何向自定义对象添加更多属性值
- Bean定义对象BeanDefinition注册到IOC容器中
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
PHP and MySQL Web Development
Luke Welling、Laura Thomson / Sams / July 25, 2007 / $49.99
Book Description PHP and MySQL Web Development teaches you to develop dynamic, secure, commerical Web sites. Using the same accessible, popular teaching style of the three previous editions, this b......一起来看看 《PHP and MySQL Web Development》 这本书的介绍吧!