
# 自定义服务CSD
在不同业务环境下，服务对平台有着不同的诉求，Kubernetes提供自定义资源CRD的轻量化机制。而在实践过程中，发现对于服务能力如服务依赖、服务访问、服务部署、监控日志等公共能力欠缺。
因此围绕CRD自研CSD，通过声明式配置CRD的能力引用，增强服务治理能力。
CSD本身属于CustomServiceDefinition类型的资源，其符合k8s资源的通用定义方法。其apiVersion和kind是固定的，metadata.name可自行配置：
```
apiVersion: osc.io/v1beta1
kind: CustomServiceDefinition
metadata:
  name: kafka-csd
```
CSD的spec包含下面的配置：
表1CSD的spec配置 
| 配置项                       | 配置描述                                                            | 必填 |
|:---|:---|:---|
| CRDRef                    | 通过apiVersion，kind以及matadata.name三个字段关联同一目录下的某个CRD资源             | 是  |
| displayName               | 所属CRD名称                                                         | 否  |
| description               | 所属CRD描述                                                         | 否  |
| role                      | 描述CRD角色，取值范围为{serviceEntity, operation}，大小写敏感，默认为serviceEntity。 | 否  |
| capabilityRequirements    | 平台能力引用配置                                                        | 否  |
| serviceEntityDependencies | 服务依赖配置                                                          | 否  |
| descriptors               | 服务安装时参数展示的UI控件定义                                                | 否  |
| versionDefinition         | 服务实例版本定义                                                        | 否  |
| defaultConfiguration      | CRD的CR示例                                                        | 否  |
   
