• Kubernetes——自定义资源类型(CRD)


    自定义资源类型(CRD)

      Kubernetes 系统的扩展和增强既包括扩展 API Server 所支持的资源类型及相关声明式功能的实现,以及消除集群的单点以实现集群的高可用等,也包括如何将系统增强为一个完整意义上的 PaaS 平台,并以 DevOps 文化为驱动改善工作流程等。

      Kubernetes API 默认提供的众多的功能性资源类型可用于容器编排以解决多数场景中的编排需求。但是,有些场景也需要借助于额外的或更高级别的编排抽象,例如引入集群外部的一些服务并以资源对象的形式进行管理,或者把 Kubernetes 的多个标准资源对象合并为一个单一的更高级别的资源抽象等等。而这类的 API 扩展抽象通常也应该兼容 Kubernetes 系统的基本特性,如支持 kubectl 管理工具、CRUD 及 watch 机制、标签、etcd 存储、认证、授权、RBAC 及审计,等等,从而使得用户可将精力集中于构建业务逻辑本身。

      目前,扩展 Kubernetes API 的常用方式有三种:

      • 使用 CRD(CustomResourceDefinitions)自定义资源类型。
      • 开发自定义的 API Server 并聚合至主 API Server。
      • 定制扩展 Kubernetes 源码。

      其中,CRD 最易用但限制较多,自定义 API Server 更富有弹性但代码工作量偏大,而仅在必须添加新的核心类型才能确保专用的 Kubernetes 集群功能正常时才应该定制系统源码。

      CRD 并非设计用来取代 Kubernetes 的原生资源类型,而是用于补充一种简单易用的更为灵活和更高级别的自定义 API 资源的方式。虽然目前在功能上仍存在不少的局限,但对于大多数的需求场景来说,CRD 的表现已经足够好,因此在满足需求的前提下是首选的 API 资源类型扩展方案。

    一、创建 CRD 对象

      CRD 自 Kubernetes 1.7 版开始引入,并自 1.8 版起完全取代其前身 TPR(ThirdPartyResources),其设计目标是通过 CRD 可以向 API 中增加新资源类型,无须修改 Kubernetes 源代码就能扩展它支持使用 API 资源类型。该功能大大提高了 Kubernetes 的可扩展能力。

      CRD 本身也是一种资源类型,是一种无须编码就可以扩展原生 Kubernetes API 接口的形式,隶属于集群级别。实例化出特定的对象之后,它会在 API 上注册生成 GVR 类型 URL 端点,并能够作为一种资源类型被使用并实例化相应的对象。自定义资源类型之前,选定其使用的 API 群租名称、版本及新建的资源类型名称,根据这些信息即可创建自定义资源类型,并创建自定义类型的资源对象。

      CRD 高级特性:

      • 支持 subresource,比如 status 或者 scale。
      • finalizer,在删除自定义资源的同时去做垃圾回收。
      • controller,通过 client-go 中的 informer,实现更强大的功能。
      • crd 的 validation 可对资源中的字段进行验证,设置默认值。

      CustomResourceDefinition 字段定义如下:

    [root@k8s-master01-test-2-26 ~]# kubectl explain customresourcedefinition
    KIND:     CustomResourceDefinition
    VERSION:  apiextensions.k8s.io/v1
    
    DESCRIPTION:
         CustomResourceDefinition represents a resource that should be exposed on
         the API server. Its name MUST be in the format <.spec.name>.<.spec.group>.
    
    FIELDS:
       apiVersion	<string>
         APIVersion defines the versioned schema of this representation of an
         object. Servers should convert recognized schemas to the latest internal
         value, and may reject unrecognized values. More info:
         https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
    
       kind	<string>
         Kind is a string value representing the REST resource this object
         represents. Servers may infer this from the endpoint the client submits
         requests to. Cannot be updated. In CamelCase. More info:
         https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
    
       metadata	<Object>
         Standard object's metadata More info:
         https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
    
       spec	<Object> -required-
         spec describes how the user wants the resources to appear
    
       status	<Object>
         status indicates the actual state of the CustomResourceDefinition
    
    [root@k8s-master01-test-2-26 ~]# 
    

      CustomResourceDefinition.spec 字段定义如下:

    [root@k8s-master01-test-2-26 ~]# kubectl explain customresourcedefinition.spec
    KIND:     CustomResourceDefinition
    VERSION:  apiextensions.k8s.io/v1
    
    RESOURCE: spec <Object>
    
    DESCRIPTION:
         spec describes how the user wants the resources to appear
    
         CustomResourceDefinitionSpec describes how a user wants their resource to
         appear
    
    FIELDS:
       conversion	<Object>
         conversion defines conversion settings for the CRD.
    
       group	<string> -required-
         group is the API group of the defined custom resource. The custom resources
         are served under `/apis/<group>/...`. Must match the name of the
         CustomResourceDefinition (in the form `<names.plural>.<group>`).
    
       names	<Object> -required-
         names specify the resource and kind names for the custom resource.
    
       preserveUnknownFields	<boolean>
         preserveUnknownFields indicates that object fields which are not specified
         in the OpenAPI schema should be preserved when persisting to storage.
         apiVersion, kind, metadata and known fields inside metadata are always
         preserved. This field is deprecated in favor of setting
         `x-preserve-unknown-fields` to true in
         `spec.versions[*].schema.openAPIV3Schema`. See
         https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions/#pruning-versus-preserving-unknown-fields
         for details.
    
       scope	<string> -required-
         scope indicates whether the defined custom resource is cluster- or
         namespace-scoped. Allowed values are `Cluster` and `Namespaced`.
    
       versions	<[]Object> -required-
         versions is the list of all API versions of the defined custom resource.
         Version names are used to compute the order in which served versions are
         listed in API discovery. If the version string is "kube-like", it will sort
         above non "kube-like" version strings, which are ordered lexicographically.
         "Kube-like" versions start with a "v", then are followed by a number (the
         major version), then optionally the string "alpha" or "beta" and another
         number (the minor version). These are sorted first by GA > beta > alpha
         (where GA is a version with no suffix such as beta or alpha), and then by
         comparing major version, then minor version. An example sorted list of
         versions: v10, v2, v1, v11beta2, v10beta3, v3beta1, v12alpha1, v11alpha2,
         foo1, foo10.
    
    [root@k8s-master01-test-2-26 ~]# 

      customresourcedefinition.spce 常用字段定义如下:

      • conversion <Object>: 定义 CRD 的不同版本之间的格式转换方式。有两个子选项: strategy 和 webhook。
      • group <string> -required-: 定义了自定义资源所属的 API 组。自定义资源在`/apis/<group>/…`下提供。必须与 CustomResourceDefinition(格式为 `<names.plural>.<group>`)相同。
      • names <Object> -required-: 指定自定义资源的资源和种类名称。
      • preserveUnknownFields <boolean>: 表示未指定的对象字段。
      • scope <string> -required-: 指示定义的自定义资源是 cluster or Namespace-scoped。允许的值为 'Cluster' 和 'Namespaced'。
      • versions <[]Object> -required-: 定义自定义资源的所有API版本的列表。

      先看看系统中有哪些 CRD 资源,然后我们再自己创建一个 CRD 资源:

    [root@k8s-master01-test-2-26 ~]# kubectl get CustomResourceDefinition
    NAME                                                  CREATED AT
    accessors.storage.kubesphere.io                       2022-07-01T02:20:20Z
    alertmanagerconfigs.monitoring.coreos.com             2022-07-01T02:23:04Z
    alertmanagers.monitoring.coreos.com                   2022-07-01T02:23:08Z
    applications.app.k8s.io                               2022-07-01T02:19:04Z
    applications.argoproj.io                              2022-07-01T02:22:10Z
    applications.gitops.kubesphere.io                     2022-07-01T02:22:38Z
    applicationsets.argoproj.io                           2022-07-01T02:22:10Z
    appprojects.argoproj.io                               2022-07-01T02:22:11Z
    argocdextensions.argoproj.io                          2022-07-01T02:22:11Z
    authorizationpolicies.security.istio.io               2022-07-01T02:21:41Z
    bgpconfigurations.crd.projectcalico.org               2022-07-01T02:12:34Z
    bgppeers.crd.projectcalico.org                        2022-07-01T02:12:34Z
    blockaffinities.crd.projectcalico.org                 2022-07-01T02:12:35Z
    clusterconfigurations.installer.kubesphere.io         2022-07-01T02:12:51Z
    clusterdashboards.monitoring.kubesphere.io            2022-07-01T02:28:13Z
    clusterinformations.crd.projectcalico.org             2022-07-01T02:12:35Z
    clusters.cluster.kubesphere.io                        2022-07-01T02:19:19Z
    clustertemplates.devops.kubesphere.io                 2022-07-01T02:22:36Z
    configs.notification.kubesphere.io                    2022-07-01T02:27:24Z
    dashboards.monitoring.kubesphere.io                   2022-07-01T02:28:13Z
    destinationrules.networking.istio.io                  2022-07-01T02:21:42Z
    devopsprojects.devops.kubesphere.io                   2022-07-01T02:22:37Z
    envoyfilters.networking.istio.io                      2022-07-01T02:21:42Z
    exporters.events.kubesphere.io                        2022-07-01T02:21:33Z
    federatedrolebindings.iam.kubesphere.io               2022-07-01T02:19:28Z
    federatedroles.iam.kubesphere.io                      2022-07-01T02:19:31Z
    federatedusers.iam.kubesphere.io                      2022-07-01T02:19:33Z
    felixconfigurations.crd.projectcalico.org             2022-07-01T02:12:35Z
    filters.logging.kubesphere.io                         2022-07-01T02:17:40Z
    fluentbitconfigs.logging.kubesphere.io                2022-07-01T02:17:41Z
    fluentbits.logging.kubesphere.io                      2022-07-01T02:17:41Z
    gateways.gateway.kubesphere.io                        2022-07-01T02:19:23Z
    gateways.networking.istio.io                          2022-07-01T02:21:42Z
    gitrepositories.devops.kubesphere.io                  2022-07-01T02:22:37Z
    globalnetworkpolicies.crd.projectcalico.org           2022-07-01T02:12:35Z
    globalnetworksets.crd.projectcalico.org               2022-07-01T02:12:35Z
    globalrolebindings.iam.kubesphere.io                  2022-07-01T02:19:35Z
    globalroles.iam.kubesphere.io                         2022-07-01T02:19:38Z
    groupbindings.iam.kubesphere.io                       2022-07-01T02:19:41Z
    groups.iam.kubesphere.io                              2022-07-01T02:19:44Z
    helmapplications.application.kubesphere.io            2022-07-01T02:19:07Z
    helmapplicationversions.application.kubesphere.io     2022-07-01T02:19:09Z
    helmcategories.application.kubesphere.io              2022-07-01T02:19:12Z
    helmreleases.application.kubesphere.io                2022-07-01T02:19:14Z
    helmrepos.application.kubesphere.io                   2022-07-01T02:19:17Z
    hostendpoints.crd.projectcalico.org                   2022-07-01T02:12:35Z
    inputs.logging.kubesphere.io                          2022-07-01T02:17:41Z
    ipamblocks.crd.projectcalico.org                      2022-07-01T02:12:35Z
    ipamblocks.network.kubesphere.io                      2022-07-01T02:20:00Z
    ipamconfigs.crd.projectcalico.org                     2022-07-01T02:12:35Z
    ipamhandles.crd.projectcalico.org                     2022-07-01T02:12:36Z
    ipamhandles.network.kubesphere.io                     2022-07-01T02:20:03Z
    ippools.crd.projectcalico.org                         2022-07-01T02:12:36Z
    ippools.network.kubesphere.io                         2022-07-01T02:20:06Z
    istiooperators.install.istio.io                       2022-07-01T02:21:42Z
    jaegers.jaegertracing.io                              2022-07-01T02:23:06Z
    kialis.kiali.io                                       2022-07-01T02:23:39Z
    kubecontrollersconfigurations.crd.projectcalico.org   2022-07-01T02:12:36Z
    loginrecords.iam.kubesphere.io                        2022-07-01T02:19:46Z
    namespacenetworkpolicies.network.kubesphere.io        2022-07-01T02:20:09Z
    networkpolicies.crd.projectcalico.org                 2022-07-01T02:12:36Z
    networksets.crd.projectcalico.org                     2022-07-01T02:12:36Z
    nginxes.gateway.kubesphere.io                         2022-07-01T02:19:25Z
    notificationmanagers.notification.kubesphere.io       2022-07-01T02:27:24Z
    outputs.logging.kubesphere.io                         2022-07-01T02:17:41Z
    parsers.logging.kubesphere.io                         2022-07-01T02:17:41Z
    peerauthentications.security.istio.io                 2022-07-01T02:21:42Z
    pipelineruns.devops.kubesphere.io                     2022-07-01T02:22:37Z
    pipelines.devops.kubesphere.io                        2022-07-01T02:22:37Z
    podmonitors.monitoring.coreos.com                     2022-07-01T02:23:12Z
    probes.monitoring.coreos.com                          2022-07-01T02:23:27Z
    prometheuses.monitoring.coreos.com                    2022-07-01T02:24:56Z
    prometheusrules.monitoring.coreos.com                 2022-07-01T02:24:11Z
    receivers.notification.kubesphere.io                  2022-07-01T02:27:25Z
    requestauthentications.security.istio.io              2022-07-01T02:21:42Z
    resourcequotas.quota.kubesphere.io                    2022-07-01T02:20:12Z
    rolebases.iam.kubesphere.io                           2022-07-01T02:19:49Z
    rulers.events.kubesphere.io                           2022-07-01T02:21:33Z
    rules.auditing.kubesphere.io                          2022-07-01T02:21:23Z
    rules.events.kubesphere.io                            2022-07-01T02:21:33Z
    s2ibinaries.devops.kubesphere.io                      2022-07-01T02:22:39Z
    s2ibuilders.devops.kubesphere.io                      2022-07-01T02:22:39Z
    s2ibuildertemplates.devops.kubesphere.io              2022-07-01T02:22:39Z
    s2iruns.devops.kubesphere.io                          2022-07-01T02:22:40Z
    serviceentries.networking.istio.io                    2022-07-01T02:21:43Z
    servicemonitors.monitoring.coreos.com                 2022-07-01T02:24:17Z
    servicepolicies.servicemesh.kubesphere.io             2022-07-01T02:20:14Z
    sidecars.networking.istio.io                          2022-07-01T02:21:43Z
    strategies.servicemesh.kubesphere.io                  2022-07-01T02:20:18Z
    telemetries.telemetry.istio.io                        2022-07-01T02:21:43Z
    templates.devops.kubesphere.io                        2022-07-01T02:22:37Z
    thanosrulers.monitoring.coreos.com                    2022-07-01T02:24:26Z
    users.iam.kubesphere.io                               2022-07-01T02:19:52Z
    virtualservices.networking.istio.io                   2022-07-01T02:21:43Z
    volumesnapshotclasses.snapshot.storage.k8s.io         2022-07-01T02:15:14Z
    volumesnapshotcontents.snapshot.storage.k8s.io        2022-07-01T02:15:14Z
    volumesnapshots.snapshot.storage.k8s.io               2022-07-01T02:15:14Z
    webhooks.auditing.kubesphere.io                       2022-07-01T02:21:23Z
    workloadentries.networking.istio.io                   2022-07-01T02:21:43Z
    workloadgroups.networking.istio.io                    2022-07-01T02:21:43Z
    workspacerolebindings.iam.kubesphere.io               2022-07-01T02:19:55Z
    workspaceroles.iam.kubesphere.io                      2022-07-01T02:19:58Z
    workspaces.tenant.kubesphere.io                       2022-07-01T02:20:23Z
    workspacetemplates.tenant.kubesphere.io               2022-07-01T02:20:25Z
    [root@k8s-master01-test-2-26 ~]# 

      下面的配置清单中定义了一个名为 user.auth.zuoyang.tech 的 CRD 资源对象,它的群组名称为为 auth.zuoyang.tech,仅支持一个版本级别 v1alpha1,复数形式为 usters,隶属于名称空间级别,因此,它的对象在 API 上的 URL 路径前缀为 /apis/auth.zuoyang.tech/v1alpha1/namespaces/NS_NAME/users/:

    apiVersion: apiextensions.k8s.io/v1
    kind: CustomResourceDefinition
    metadata:
      name: users.auth.zuoyang.tech
    spec:
      group: auth.zuoyang.tech
      names:
        kind: User
        plural: users
        singular: user
        shortNames:
        - u
      scope: Namespaced
      versions:
      - served: true
        storage: true
        name: v1alpha1
        schema:
          openAPIV3Schema:
            type: object
            properties:
              spec:
                type: object
                properties:
                  userID:
                    type: integer
                    minimum: 1
                    maximum: 65535
                  groups :
                    type: array
                    items:
                      type: string
                  email:
                    type: string
                  password:
                    type: string
                    format: password
                required: ["userID","groups"]

      配置清单中,spec 嵌套使用的字段都能够见名知意,这里需要特别说明的是,metadata.name 字段的值必须等同于 spec 字段中的 "<name.plural>.<group>" 合并起来的形式。

      清单中的 CRD 资源创建于 Kubernetes 集群中之后,继而创建一个新的 CustomResourceDefinition 类型的对象,例如,使用下面的命令列出集群上的 CRD 对象时,命令结果将显示出如下资源名称及创建时间状态信息:

    [root@k8s-master01-test-2-26 ~]# kubectl  get crd |grep zuoyang
    users.auth.zuoyang.tech                               2022-07-07T07:48:05Z
    [root@k8s-master01-test-2-26 ~]# 
    

      现在,在 API 群组 auth.zuoyang.tech/v1beta1 中,users 已经是一个名称空间级别的可用资源类型,用不可按需创建出任意数量的 users 类型的对象,下面就是一个资源清单示例,它定义了一个名为 admin 的 users 对象:

    apiVersion: auth.zuoyang.tech/v1alpha1
    kind: User
    metadata:
      name: admin
      namespace: default
    spec:
      userID: 1
      email: 1635230007@qq.com
      groups:
      - superusers
      - adminstrators
      password: zuoyang.tech
    [root@k8s-master01-test-2-26 ~]# kubectl apply -f user-cr-demo.yaml 
    user.auth.zuoyang.tech/admin created
    

      "kubectl get users" 可以查看自定义资源的状态信息:

    [root@k8s-master01-test-2-26 ~]# kubectl get users -n default
    NAME    AGE
    admin   2m39s
    [root@k8s-master01-test-2-26 ~]# kubectl describe users
    Name:         admin
    Namespace:    default
    Labels:       <none>
    Annotations:  <none>
    API Version:  auth.zuoyang.tech/v1alpha1
    Kind:         User
    Metadata:
      Creation Timestamp:  2022-07-07T07:59:20Z
      Generation:          1
      Managed Fields:
        API Version:  auth.zuoyang.tech/v1alpha1
        Fields Type:  FieldsV1
        fieldsV1:
          f:metadata:
            f:annotations:
              .:
              f:kubectl.kubernetes.io/last-applied-configuration:
          f:spec:
            .:
            f:email:
            f:groups:
            f:password:
            f:userID:
        Manager:         kubectl-client-side-apply
        Operation:       Update
        Time:            2022-07-07T07:59:20Z
      Resource Version:  390747
      UID:               e18c3482-cf85-4898-9ad7-340d47d87572
    Spec:
      Email:  1635230007@qq.com
      Groups:
        superusers
        adminstrators
      Password:  zuoyang.tech
      User ID:   1
    Events:      <none>
    [root@k8s-master01-test-2-26 ~]# 
    

      根据 API 对象 GVR 格式的 URL 规范,users 资源的对象 admin 的引用路径为 /apis/auth.zuoyang.tech/v1alpha1/namespaces/default/users/admin,这一点已通过 descreibe 命令予以证实。而要删除自定义的 users 对象 admin,只要使用通用格式的 kubeclt 命令即可,如 "kubectl delete users admin",或者使用陈述式对象配置命令 “kubectl delete -f <filename>”。

    [root@k8s-master01-test-2-26 ~]#  kubectl delete users admin
    user.auth.zuoyang.tech "admin" deleted
    [root@k8s-master01-test-2-26 ~]# kubectl get users -n default
    No resources found in default namespace.
    [root@k8s-master01-test-2-26 ~]# 

    二、定义资源格式验证

      除了对操作请求进行身份验证和授权检查之外,对象配置的变动在存储 etcd 之前还需要经由准入控制器的核验,尤其是验证型(validation)控制器会检查传入的对象格式是否符合有效格式,包括是否设定了不符合定义的数据类型值,以及是否违反了字段的限制规则等。

      Kubernetes 自 1.9 版本起支持为 CRD 定义验证(validation 字段)机制用以定义 CRD 可用的有效字段等,这在将设计的自定义资源公开时非常重要。自定义资源可使用 OpenAPI 模式声明验证规则,该模式是 JSON 模式的子集。需要注意的是,OpenAPI 架构并不能支持 JSON 架构的所有功能,而 CRD 验证也不能支持 OpenAPI 架构的所有功能,不过对大多数情况来说,它足够使用了。

      下面是一个配置清单(就是上面那个yaml)。它分别定义了 userID、groups、email 和 password 字段的数据类型,并指定了 userID 字段的取值范围,以及 password 字段的数据格式,而且还通过 required 指定 userID 和 groups 是必选字段:

    apiVersion: apiextensions.k8s.io/v1
    kind: CustomResourceDefinition
    metadata:
      name: users.auth.zuoyang.tech
    spec:
      group: auth.zuoyang.tech
      names:
        kind: User
        plural: users
        singular: user
        shortNames:
        - u
      scope: Namespaced
      versions:
      - served: true
        storage: true
        name: v1alpha1
        schema:
          openAPIV3Schema:
            type: object
            properties:
              spec:
                type: object
                properties:
                  userID:
                    type: integer
                    minimum: 1
                    maximum: 65535
                  groups :
                    type: array
                    items:
                      type: string
                  email:
                    type: string
                  password:
                    type: string
                    format: password
                required: ["userID","groups"]

      限制了每个字段的数据类型之后,验证机制会检查创建或修改操作中提供的每个字段值等是否违反了格式要求,任何的核验失败都会导致写入操作被拒绝。

      自 Kubernetes 1.11 版本开始,kubeclt 即使用服器侧对象信息打印机制,这意味着将由 API Server 决定 kubectl get 命令结果会显示哪些字段。在 CRD 资源中,可在 spec.additionalPrinterColumns 中嵌套定义在对象的详细信息中要打印的字段列表。

      下面的配置清单片段定义了要为 users 类型的对象显示相关的四个字段,将其合并至前面定义的 CRD 对象 users 配置清单的 spec 字段中,重新应用到集群中并确保其正常生效:

    [root@k8s-master01-test-2-26 ~]# kubectl explain customresourcedefinition.spec.versions.additionalPrinterColumns
    KIND:     CustomResourceDefinition
    VERSION:  apiextensions.k8s.io/v1
    
    RESOURCE: additionalPrinterColumns <[]Object>
    
    DESCRIPTION:
         additionalPrinterColumns specifies additional columns returned in Table
         output. See
         https://kubernetes.io/docs/reference/using-api/api-concepts/#receiving-resources-as-tables
         for details. If no columns are specified, a single column displaying the
         age of the custom resource is used.
    
         CustomResourceColumnDefinition specifies a column for server side printing.
    
    FIELDS:
       description	<string>
         description is a human readable description of this column.
    
       format	<string>
         format is an optional OpenAPI type definition for this column. The 'name'
         format is applied to the primary identifier column to assist in clients
         identifying column is the resource name. See
         https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types
         for details.
    
       jsonPath	<string> -required-
         jsonPath is a simple JSON path (i.e. with array notation) which is
         evaluated against each custom resource to produce the value for this
         column.
    
       name	<string> -required-
         name is a human readable name for the column.
    
       priority	<integer>
         priority is an integer defining the relative importance of this column
         compared to others. Lower numbers are considered higher priority. Columns
         that may be omitted in limited space scenarios should be given a priority
         greater than 0.
    
       type	<string> -required-
         type is an OpenAPI type definition for this column. See
         https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types
         for details.
    
    [root@k8s-master01-test-2-26 ~]# 
    
    apiVersion: apiextensions.k8s.io/v1
    kind: CustomResourceDefinition
    metadata:
      name: users.auth.zuoyang.tech
    spec:
      group: auth.zuoyang.tech
      names:
        kind: User
        plural: users
        singular: user
        shortNames:
        - u
      scope: Namespaced
      versions:
      - served: true
        storage: true
        name: v1alpha1
        schema:
          openAPIV3Schema:
            type: object
            properties:
              spec:
                type: object
                properties:
                  userID:
                    type: integer
                    minimum: 1
                    maximum: 65535
                  groups :
                    type: array
                    items:
                      type: string
                  email:
                    type: string
                  password:
                    type: string
                    format: password
                required: ["userID","groups"]
        additionalPrinterColumns:
        - name: userID
          type: integer
          description: The user ID.
          jsonPath: .spec.userID
        - name: groups
          type: string
          description: The goups of the user.
          jsonPath: .spec.goups        
        - name: email
          type: string
          description: The email of the user.
          jsonPath: .spec.email    
        - name: password
          type: string
          description: The password of the user account.
          jsonPath: .spec.password    
    
    [root@k8s-master01-test-2-26 ~]# kubectl get crd users.auth.zuoyang.tech
    NAME                      CREATED AT
    users.auth.zuoyang.tech   2022-07-07T08:54:41Z
    [root@k8s-master01-test-2-26 ~]# kubectl describe crd users.auth.zuoyang.tech
    Name:         users.auth.zuoyang.tech
    Namespace:    
    Labels:       <none>
    Annotations:  <none>
    API Version:  apiextensions.k8s.io/v1
    Kind:         CustomResourceDefinition
    Metadata:
      Creation Timestamp:  2022-07-07T08:54:41Z
      Generation:          1
      Managed Fields:
        API Version:  apiextensions.k8s.io/v1
        Fields Type:  FieldsV1
        fieldsV1:
          f:status:
            f:acceptedNames:
              f:kind:
              f:listKind:
              f:plural:
              f:shortNames:
              f:singular:
            f:conditions:
              k:{"type":"Established"}:
                .:
                f:lastTransitionTime:
                f:message:
                f:reason:
                f:status:
                f:type:
              k:{"type":"NamesAccepted"}:
                .:
                f:lastTransitionTime:
                f:message:
                f:reason:
                f:status:
                f:type:
        Manager:      kube-apiserver
        Operation:    Update
        Subresource:  status
        Time:         2022-07-07T08:54:41Z
        API Version:  apiextensions.k8s.io/v1
        Fields Type:  FieldsV1
        fieldsV1:
          f:metadata:
            f:annotations:
              .:
              f:kubectl.kubernetes.io/last-applied-configuration:
          f:spec:
            f:conversion:
              .:
              f:strategy:
            f:group:
            f:names:
              f:kind:
              f:listKind:
              f:plural:
              f:shortNames:
              f:singular:
            f:scope:
            f:versions:
        Manager:         kubectl-client-side-apply
        Operation:       Update
        Time:            2022-07-07T08:54:41Z
      Resource Version:  405679
      UID:               c98f0ba2-7fb4-4e0f-85f4-a55173b5aa64
    Spec:
      Conversion:
        Strategy:  None
      Group:       auth.zuoyang.tech
      Names:
        Kind:       User
        List Kind:  UserList
        Plural:     users
        Short Names:
          u
        Singular:  user
      Scope:       Namespaced
      Versions:
        Additional Printer Columns:
          Description:  The user ID.
          Json Path:    .spec.userID
          Name:         userID
          Type:         integer
          Description:  The goups of the user.
          Json Path:    .spec.goups
          Name:         groups
          Type:         string
          Description:  The email of the user.
          Json Path:    .spec.email
          Name:         email
          Type:         string
          Description:  The password of the user account.
          Json Path:    .spec.password
          Name:         password
          Type:         string
        Name:           v1alpha1
        Schema:
          openAPIV3Schema:
            Properties:
              Spec:
                Properties:
                  Email:
                    Type:  string
                  Groups:
                    Items:
                      Type:  string
                    Type:    array
                  Password:
                    Format:  password
                    Type:    string
                  User ID:
                    Maximum:  65535
                    Minimum:  1
                    Type:     integer
                Required:
                  userID
                  groups
                Type:  object
            Type:      object
        Served:        true
        Storage:       true
    Status:
      Accepted Names:
        Kind:       User
        List Kind:  UserList
        Plural:     users
        Short Names:
          u
        Singular:  user
      Conditions:
        Last Transition Time:  2022-07-07T08:54:41Z
        Message:               no conflicts found
        Reason:                NoConflicts
        Status:                True
        Type:                  NamesAccepted
        Last Transition Time:  2022-07-07T08:54:41Z
        Message:               the initial names have been accepted
        Reason:                InitialNamesAccepted
        Status:                True
        Type:                  Established
      Stored Versions:
        v1alpha1
    Events:  <none>
    [root@k8s-master01-test-2-26 ~]# 

     三、子资源

      前面自定义资源对象 admin 在其详细状态信息输出中没有类似核心资源的 status 字段,该字段是一种用于保存对象当前状态的子资源。

      在 Kubernetes 系统的声明式 API 中,status 字段至关重要,它由 Kubernetes 系统自行维护,相关的控制器循环中持续与 API Server 进行通信,并负责确保 status 字段中的状态匹配 spec 字段中定义的期望状态。

      在 CRD 中为自定义资源启用 status 字段的方式非常简单,只需要为其定义 spec.subresources.status 字段即可,其内嵌的字段等由系统自行维护,用户无须提供任何额外的配置。它的使用格式如下:

      crd.spec.versions.subresources 字段定义如下:

    [root@k8s-master01-test-2-26 ~]#  kubectl explain crd.spec.versions.subresources
    KIND:     CustomResourceDefinition
    VERSION:  apiextensions.k8s.io/v1
    
    RESOURCE: subresources <Object>
    
    DESCRIPTION:
         subresources specify what subresources this version of the defined custom
         resource have.
    
         CustomResourceSubresources defines the status and scale subresources for
         CustomResources.
    
    FIELDS:
       scale	<Object>
         scale indicates the custom resource should serve a `/scale` subresource
         that returns an `autoscaling/v1` Scale object.
    
       status	<map[string]>
         status indicates the custom resource should serve a `/status` subresource.
         When enabled: 1. requests to the custom resource primary endpoint ignore
         changes to the `status` stanza of the object. 2. requests to the custom
         resource `/status` subresource ignore changes to anything other than the
         `status` stanza of the object.
    
    [root@k8s-master01-test-2-26 ~]# 
    

      crd.spec.versions.subresources.scale 字段定义如下:

    [root@k8s-master01-test-2-26 ~]#  kubectl explain crd.spec.versions.subresources.scale
    KIND:     CustomResourceDefinition
    VERSION:  apiextensions.k8s.io/v1
    
    RESOURCE: scale <Object>
    
    DESCRIPTION:
         scale indicates the custom resource should serve a `/scale` subresource
         that returns an `autoscaling/v1` Scale object.
    
         CustomResourceSubresourceScale defines how to serve the scale subresource
         for CustomResources.
    
    FIELDS:
       labelSelectorPath	<string>
         labelSelectorPath defines the JSON path inside of a custom resource that
         corresponds to Scale `status.selector`. Only JSON paths without the array
         notation are allowed. Must be a JSON Path under `.status` or `.spec`. Must
         be set to work with HorizontalPodAutoscaler. The field pointed by this JSON
         path must be a string field (not a complex selector struct) which contains
         a serialized label selector in string form. More info:
         https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions#scale-subresource
         If there is no value under the given path in the custom resource, the
         `status.selector` value in the `/scale` subresource will default to the
         empty string.
    
       specReplicasPath	<string> -required-
         specReplicasPath defines the JSON path inside of a custom resource that
         corresponds to Scale `spec.replicas`. Only JSON paths without the array
         notation are allowed. Must be a JSON Path under `.spec`. If there is no
         value under the given path in the custom resource, the `/scale` subresource
         will return an error on GET.
    
       statusReplicasPath	<string> -required-
         statusReplicasPath defines the JSON path inside of a custom resource that
         corresponds to Scale `status.replicas`. Only JSON paths without the array
         notation are allowed. Must be a JSON Path under `.status`. If there is no
         value under the given path in the custom resource, the `status.replicas`
         value in the `/scale` subresource will default to 0.
    
    [root@k8s-master01-test-2-26 ~]# 
    

      crd.spec.versions.subresources.status字段定义如下:

    KIND:     CustomResourceDefinition
    VERSION:  apiextensions.k8s.io/v1
    
    DESCRIPTION:
         status indicates the custom resource should serve a `/status` subresource.
         When enabled: 1. requests to the custom resource primary endpoint ignore
         changes to the `status` stanza of the object. 2. requests to the custom
         resource `/status` subresource ignore changes to anything other than the
         `status` stanza of the object.
    
         CustomResourceSubresourceStatus defines how to serve the status subresource
         for CustomResources. Status is represented by the `.status` JSON path
         inside of a CustomResource. When set, * exposes a /status subresource for
         the custom resource * PUT requests to the /status subresource take a custom
         resource object, and ignore changes to anything except the status stanza *
         PUT/POST/PATCH requests to the custom resource ignore changes to the status
         stanza
    
         CustomResourceSubresourceStatus defines how to serve the status subresource
         for CustomResources. Status is represented by the `.status` JSON path
         inside of a CustomResource. When set, * exposes a /status subresource for
         the custom resource * PUT requests to the /status subresource take a custom
         resource object, and ignore changes to anything except the status stanza *
         PUT/POST/PATCH requests to the custom resource ignore changes to the status
         stanza
    [root@k8s-master01-test-2-26 ~]# 
    

      将前面配置清单中 CRD 对象 users 的配置中,再改造下,完成活动对象的修改即可在其实例化出的对象上通过 /status 获取状态信息,例如,对象 admin 的状态引用路径为 /apis/auth.zuoyang.tech/v1alpha1/namespaces/default/users/admin/status。在没有相应资源控制器的情形下,活动对象状态的非计划内变动既不会实时反映到 status 中,也不会问 spec 定义的期望状态转换。

      事实上,如果有相应的资源控制器维护自定义的资源类型时,还可以配置自定义资源对象时使用 scale 子资源和 status 子资源协同实现类似 Deployment 或 StatefulSet 等控制器一样对象规模的伸缩功能。例子如下:

    apiVersion: apiextensions.k8s.io/v1
    kind: CustomResourceDefinition
    metadata:
      name: users.auth.zuoyang.tech
    spec:
      group: auth.zuoyang.tech
      names:
        kind: User
        plural: users
        singular: user
        shortNames:
        - u
      scope: Namespaced
      versions:
      - served: true
        storage: true
        name: v1alpha1
        schema:
          openAPIV3Schema:
            type: object
            properties:
              spec:
                type: object
                properties:
                  userID:
                    type: integer
                    minimum: 1
                    maximum: 65535
                  groups :
                    type: array
                    items:
                      type: string
                  email:
                    type: string
                  password:
                    type: string
                    format: password
                required: ["userID","groups"]
        additionalPrinterColumns:
        - name: userID
          type: integer
          description: The user ID.
          jsonPath: .spec.userID
        - name: groups
          type: string
          description: The goups of the user.
          jsonPath: .spec.goups        
        - name: email
          type: string
          description: The email of the user.
          jsonPath: .spec.email    
        - name: password
          type: string
          description: The password of the user account.
          jsonPath: .spec.password
        subresources:
          status: {}
          scale:
            labelSelectorPath: .status.labelSelector
            specReplicasPath: .spec.replicas
            statusReplicasPath: .status.replicas
    

      crd.spec.versions.subresources.scale 的各内嵌字段介绍如下:

      • specReplicasPath <string> -required-: 引用定义在 spec 中用于表示期望的副本数量的字段 jsonPath 格式,如 .spec.relicas。
      • statusReplicasPath <string> -required-: 引用保存在 status 中用于表示对象的当前副本数量的字段,jsonPath 格式,如 .status.replicas。
      • labelSelectorPath <string>: 可选字段,但若要与 HPA 结合使用则是必选字段,用于引用 status 中用于表示使用的标签选择器字段,jsonPath 格式,如 .status.labelSelector。

      为某 CRD 资源定义 scale 子资源之后,即可实例化出支持规模伸缩的自定义资源对象。但必须存在一个相应的资源控制器来持续维护相应的自定义资源对象,以确保其当前状态匹配期望的状态。满足条件后,类似于 Deployment 资源对象等,使用 "kubectl scale" 命令就能完成对自定义资源对象规模的手动伸缩。

    四、使用资源类别

      类别(categories)[英[ˈkætɪgəriz]美[ˈkætəˌgɔriz]] 是 Kubernetes 1.10 版本引入的一种分组组织自定义资源的方法,定义 CRD 对象时为其指定一个或多个类别,可以通过 kubectl get <category-name> 命令列出该类别中的所有自定义资源对象,all 就是一个常用的内建资源类别。

      例如,为前面定义的 CRD 对象 users 的 spec.names 字段中额外内嵌如下配置,便能使得 users 资源类型下的所有对象都隶属于 all 类别:

    [root@k8s-master01-test-2-26 ~]#  kubectl explain crd.spec.names
    KIND:     CustomResourceDefinition
    VERSION:  apiextensions.k8s.io/v1
    
    RESOURCE: names <Object>
    
    DESCRIPTION:
         names specify the resource and kind names for the custom resource.
    
         CustomResourceDefinitionNames indicates the names to serve this
         CustomResourceDefinition
    
    FIELDS:
       categories	<[]string>
         categories is a list of grouped resources this custom resource belongs to
         (e.g. 'all'). This is published in API discovery documents, and used by
         clients to support invocations like `kubectl get all`.
    
       kind	<string> -required-
         kind is the serialized kind of the resource. It is normally CamelCase and
         singular. Custom resource instances will use this value as the `kind`
         attribute in API calls.
    
       listKind	<string>
         listKind is the serialized kind of the list for this resource. Defaults to
         "`kind`List".
    
       plural	<string> -required-
         plural is the plural name of the resource to serve. The custom resources
         are served under `/apis/<group>/<version>/.../<plural>`. Must match the
         name of the CustomResourceDefinition (in the form
         `<names.plural>.<group>`). Must be all lowercase.
    
       shortNames	<[]string>
         shortNames are short names for the resource, exposed in API discovery
         documents, and used by clients to support invocations like `kubectl get
         <shortname>`. It must be all lowercase.
    
       singular	<string>
         singular is the singular name of the resource. It must be all lowercase.
         Defaults to lowercased `kind`.
    
    [root@k8s-master01-test-2-26 ~]# 
    

      explain crd.spec.names.categories 内嵌字段定义如下:

    [root@k8s-master01-test-2-26 ~]#  kubectl explain crd.spec.names.categories
    KIND:     CustomResourceDefinition
    VERSION:  apiextensions.k8s.io/v1
    
    FIELD:    categories <[]string>
    
    DESCRIPTION:
         categories is a list of grouped resources this custom resource belongs to
         (e.g. 'all'). This is published in API discovery documents, and used by
         clients to support invocations like `kubectl get all`.
    [root@k8s-master01-test-2-26 ~]# 

    五、多版本支持

      Kubernetes 原生资源的一个引人瞩目的特性是它们能够在 API 版本之间自动和透明地迁移。资源的使用者可以使用混合 API 版本,并且都能够获得他们所期望的资源版本。而 Kubernetes 1.11 版本开始,CRD 支持多个版本,但它们之间的转换必须手动完成。

      在 CRD 上使用多版本机制时,将 spec.version 字段替换为 spec.versions 字段,并将支持的各版本以对象列表的形式给出定义即可。不过,多版本并存时,仅其中一个版本且必须有一个版本应标记为存储(customresourcedefinition.spec.versions.storage 字段)版本。

      下面的配置清单片断中定义了两个 API 版本,其中仅 v1alpha1 标记为了 storage:

    apiVersion: apiextensions.k8s.io/v1
    kind: CustomResourceDefinition
    metadata:
      name: users.auth.zuoyang.tech
    spec:
      group: auth.zuoyang.tech
      names:
        kind: User
        plural: users
        singular: user
        shortNames:
        - u
      scope: Namespaced
      versions:
      - served: true
        storage: true
        name: v1alpha1
        schema:
          openAPIV3Schema:
            type: object
            properties:
              spec:
                type: object
                properties:
                  userID:
                    type: integer
                    minimum: 1
                    maximum: 65535
                  groups :
                    type: array
                    items:
                      type: string
                  email:
                    type: string
                  password:
                    type: string
                    format: password
                required: ["userID","groups"]
      - served: true
        storage: false
        name: v1alpha2
        schema:
          openAPIV3Schema:
            type: object
            properties:
              spec:
                type: object
                properties:
                  userID:
                    type: integer
                    minimum: 1
                    maximum: 65535
                  groups :
                    type: array
                    items:
                      type: string
                  email:
                    type: string
                  password:
                    type: string
                    format: password
                required: ["userID","groups"]   
        additionalPrinterColumns:
        - name: userID
          type: integer
          description: The user ID.
          jsonPath: .spec.userID
        - name: groups
          type: string
          description: The goups of the user.
          jsonPath: .spec.goups        
        - name: email
          type: string
          description: The email of the user.
          jsonPath: .spec.email    
        - name: password
          type: string
          description: The password of the user account.
          jsonPath: .spec.password
        subresources:
          status: {}
          scale:
            labelSelectorPath: .status.labelSelector
            specReplicasPath: .spec.replicas
            statusReplicasPath: .status.replicas

    六、自定义控制器基础

      仅借助于 CRD 完成资源自定义本身并不能为用户带来太多的价值,它只是资源类型的定义,只是提供了 JSON 格式的数据范式及存储相关数据的能力,至于如何执行数据相关的业务逻辑,时刻确保将 status 中的状态移向 spec 中的状态则是由封装于控制器中的代码来负责实现的。

      相应的,为自定义资源类型提供业务逻辑代码的控制器需要由用户自行开发,并运行于 API Server 的客户端程序(通常是托管运行于 kubernetes 系统之上,类似于 Ingress 控制器),这就是所谓的自定义控制器(Custom Controller)。

      换句话讲,某特定的 CRD 资源的相关对象发生变动时,如何确保它的当前状态不断地接近期望的状态并非 API Server 的功能,而是相关的专用控制器组件。

      事实上,自定义控制器不仅仅能够用于管理 CRD 资源,用户也完全可以仅针对系统内建的核心类型对象开啊更高级的控制器,这些对象类型包括 Service、Deployment、ConfigMap。不过,对于每个 CRD 的自定义类别来说,至少应该存在一个相关的自定义控制器。

      简单的来说,控制器负责持续监视资源变动,根据资源的 spec 及 status 中的信息执行某些操作逻辑,并将执行结果更新至资源的 status 中。自定义控制器同样担负着类似的职责,只不过一个特定的控制器通常仅负责一部分特定的资源类型,并执行专有管理逻辑。

      Kubernetes 系统内建了许多控制器,如 NodeController、ServiceController 等,它们打包在一起并作为一个统一守护进程 kube-controller-manager。这些控制器基本上都遵循同一钟模式以完成资源管理操作,该模式通常可描述为三种特性:

      • 声明式 API:用户自定义期望的状态而非要执行的特定操作,如使用 kubectl apply 命令将请求发送至 API Server 存储于 etcd 中,并由 API Server 做出处理响应。
      • 异步:客户端的请求于 API Server 存储完成之后即返回成功信息,而无须等待控制器执行的和解循环结束。
      • 水平处理(level-based):同一对象有多次变动事件待处理时,控制器仅需要处理其最新一次的变动。这种根据最新观察结果而非历史变化来和解 status 和 spec 的机制即为水平处理机制

      定义控制器实现自定义资源管理行为的最佳方法同样是遵循此类控制器模式进行程序开发,目前,大部分开发接口都是基于 Golang 语言来实现的,相关代码位于客户端库的 client-go/go/tools/cache 和 client-go/util/workqueue 目录中。

      简单的来说,控制器包含两个重要组件,Informer/SharedInformer 和 Workqueue,前者负责监视资源对象当前状态的更改,并将事件发送至后者,而后由处理函数进行处理,如下图:

      Informer 主要由 Listwatcher、ResourceEvenetHandler 和 ResyncPeriod 三类函数组件进行构造。 

      • Listwather: 是应用于特定名称空间中特定资源对象的列表函数(listFunc)和监视函数(watchFunc),并结合字段选择器为控制器精确限定关注的资源对象。
      • ResourceEvenetHandler: 负责处理资源对象状态改变产生的相关通知,其分别使用 AddFunc、UpdateFunc、DeleteFunc 三个函数完成对象的创建、更新和删除操作。
      • ResyncPeriod 定义控制器遍历缓存中的所有项目并触发运行 UpdateFunc 的频率,即和解循环的执行频度。 
     
  • 相关阅读:
    BZOJ2705: [SDOI2012]Longge的问题 欧拉函数
    BZOJ3884: 上帝与集合的正确用法 拓展欧拉定理
    BZOJ1296: [SCOI2009]粉刷匠 DP
    BZOJ5293: [Bjoi2018]求和 树上差分
    BZOJ1398: Vijos1382寻找主人 Necklace 字符串最小表示法
    BZOJ5189: [Usaco2018 Jan]Cow at Large 贪心+LCA
    BZOJ2654: tree 二分答案+最小生成树
    BZOJ1304: [CQOI2009]叶子的染色 树形dp
    BZOJ1632: [Usaco2007 Feb]Lilypad Pond SPFA+最短路计数
    BZOJ1726: [Usaco2006 Nov]Roadblocks第二短路 K短路
  • 原文地址:https://www.cnblogs.com/zuoyang/p/16454293.html
Copyright © 2020-2023  润新知