Version: v1.0

Crossplane

云服务是应用程序的一部分。

云服务是 Component 还是 Trait?

可以考虑以下做法:

  • 使用 ComponentDefinition 的场景:
    • 你想要允许最终用户明确声明云服务的实例并使用它,并在删除应用程序时释放该实例。
  • 使用 TraitDefinition 的场景:
    • 你不想让最终用户拥有声明或发布云服务的任何控制权,而只想给他们消费云服务,甚至可以由其他系统管理的云服务的方式。在这种情况下,会广泛使用 Service Binding 特性。

在本文档中,我们将以阿里云的 RDS(关系数据库服务)和阿里云的 OSS(对象存储服务)为例。在单个应用程序中,它们是 Traits,在多个应用程序中,它们是 Components。此机制与其他云提供商相同。

安装和配置 Crossplane

KubeVela 使用 Crossplane 作为云服务提供商。请参阅 Installation 安装 Crossplane Alibaba provider v0.5.0。

如果你想配置任何其他 Crossplane providers,请参阅 Crossplane Select a Getting Started Configuration

  1. $ kubectl crossplane install provider crossplane/provider-alibaba:v0.5.0
  2. # 注意这里的 xxx 和 yyy 是你自己云资源的 AccessKey 和 SecretKey。
  3. $ kubectl create secret generic alibaba-account-creds -n crossplane-system --from-literal=accessKeyId=xxx --from-literal=accessKeySecret=yyy
  4. $ kubectl apply -f provider.yaml

provider.yaml 如下。

  1. apiVersion: v1
  2. kind: Namespace
  3. metadata:
  4. name: crossplane-system
  5. ---
  6. apiVersion: alibaba.crossplane.io/v1alpha1
  7. kind: ProviderConfig
  8. metadata:
  9. name: default
  10. spec:
  11. credentials:
  12. source: Secret
  13. secretRef:
  14. namespace: crossplane-system
  15. name: alibaba-account-creds
  16. key: credentials
  17. region: cn-beijing

注意:我们目前仅使用阿里提供的 Crossplane。但是在不久的将来,我们将使用 Crossplane 作为 Kubernetes 的云资源供应商。

注册 ComponentDefinition 和 TraitDefinition

注册 ComponentDefinition alibaba-rds 为 RDS 云资源生产者

将工作负载类型 alibaba-rds 注册到 KubeVela。

  1. apiVersion: core.oam.dev/v1beta1
  2. kind: ComponentDefinition
  3. metadata:
  4. name: alibaba-rds
  5. namespace: vela-system
  6. annotations:
  7. definition.oam.dev/description: "Alibaba Cloud RDS Resource"
  8. spec:
  9. workload:
  10. definition:
  11. apiVersion: database.alibaba.crossplane.io/v1alpha1
  12. kind: RDSInstance
  13. schematic:
  14. cue:
  15. template: |
  16. output: {
  17. apiVersion: "database.alibaba.crossplane.io/v1alpha1"
  18. kind: "RDSInstance"
  19. spec: {
  20. forProvider: {
  21. engine: parameter.engine
  22. engineVersion: parameter.engineVersion
  23. dbInstanceClass: parameter.instanceClass
  24. dbInstanceStorageInGB: 20
  25. securityIPList: "0.0.0.0/0"
  26. masterUsername: parameter.username
  27. }
  28. writeConnectionSecretToRef: {
  29. namespace: context.namespace
  30. name: parameter.secretName
  31. }
  32. providerConfigRef: {
  33. name: "default"
  34. }
  35. deletionPolicy: "Delete"
  36. }
  37. }
  38. parameter: {
  39. // +usage=RDS engine
  40. engine: *"mysql" | string
  41. // +usage=The version of RDS engine
  42. engineVersion: *"8.0" | string
  43. // +usage=The instance class for the RDS
  44. instanceClass: *"rds.mysql.c1.large" | string
  45. // +usage=RDS username
  46. username: string
  47. // +usage=Secret name which RDS connection will write to
  48. secretName: string
  49. }

注册 ComponentDefinition alibaba-oss 为 OSS 云资源生产者

  1. apiVersion: core.oam.dev/v1beta1
  2. kind: ComponentDefinition
  3. metadata:
  4. name: alibaba-oss
  5. namespace: vela-system
  6. annotations:
  7. definition.oam.dev/description: "Alibaba Cloud RDS Resource"
  8. spec:
  9. workload:
  10. definition:
  11. apiVersion: oss.alibaba.crossplane.io/v1alpha1
  12. kind: Bucket
  13. schematic:
  14. cue:
  15. template: |
  16. output: {
  17. apiVersion: "oss.alibaba.crossplane.io/v1alpha1"
  18. kind: "Bucket"
  19. spec: {
  20. name: parameter.name
  21. acl: parameter.acl
  22. storageClass: parameter.storageClass
  23. dataRedundancyType: parameter.dataRedundancyType
  24. writeConnectionSecretToRef: {
  25. namespace: context.namespace
  26. name: parameter.secretName
  27. }
  28. providerConfigRef: {
  29. name: "default"
  30. }
  31. deletionPolicy: "Delete"
  32. }
  33. }
  34. parameter: {
  35. // +usage=OSS bucket name
  36. name: string
  37. // +usage=The access control list of the OSS bucket
  38. acl: *"private" | string
  39. // +usage=The storage type of OSS bucket
  40. storageClass: *"Standard" | string
  41. // +usage=The data Redundancy type of OSS bucket
  42. dataRedundancyType: *"LRS" | string
  43. // +usage=Secret name which RDS connection will write to
  44. secretName: string
  45. }