#### role
在Openshift Operator Framework规范中，开发者定义的各类CRD资源都是对等的，没有更进一步的划分，但从实际的功能属性上来说，很容易识别出，不同CRD所处的层级和使用场景并不相同，以etcd为例，可能定义有代表服务主体本身的etcd CRD，以及表示etcd备份的backup CRD，两者客观上存在从属和依赖关系。所以，平铺的定义方式并不能很好的体现这种资源的层级和保证用户体验，在这个维度进行了细化，把CRD的功能和应用场景，按其角色分为以下两类：
- serviceEntity: 服务实体类资源，即提供如etcd实例CRD定义。
- operation：运维功能类，服务实例安装后以独立页签的形式展示，用户可以浏览已有的operation实例以及主动下发新的operation实例，如etcd backup CRD。
其中operation属于服务实体资源的能力（Capability）范畴，与serviceEntity相比只是行为方式上有所不同。
特别地，认为Helm服务的场景是一个最基本的，只包含一个serviceEntity资源定义的场景。Operator则可以包含多个不同角色的CSD，服务包在转换为OSC服务包后，用户需要对不同角色的CRD对应的CSD文件进行定制化的配置。
#### capabilityRequirements
- 配置能力引用需要在csd文件中声明capabilityRequirements。
- 能力引用只支持引入operator类型的平台能力，即平台提供的包括监控、日志等的公共能力。
- 可通过defaultPath配置文件路径，统一配置到[vendor目录](https://support.huaweicloud.com/devg-osc/osc_ss_0010.html)下。
capabilityRequirements配置样例
```
# 能力引用配置
capabilityRequirements:
  - apiVersion: osc.io/v1         # 引用平台监控capability
    kind: MonitorConfig
    defaultPath: vendor/monitor_config.yaml
  - apiVersion: osc.io/v1        # 引用平台日志capability
    kind: LogConfig
    defaultPath: vendor/log_config.yaml
```
表2capabilityRequirements配置 
| 参数名称        | 参数描述，                                    | 参数示例                       | 必填 |
|:---|:---|:---|:---|
| apiVersion  | 所引用的能力的配置版本，固定值osc.io/v1                 | osc.io/v1                  | 是  |
| kind        | 所引用的能力的配置类型，范围列表MonitorConfig\|LogConfig | MonitorConfig              | 是  |
| defaultPath | 默认配置文件路径，路径为vendor目录                     | vendor/monitor_config.yaml | 是  |
   
#### serviceEntityDependencies
- 配置服务依赖需要在csd文件中配置serviceEntityDependencies。
- 仅支持对公有服务的依赖，不支持依赖私有服务。
- defaultPath为依赖实例的配置文件，会覆盖服务自带配置。
serviceEntityDependencies配置样例
```
# 服务依赖
serviceEntityDependencies:           
  - service: rdsService               # 依赖operator类型的RDS实例
    apiVersion: rds.io/v1alpha1
    kind: rds
    defaultPath: vendor/rds_provider.yaml
  - service: redisService             # 依赖Helm类型的Redis实例，apiVersion、kind不配置
    defaultPath: vendor/redis_service_values.yaml  # redis的values.yaml文件
```
表3serviceEntityDependencies配置 
| 参数名称        | 参数描述                     | 参数示例            | 必填 |
|:---|:---|:---|:---|
| service     | 所依赖的服务的名称                | rdsService      | 是  |
| apiVersion  | 所依赖的服务的配置版本              | rds.io/v1alpha1 | 否  |
| kind        | 所依赖的服务的配置类型              | rds             | 否  |
| defaultPath | 默认配置文件路径，统一配置在vendor目录下。 | 参见样例            | 是  |
   
服务依赖配置文件样例：
- *rds_provider.yaml*
  ```
  apiVersion: osc.io/v1
  kind: rds
  spec:
    ...
  ```
  

- *redis_service_values.yaml*
  ```
  apiVersion: osc.io/v1
  kind: redis
  spec:
    global:
      imageRegistry: ""
      imagePullSecrets: []
    clusterDomain: cluster.local
    resources:
      limits: {}
      requests: {}
  ```
  
 
#### descriptors
descriptor字段用于配置UI控件，提升部署服务的用户体验，对服务参数进行控件增强，包括服务规格spec和服务状态status。该控件为可选项。
descriptors样例：
```
# UI控件
descriptors:
  spec:
  - description: "kafka实例个数"
    displayName: 集群大小
    path: {kafka.replicas}
    restriction:
      scenes:
        - CCE
    x-descriptors:
      - "urn:alm:descriptor:com.tectonic.ui:podCount"
  status:
  - description: "kafka实例个数"
    displayName: 集群大小
    path: {kafka.replicas}
    restriction:
      scenes:
       - CCE
    x-descriptors:
      - "urn:alm:descriptor:com.tectonic.ui:podCount"
```
表4descriptors配置 
| 参数名称          | 参数描述                                                                               | 必填 |
|:---|:---|:---|
| displayName:  | 控件显示名称                                                                             | 是  |
| description   | 控件显示描述                                                                             | 是  |
| path          | 控件对应字段，描述的对象上字段的点分隔路径，例如globalConfig1.field1                                       | 是  |
| restriction   | 如果不同的部署的场景需要不同的控件配置，可配置此字段，支持CCE、UCS两种配置，分别表示云容器引擎和华为云UCS场景                        | 否  |
| x-descriptors | 控件类型，具体参考[配置表单控件](https://support.huaweicloud.com/devg-osc/osc_ss_0043.html)了解相关配置 | 是  |
   
 #### versionDefinition
实例版本定义配置是在csd文件中配置versionDefinition。
- versionDefinition配置tag样例如下。
  ```
  versionDefinition:
    mode: tag
    path: spec.kafka.image
    tags:    
      - 1.1.1
      - 2.2.2
      - 3.3.3
      - 9.9.9
  ```
  

- versionDefinition配置url样例如下。
  ```
  versionDefinition:
    mode: url
    path: spec.kafka.image
    tags:
      - 1.1.1
      - 2.2.2
      - 3.3.3
      - 9.9.9
  ```
  
```
defaultConfiguration: |-{
        ....
        ...
        "spec": {
          "kafka": {
            "config": {
            },
            "image": "example:1.1.1"
            "nodeIps": [],
            "nodeSelector": {},
            "podAntiAffinity": true,
            "ports": {
              "bootstrapServer": 9092,
              "prometheus": 9404
            },
            "replicas": 3,
            "storageSize": "8Gi"
          }
        }
      }
```
表5versionDefiniton配置 
| 参数名称        | 参数描述                                                                                                                                                                                          | 参数示例                                                                                                                                                                                                                                                                                                                                                                                                  | 必填                            |
|:---|:---|:---|:---|
| description | 单击升级时的提示信息，知会用户进行实例升级的注意事项                                                                                                                                                                    | 您可以直接升级到最新版本，升级期间会发生5s之内的连接闪断，请确认应用程序具备重连机制                                                                                                                                                                                                                                                                                                                                                           | 否                             |
| mode        | 实例的镜像格式，当前仅支持url、tag这两种格式                                                                                                                                                                     | 取值范围固定为\[url、tag\] - mode配置为url，则会将上述所示defaultConfiguration字段下的"image"字段的值替换为"example:2.2.2"    - mode配置为tag后，则会将上述所示defaultConfiguration字段下的"image"字段的值替换为"2.2.2"   | 必填, 当mode配置之后，path和tags就成了必填项 |
| path        | 实例镜像替换路径，位于defaultConfiguration字段下的值                                                                                                                                                          | 例如，path值配置为"spec.kafka.image"，则需要替换的值是"example:1.1.1"                                                                                                                                                                                                                                                                                                                                                 | 必填                            |
| tags        | 实例镜像tag版本号列表。建议使用引号，否则YAML会将类似2.0的tag版本号识别为浮点数。 注意： 配置在tags下的实例版本号默认都是兼容的实例版本，即这些版本之间能进行互相升级。不兼容的版本号配置在tags列表下会造成升级完成之后实例功能有问题。 | 以实例镜像文件为test-x86_64-2.0.1.20210929123638.tar为例, 实例镜像文件通过docker load -i test-x86_64-2.0.1.20210929123638.tar执行完成之后，会在控制台回显如下信息： Loaded image: test-x86_64:2.0.1.20210929123638 则tag版本号为2.0.1.20210929123638，如果有多个版本镜像，则都可以通过此方式获取tag版本号， 然后将这些tag版本号配置在tags下面                                              | 必填                            |
   
![](https://support.huaweicloud.com/devg-osc/public_sys-resources/caution_3.0-zh-cn.png)
对于lifecycle文件中配置了upgrade字段的服务包，需要确保versionDefinition字段与被升级的operator的所管理的实例相兼容，否则会导致上传服务包或升级服务operator失败，具体规则如下：
1. 在上传服务包阶段，upgrade.replaces字段指定的被升级operator的versionDefinition字段为空时，允许上传服务包；不为空时，新的versionDefinition.tags需要与其有交集才能发布。
2. 在服务operator升级阶段，被升级的operator当前管理的实例版本必须都在新的versionDefinition.tags列表中，否则不允许升级，需要确认新版本的operator是否能够管理这些实例，如果可以，则修改versionDefinition后重新上传服务包，否则需要删除不兼容的实例后再升级。
**示例：** csd.yaml完整示例，以kafka为例。
```
apiVersion: osc.io/v1beta1
kind: CustomServiceDefinition
metadata:
  name: kafka-csd
spec:
  # 通过CRDRef将此CSD跟同一文件夹下的某个CRD相关联
  CRDRef:
    apiVersion: apiextensions.k8s.io/v1beta1
    kind: CustomResourceDefinition
    metadata:
      name: kafkas.osc.huawei.com
  
  # CRD显示名字
  displayName: kafka
  # CRD 描述
  description: kafka Description
  # CRD的角色
  role: serviceEntity
  # 公共能力引用（只针对平台能力引用）
  capabilityRequirements:
    - apiVersion: osc.io/v1             # 引用平台监控能力
      kind: MonitorConfig
      defaultPath: vendor/monitor_config.yaml
    - apiVersion: osc.io/v1        # 引用平台日志能力
      kind: LogConfig
      defaultPath: vendor/log_config.yaml
   
      
      
  # 服务依赖
  serviceEntityDependencies:
    - service: rdsService
      apiVersion: rds.io/v1alpha1     # 依赖operator格式的RDS
      kind: rds
      defaultPath: vendor/rds_provider.yaml
    - service: redisService                       # 依赖Helm格式的redisService
      defaultPath: vendor/redis_service_values.yaml # redis的values.yaml文件
  # UI控件
  descriptors:
    spec:
      - description: ""
        displayName: ""
        path: {crd-name.replicas}
        x-descriptors:
          - "urn:alm:descriptor:com.tectonic.ui:podCount"
    status:
      - description: ""
        displayName: ""
        path: {crd-name.replicas}
        x-descriptors:
          - "urn:alm:descriptor:com.tectonic.ui:podCount"
  # CRD对应的CR样例
  defaultConfiguration: |-{
        "apiVersion": "osc.huawei.com/v1",
        "kind": "Kafka",
        "metadata": {
          "annotations": {
            "osc.io/occupied-port": "135,139"
          },
          "name": "kafka-sample",
          "namespace": "kfk",
          "finalizers": [
            "kafka.finalizers.osc.huawei.com"
          ]
        },
        "spec": {
          "kafka": {
            "config": {
            },
            "image": "xxx/xx/aa:1.0"
            "nodeIps": [],
            "nodeSelector": {},
            "podAntiAffinity": true,
            "ports": {
              "bootstrapServer": 9092,
              "prometheus": 9404
            },
            "replicas": 3,
            "storageSize": "8Gi"
          }
        }
      }
  # 服务实例升级
  versionDefinition:
    description: 您可以直接升级到最新版本，升级期间会发生5s之内的连接闪断，请确认应用程序具备重连机制
    mode: url
    path: spec.image
    tags:
      - "2.7.0"
      - "2.7.1"
      - "2.7.2"
```
