参考官方文档:CustomResourceDefinition 扩展 Kubernetes API
创建 CustomResourceDefinition
CustomResourceDefinition(CRD)时,Kubernetes API 服务器会为你所 指定的每一个版本生成一个 RESTful 的 资源路径。CRD 可以是名字空间作用域的,也可以 是集群作用域的,取决于 CRD 的 scope
字段设置。和其他现有的内置对象一样,删除 一个名字空间时,该名字空间下的所有定制对象也会被删除。CustomResourceDefinition 本身是不受名字空间限制的,对所有名字空间可用。
创建CRD,代码
kubectl create -f crd.yaml
(venv) ➜ v1 git:(master) ✗ kubectl get crd
NAME CREATED AT
crontabs.stable.example.com 2022-05-03T06:36:22Z
stars.cnstar.kubecto-kubernetes.info 2022-05-03T08:11:02Z
创建定制对象
在创建了 CustomResourceDefinition 对象之后,你可以创建定制对象(Custom Objects)。定制对象可以包含定制字段。这些字段可以包含任意的 JSON 数据。 在下面的例子中,在类别为 CrontTab
的定制对象中,设置了cronSpec
和 image
定制字段。类别 CronTab
来自你在上面所创建的 CRD 的规约。
创建CR,代码
kubectl create -f example.yaml
(venv) ➜ v1 git:(master) ✗ kubectl get star
NAME SCHEDULE COMMAND AGE REPLICAS PHASE
example-star 2022-05-03T16:13:00Z echo Kubernetes native star! 38m 3 Running
//用简写查看st
(venv) ➜ v1 git:(master) ✗ kubectl get st
NAME SCHEDULE COMMAND AGE REPLICAS PHASE
example-star 2022-05-03T16:13:00Z echo Kubernetes native star! 39m 3 Running
//查看资源和版本信息
(venv) ➜ v1 git:(master) ✗ kubectl api-resources | grep star
stars st cnstar.kubecto-kubernetes.info/v1 true Star
(venv) ➜ v1 git:(master) ✗ kubectl get crontab
NAME AGE
my-new-cron-object 134m(venv) ➜ v1 git:(master) ✗ kubectl get ct
NAME AGE
my-new-cron-object 134m
分类
分类(Categories)是定制资源所归属的分组资源列表(例如,all
)。 你可以使用 kubectl get <分类名称>
来列举属于某分类的所有资源。
下面的示例在 CustomResourceDefinition 中将 all
添加到分类列表中, 并展示了如何使用 kubectl get all
来输出定制资源:
//categories 是定制资源所归属的分类资源列表
(venv) ➜ v1 git:(master) ✗ kubectl get all | grep star
star.cnstar.kubecto-kubernetes.info/example-star 2022-05-03T16:13:00Z echo Kubernetes native star! 40m 3 Running
设置结构化的模式
CustomResource 对象在定制字段中保存结构化的数据,这些字段和内置的字段 apiVersion
、kind
和 metadata
等一起存储,不过内置的字段都会被 API 服务器隐式完成合法性检查。有了 OpenAPI v3.0 检查 能力之后,你可以设置一个模式(Schema),在创建和更新定制对象时,这一模式会被用来 对对象内容进行合法性检查。参阅下文了解这类模式的细节和局限性。
在 apiextensions.k8s.io/v1
版本中,CustomResourceDefinition 的这一结构化模式 定义是必需的。 在 CustomResourceDefinition 的 beta 版本中,结构化模式定义是可选的。
结构化模式本身是一个 OpenAPI v3.0 验证模式,其中:
- 为对象根(root)设置一个非空的 type 值(藉由 OpenAPI 中的
type
),对每个 object 节点的每个字段(藉由 OpenAPI 中的properties
或additionalProperties
)以及 array 节点的每个条目(藉由 OpenAPI 中的items
)也要设置非空的 type 值, 除非:
- 节点包含属性
x-kubernetes-int-or-string: true
- 节点包含属性
x-kubernetes-preserve-unknown-fields: true
- 对于 object 的每个字段或 array 中的每个条目,如果其定义中包含
allOf
、anyOf
、oneOf
或not
,则模式也要指定这些逻辑组合之外的字段或条目(试比较例 1 和例 2)。 - 在
allOf
、anyOf
、oneOf
或not
上下文内不设置description
、type
、default
、additionalProperties
或者nullable
。此规则的例外是x-kubernetes-int-or-string
的两种模式(见下文)。 - 如果
metadata
被设置,
删除 CustomResourceDefinition
当你删除某 CustomResourceDefinition 时,服务器会卸载其 RESTful API 端点,并删除服务器上存储的所有定制对象。
kubectl delete -f resourcedefinition.yaml
kubectl get crontabs
Error from server (NotFound): Unable to list {"stable.example.com" "v1" "crontabs"}: the server could not find the requested resource (get crontabs.stable.example.com)
如果你在以后创建相同的 CustomResourceDefinition 时,该 CRD 会是一个空的结构。
资源类型发现
自定义完crd和cr之后,kubectl是如何发现crd的呢?
1kubectl启⽤更⾼级别的⽇志,我们便能从⽇志中了解到kubectl是如何发现这种新的资源类型:
发现过程细节如下:
- kubectl 并不知道stars
- 所以kubectl 了调⽤API 服务器的/apis 这个服务发现接⼝查询所有的API组。
- 接下来kubectI 通过/apis/group version 这个组的发现接⼝查询API 组中所有的资源
- 最后kubectl 把相关的类型(⽐如我们例⼦中的stars )转换成三元组:
- 组(如stars.cnstar.kubecto-kubernetes.info )
- 版本(如v1alpha1 )。
- 资源(如Star )
- 这些服务发现接⼝提供了完成最后⼀步转换⼯作所需要的所有信息:
➜ star-crd git:(master) ✗ kubectl get stars -v=7
I0926 21:34:35.540568 36092 loader.go:372] Config loaded from file: /Users/daixuan/.kube/config
I0926 21:34:35.550728 36092 round_trippers.go:463] GET https://192.168.59.101:8443/api?timeout=32s
I0926 21:34:35.550769 36092 round_trippers.go:469] Request Headers:
I0926 21:34:35.550840 36092 round_trippers.go:473] Accept: application/json, */*
I0926 21:34:35.550853 36092 round_trippers.go:473] User-Agent: kubectl/v1.23.5 (darwin/amd64) kubernetes/c285e78
I0926 21:34:35.550783 36092 cert_rotation.go:137] Starting client certificate rotation controller
I0926 21:34:35.580050 36092 round_trippers.go:574] Response Status: 200 OK in 29 milliseconds
I0926 21:34:35.630134 36092 round_trippers.go:463] GET https://192.168.59.101:8443/apis?timeout=32s
I0926 21:34:35.630147 36092 round_trippers.go:469] Request Headers:
I0926 21:34:35.630154 36092 round_trippers.go:473] User-Agent: kubectl/v1.23.5 (darwin/amd64) kubernetes/c285e78
I0926 21:34:35.630159 36092 round_trippers.go:473] Accept: application/json, */*
I0926 21:34:35.631751 36092 round_trippers.go:574] Response Status: 200 OK in 1 milliseconds
I0926 21:34:35.676896 36092 round_trippers.go:463] GET https://192.168.59.101:8443/apis/stable.example.com/v1?timeout=32s
I0926 21:34:35.676911 36092 round_trippers.go:469] Request Headers:
I0926 21:34:35.676918 36092 round_trippers.go:473] Accept: application/json, */*
I0926 21:34:35.676924 36092 round_trippers.go:473] User-Agent: kubectl/v1.23.5 (darwin/amd64) kubernetes/c285e78
I0926 21:34:35.676938 36092 round_trippers.go:463] GET https://192.168.59.101:8443/apis/policy/v1?timeout=32s
I0926 21:34:35.677905 36092 round_trippers.go:463] GET https://192.168.59.101:8443/apis/cnstar.kubecto-kubernetes.info/v1?timeout=32s
启动kube proxy,允许代理访问:
➜ star-crd git:(master) ✗ kubectl proxy --port 8080
Starting to serve on 127.0.0.1:8080
➜ star-crd git:(master) ✗ curl --request GET --url http://localhost:8080/apis/cnstar.kubecto-kubernetes.info/v1
{
"kind": "APIResourceList",
"apiVersion": "v1",
"groupVersion": "cnstar.kubecto-kubernetes.info/v1",
"resources": [
{
"name": "stars",
"singularName": "star",
"namespaced": true,
"kind": "Star",
"verbs": [
"delete",
"deletecollection",
"get",
"list",
"patch",
"create",
"update",
"watch"
],
"shortNames": [
"st"
],
"categories": [
"all"
],
"storageVersionHash": "olncovuN/7Q="
},
{
"name": "stars/status",
"singularName": "",
"namespaced": true,
"kind": "Star",
"verbs": [
"get",
"patch",
"update"
]
},
{
"name": "stars/scale",
"singularName": "",
"namespaced": true,
"group": "autoscaling",
"version": "v1",
"kind": "Scale",
"verbs": [
"get",
"patch",
"update"
]
}
]
}
这些逻辑都在服务发现的RESTMapper 中实现,kubect1 CLI 在~/.kube⽬录中缓存了⼀份资源类型列表,所以它⽆须每次都重新通过服务发现接⼝去获取信息。这个缓存有效期为10分钟。如果CRD 如果发⽣变化,最多可能需要10 分钟后才能在CLI中体现出来。
➜ star-crd git:(master) ✗ cat /Users/daixuan/.kube/cache/discovery/192.168.59.101_8443/cnstar.kubecto-kubernetes.info/v1/serverresources.json | jq
{
"kind": "APIResourceList",
"apiVersion": "v1",
"groupVersion": "cnstar.kubecto-kubernetes.info/v1",
"resources": [
{
"name": "stars",
"singularName": "star",
"namespaced": true,
"kind": "Star",
"verbs": [
"delete",
"deletecollection",
"get",
"list",
"patch",
"create",
"update",
"watch"
],
"shortNames": [
"st"
],
"categories": [
"all"
],
"storageVersionHash": "olncovuN/7Q="
},
{
"name": "stars/status",
"singularName": "",
"namespaced": true,
"kind": "Star",
"verbs": [
"get",
"patch",
"update"
]
},
{
"name": "stars/scale",
"singularName": "",
"namespaced": true,
"group": "autoscaling",
"version": "v1",
"kind": "Scale",
"verbs": [
"get",
"patch",
"update"
]
}
]
}
子资源
⼦资源是⼀个特殊的HTTP 端点,通过在普通资源的HTTP 路径后加上后缀得到,⽐如⼀个pod 的标准HTTP 路径是/api/v1/namespaces/namespace/pods/name ,pod 还具有⼀系列⼦资源,⽐如/logs、/portforward、/exec 和 /status ,它们对应的⼦资源 HTTP 路径:
/api/v1/namespaces/namespace/pods/name/logs
/api/v1/namespaces/namespace/pods/name/portforward
/api/v1/namespaces/namespace/pods/name/exec
/api/v1/namespaces/namespace/pods/name/status
定制资源支持 /status
和 /scale
子资源。通过在 CustomResourceDefinition 中定义 status
和 scale
, 可以有选择地启用这些子资源。
Status 子资源
/status ⼦资源⽤于把⽤户提供的CR 实例的规格与控制器提供的状态分离。 这样做的主要⽬的是⽅便进⾏权限隔离:⽤户⼀般不会更改状态字段,控制器不应该更新资源规格相关字段。
基于RBAC 的访问控制⽆法做到这么细的粒度,这些规则只能投资源维度来配置。引⼊/status ⼦资源后就解决了这个问题,因为它提供了两个不同的端点。每个常点都可以 由RBAC 规则来独⽴管理。这么做被称为规格⼀状态分离。
对/status ⼦资源的任何操作都会忽略除了status 以外的值,在/status 接⼝上不能进⾏创建资源的操作,主资源和⼦资源具有相同的乐观并发能⼒,也就是说status 和spec 共享相同的资源版本,对/ status 的更新可能会因为主资源有更新⽽发⽣冲突,反之亦然
Scale 子资源
/scale ⼦资源是对应资源的⼀个投影视图,仅仅⽤于查看或修改资源中指定的副本数。这个⼦资源主要⽤于类似Kubernetes 中的Deployment 和 Replicset 这样的具有副本数的资源,通过它可以对资源进⾏扩容或缩容。
kubectl scale 命令就是通过/scale ⼦资源来实现的。⽐如下⾯的命令可以⽤于修改某个指定资源的副本数,命令执⾏后,修改过的副本数会被写⼊Spec.replicas ,并在 GET 这个资源时可以返回给⽤户
#star原来副本数为3
➜ v1 git:(master) ✗ kubectl get star
NAME SCHEDULE COMMAND AGE REPLICAS PHASE
example-star 2022-05-03T16:13:00Z echo Kubernetes native star! 17d 3 Running
#通过scale修改star副本数为6
➜ v1 git:(master) ✗ kubectl scale --replicas=6 stars/example-star -v7
I1016 09:16:52.305804 94797 loader.go:372] Config loaded from file: /Users/daixuan/.kube/config
I1016 09:16:52.307438 94797 cert_rotation.go:137] Starting client certificate rotation controller
I1016 09:16:52.322483 94797 round_trippers.go:463] GET https://192.168.59.101:8443/apis/cnstar.kubecto-kubernetes.info/v1/namespaces/default/stars/example-star
I1016 09:16:52.322504 94797 round_trippers.go:469] Request Headers:
I1016 09:16:52.322513 94797 round_trippers.go:473] Accept: application/json
I1016 09:16:52.322518 94797 round_trippers.go:473] User-Agent: kubectl/v1.23.5 (darwin/amd64) kubernetes/c285e78
I1016 09:16:52.335225 94797 round_trippers.go:574] Response Status: 200 OK in 12 milliseconds
I1016 09:16:52.335432 94797 round_trippers.go:463] PATCH https://192.168.59.101:8443/apis/cnstar.kubecto-kubernetes.info/v1/namespaces/default/stars/example-star/scale
I1016 09:16:52.335440 94797 round_trippers.go:469] Request Headers:
I1016 09:16:52.335445 94797 round_trippers.go:473] Accept: application/json, */*
I1016 09:16:52.335450 94797 round_trippers.go:473] Content-Type: application/merge-patch+json
I1016 09:16:52.335453 94797 round_trippers.go:473] User-Agent: kubectl/v1.23.5 (darwin/amd64) kubernetes/c285e78
I1016 09:16:52.344896 94797 round_trippers.go:574] Response Status: 200 OK in 9 milliseconds
star.cnstar.kubecto-kubernetes.info/example-star scaled
#查看当前star副本数量
➜ v1 git:(master) ✗ kubectl get star
NAME SCHEDULE COMMAND AGE REPLICAS PHASE
example-star 2022-05-03T16:13:00Z echo Kubernetes native star! 17d 6 Running
从扩缩容⼦资源端点读取或写⼊的对象型别是autoscaling/v1 这个API 组中定义的Scale ,代码地址:vendor/k8s.io/api/autoscaling/v1/types.go