引用 Secret 注册 ComponentDefinition webconsumer

  1. apiVersion: core.oam.dev/v1beta1
  2. kind: ComponentDefinition
  3. metadata:
  4. name: webconsumer
  5. annotations:
  6. definition.oam.dev/description: A Deployment provides declarative updates for Pods and ReplicaSets
  7. spec:
  8. workload:
  9. definition:
  10. apiVersion: apps/v1
  11. kind: Deployment
  12. schematic:
  13. cue:
  14. template: |
  15. output: {
  16. apiVersion: "apps/v1"
  17. kind: "Deployment"
  18. spec: {
  19. selector: matchLabels: {
  20. "app.oam.dev/component": context.name
  21. }
  22. template: {
  23. metadata: labels: {
  24. "app.oam.dev/component": context.name
  25. }
  26. spec: {
  27. containers: [{
  28. name: context.name
  29. image: parameter.image
  30. if parameter["cmd"] != _|_ {
  31. command: parameter.cmd
  32. }
  33. if parameter["dbSecret"] != _|_ {
  34. env: [
  35. {
  36. name: "username"
  37. value: dbConn.username
  38. },
  39. {
  40. name: "endpoint"
  41. value: dbConn.endpoint
  42. },
  43. {
  44. name: "DB_PASSWORD"
  45. value: dbConn.password
  46. },
  47. ]
  48. }
  49. ports: [{
  50. containerPort: parameter.port
  51. }]
  52. if parameter["cpu"] != _|_ {
  53. resources: {
  54. limits:
  55. cpu: parameter.cpu
  56. requests:
  57. cpu: parameter.cpu
  58. }
  59. }
  60. }]
  61. }
  62. }
  63. }
  64. }
  65. parameter: {
  66. // +usage=Which image would you like to use for your service
  67. // +short=i
  68. image: string
  69. // +usage=Commands to run in the container
  70. cmd?: [...string]
  71. // +usage=Which port do you want customer traffic sent to
  72. // +short=p
  73. port: *80 | int
  74. // +usage=Referred db secret
  75. // +insertSecretTo=dbConn
  76. dbSecret?: string
  77. // +usage=Number of CPU units for the service, like `0.5` (0.5 CPU core), `1` (1 CPU core)
  78. cpu?: string
  79. }
  80. dbConn: {
  81. username: string
  82. endpoint: string
  83. password: string
  84. }

关键词是 annotation // + insertSecretTo = dbConn,KubeVela 将知道该参数是 K8s 的 secret,它将解析该 secret 并将数据绑定到 CUE 接口 dbConn 中。

output 可以引用 dbConn 获取数据。dbConn 的名称没有限制。 关键词是 +insertSecretTo,它定义了数据绑定机制。以上只是一个例子。

准备 TraitDefinition service-binding 进行 env-secret mapping

至于应用程序中的数据绑定,KubeVela 建议定义一个 trait 以完成工作。我们已经准备了一个方便的 trait。此 trait 非常适合将资源的信息绑定到 pod spec 的环境变量中.

  1. apiVersion: core.oam.dev/v1beta1
  2. kind: TraitDefinition
  3. metadata:
  4. annotations:
  5. definition.oam.dev/description: "binding cloud resource secrets to pod env"
  6. name: service-binding
  7. spec:
  8. appliesToWorkloads:
  9. - webservice
  10. - worker
  11. schematic:
  12. cue:
  13. template: |
  14. patch: {
  15. spec: template: spec: {
  16. // +patchKey=name
  17. containers: [{
  18. name: context.name
  19. // +patchKey=name
  20. env: [
  21. for envName, v in parameter.envMappings {
  22. name: envName
  23. valueFrom: {
  24. secretKeyRef: {
  25. name: v.secret
  26. if v["key"] != _|_ {
  27. key: v.key
  28. }
  29. if v["key"] == _|_ {
  30. key: envName
  31. }
  32. }
  33. }
  34. },
  35. ]
  36. }]
  37. }
  38. }
  39. parameter: {
  40. // +usage=The mapping of environment variables to secret
  41. envMappings: [string]: [string]: string
  42. }

借助这种 service-binding trait,开发人员可以显式设置参数 envMappings,以映射所有环境变量。例子如下。

  1. ...
  2. traits:
  3. - type: service-binding
  4. properties:
  5. envMappings:
  6. # environments refer to db-conn secret
  7. DB_PASSWORD:
  8. secret: db-conn
  9. key: password # 1) If the env name is different from secret key, secret key has to be set.
  10. endpoint:
  11. secret: db-conn # 2) If the env name is the same as the secret key, secret key can be omitted.
  12. username:
  13. secret: db-conn
  14. # environments refer to oss-conn secret
  15. BUCKET_NAME:
  16. secret: oss-conn
  17. key: Bucket
  18. ...

你可以通过查看 the end user usage workflow 了解其使用方式。