diff --git a/examples/cronhpa/cronhpa-sample.yaml b/examples/cronhpa/cronhpa-sample.yaml new file mode 100644 index 00000000..c2a7b566 --- /dev/null +++ b/examples/cronhpa/cronhpa-sample.yaml @@ -0,0 +1,44 @@ +apiVersion: core.oam.dev/v1beta1 +kind: Application +metadata: + name: helloworld +spec: + components: + - name: helloworld + type: webservice + properties: + cpu: "0.5" + exposeType: ClusterIP + image: oamdev/hello-world + memory: 1024Mi + ports: + - expose: true + port: 80 + protocol: TCP + traits: + - type: cronhpa + properties: + targetAPIVersion: apps/v1 + targetKind: Deployment + excludeDates: + - '* * * 15 11 *' + - '* * * * * 5' + hpaJobs: + - name: scale-down + runOnce: false + schedule: "30 */1 * * * *" + targetSize: 1 + - name: scale-up + runOnce: false + schedule: "0 */1 * * * *" + targetSize: 3 + policies: + - name: apply-once + type: apply-once + properties: + enable: true + rules: + - strategy: + path: ["spec.replicas"] + selector: + resourceTypes: ["Deployment","StatefulSet"] \ No newline at end of file diff --git a/experimental/addons/cronhpa/README.md b/experimental/addons/cronhpa/README.md new file mode 100644 index 00000000..fbffdcd7 --- /dev/null +++ b/experimental/addons/cronhpa/README.md @@ -0,0 +1,87 @@ +# cronhpa + +This addon is built based [kubernetes-cronhpa-controller](https://github.com/AliyunContainerService/kubernetes-cronhpa-controller/) + +## install +```shell +vela addon enable cronhpa +``` + +## usage + +This addon exposes one Trait "cronhpa", it provides cron horizontal pod autoscaler controller using crontab like scheme. + +### properties + +```shell + +# properties ++------------------+---------------------------------------------------------------------------------------------+-----------------------+----------+------------+ +| NAME | DESCRIPTION | TYPE | REQUIRED | DEFAULT | ++------------------+---------------------------------------------------------------------------------------------+-----------------------+----------+------------+ +| targetAPIVersion | Specify the apiVersion of scale target. | string | false | apps/v1 | +| targetKind | Specify the kind of scale target. | string | false | Deployment | +| excludeDates | Specify the job will skip the execution when the dates is matched. The minimum unit is day. | []string | false | | +| hpaJobs | Specify multiple cron hpa jobs. | [[]hpaJobs](#hpajobs) | true | | ++------------------+---------------------------------------------------------------------------------------------+-----------------------+----------+------------+ + + +## hpaJobs ++------------+------------------------------------------------------------------------------------------------------+--------+----------+---------+ +| NAME | DESCRIPTION | TYPE | REQUIRED | DEFAULT | ++------------+------------------------------------------------------------------------------------------------------+--------+----------+---------+ +| name | Specify the name of hpa job, should be unique in one cronhpa spec. | string | true | | +| schedule | Specify the cron schedule strategy. | string | true | | +| targetSize | Specify the size you desired to scale when the scheduled time arrive. | int | true | | +| runOnce | Specify if this job need executed repeatly, if runOnce is true then the job will only run and exit | bool | false | false | +| | after the first execution. | | | | ++------------+------------------------------------------------------------------------------------------------------+--------+----------+---------+ +``` + +sample as below: +```yaml +apiVersion: core.oam.dev/v1beta1 +kind: Application +metadata: + name: helloworld +spec: + components: + - name: helloworld + type: webservice + properties: + cpu: "0.5" + exposeType: ClusterIP + image: oamdev/hello-world + memory: 1024Mi + ports: + - expose: true + port: 80 + protocol: TCP + traits: + - type: cronhpa + properties: + targetAPIVersion: apps/v1 + targetKind: Deployment + excludeDates: + - '* * * 15 11 *' + - '* * * * * 5' + hpaJobs: + - name: scale-down + runOnce: false + schedule: "30 */1 * * * *" + targetSize: 1 + - name: scale-up + runOnce: false + schedule: "0 */1 * * * *" + targetSize: 3 + policies: + - name: apply-once + type: apply-once + properties: + enable: true + rules: + - strategy: + path: ["spec.replicas"] + selector: + resourceTypes: ["Deployment","StatefulSet"] +``` \ No newline at end of file diff --git a/experimental/addons/cronhpa/definitions/cronhpa.cue b/experimental/addons/cronhpa/definitions/cronhpa.cue new file mode 100644 index 00000000..090942a4 --- /dev/null +++ b/experimental/addons/cronhpa/definitions/cronhpa.cue @@ -0,0 +1,70 @@ +cronhpa: { + type: "trait" + alias: "cronhpa" + annotations: {} + attributes: { + appliesToWorkloads: [ + "deployments.apps", + "statefulsets.apps", + ] + conflictsWith: [] + podDisruptive: false + workloadRefPath: "" + } + description: "kubernetes cron horizontal pod autoscaler trait" + labels: {} +} + +template: { + outputs: { + cronhpa: { + apiVersion: "autoscaling.alibabacloud.com/v1beta1" + kind: "CronHorizontalPodAutoscaler" + metadata: { + labels: "controller-tools.k8s.io": "1.0" + name: context.name + } + spec: { + scaleTargetRef: { + apiVersion: parameter.targetAPIVersion + kind: parameter.targetKind + name: context.name + } + if parameter.excludeDates != _|_ { + excludeDates: [ + for d in parameter.excludeDates { + d + }, + ] + } + jobs: [ + for s in parameter.hpaJobs { + name: s.name + schedule: s.schedule + targetSize: s.targetSize + runOnce: s.runOnce + }, + ] + } + } + } + parameter: { + // +usage=Specify the apiVersion of scale target + targetAPIVersion: *"apps/v1" | string + // +usage=Specify the kind of scale target + targetKind: *"Deployment" | string + // +usage=Specify the job will skip the execution when the dates is matched. The minimum unit is day. + excludeDates?: [...string] + // +usage=Specify multiple cron hpa jobs + hpaJobs: [...{ + // +usage=Specify the name of hpa job, should be unique in one cronhpa spec + name: string + // +usage=Specify the cron schedule strategy + schedule: string + // +usage=Specify the size you desired to scale when the scheduled time arrive + targetSize: int + // +usage=Specify if this job need executed repeatly, if runOnce is true then the job will only run and exit after the first execution. + runOnce: *false | bool + }] + } +} diff --git a/experimental/addons/cronhpa/metadata.yaml b/experimental/addons/cronhpa/metadata.yaml new file mode 100644 index 00000000..5d68ef3a --- /dev/null +++ b/experimental/addons/cronhpa/metadata.yaml @@ -0,0 +1,9 @@ +description: An cron hpa addon for KubeVela. +icon: "" +invisible: false +name: cronhpa +tags: + - Scaler + - AutoScaler + - Cron +version: 1.4.1 diff --git a/experimental/addons/cronhpa/parameter.cue b/experimental/addons/cronhpa/parameter.cue new file mode 100644 index 00000000..e3bc4950 --- /dev/null +++ b/experimental/addons/cronhpa/parameter.cue @@ -0,0 +1,29 @@ +parameter: { + // +usage=Specify the image registry of cronhpa controller, eg. "registry.aliyuncs.com/acs" + registry: *"registry.aliyuncs.com" | string + // +usage=Specify the image repository of cronhpa controller, eg. "kubernetes-cronhpa-controller" + repository: *"acs/kubernetes-cronhpa-controller" | string + // +usage=Specify the image tag of cronhpa controller, eg. "v1.4.1" + imageTag: *"v1.4.1-b8cd52c-aliyun" | string + // +usage=Specify the names of imagePullSecret for private image registry, eg. "{a,b,c}" + imagePullSecrets?: [...string] + // +usage=Specify the imagePullPolicy of the image + imagePullPolicy: *"Always" | string + // +usage=Specify the replicas. + replicas: *1 | int + // +usage=Specify the namespace to install + namespace: *"vela-system" | string + // +usage=Specify the clusters to install + clusters?: [...string] + // +usage=Specifies the attributes of the resource required + resources: { + requests: { + cpu: *1 | number + memory: *"100Mi" | string + } + limits: { + cpu: *1 | number + memory: *"100Mi" | string + } + } +} diff --git a/experimental/addons/cronhpa/resources/component/cronController.cue b/experimental/addons/cronhpa/resources/component/cronController.cue new file mode 100644 index 00000000..4ff5bfd7 --- /dev/null +++ b/experimental/addons/cronhpa/resources/component/cronController.cue @@ -0,0 +1,54 @@ +package main + +cronController: { + name: "cron-controller" + type: "webservice" + properties: { + image: parameter.registry + "/" + parameter.repository + ":" + parameter.imageTag + imagePullPolicy: parameter.imagePullPolicy + if parameter.imagePullSecrets != _|_ { + imagePullSecrets: [ for v in parameter.imagePullSecrets { + v + }, + ] + } + env: [ + { + name: "TZ" + value: '"Asia/Shanghai"' + }, + ] + } + traits: [ + { + type: "scaler" + properties: { + replicas: parameter.replicas + } + }, { + type: "resource" + properties: { + requests: { + cpu: parameter.resources.requests.cpu + memory: parameter.resources.requests.memory + } + limits: { + cpu: parameter.resources.limits.cpu + memory: parameter.resources.limits.memory + } + } + }, { + type: "labels" + properties: { + "app": "kubernetes-cronhpa-controller" + "controller-tools.k8s.io": '2.0' + } + }, { + type: "service-account" + properties: { + create: true + name: "kubernetes-cronhpa-controller" + } + }, + ] +} diff --git a/experimental/addons/cronhpa/resources/crd/cronhpa.cue b/experimental/addons/cronhpa/resources/crd/cronhpa.cue new file mode 100644 index 00000000..57f46e79 --- /dev/null +++ b/experimental/addons/cronhpa/resources/crd/cronhpa.cue @@ -0,0 +1,119 @@ +package main + +cronhpaCRD: { + apiVersion: "apiextensions.k8s.io/v1beta1" + kind: "CustomResourceDefinition" + metadata: { + annotations: "controller-gen.kubebuilder.io/version": "v0.2.5" + name: "cronhorizontalpodautoscalers.autoscaling.alibabacloud.com" + } + spec: { + group: "autoscaling.alibabacloud.com" + names: { + kind: "CronHorizontalPodAutoscaler" + listKind: "CronHorizontalPodAutoscalerList" + plural: "cronhorizontalpodautoscalers" + shortNames: ["cronhpa"] + singular: "cronhorizontalpodautoscaler" + } + scope: "Namespaced" + validation: openAPIV3Schema: { + properties: { + apiVersion: type: "string" + kind: type: "string" + metadata: type: "object" + spec: { + properties: { + excludeDates: { + items: type: "string" + type: "array" + } + jobs: { + items: { + properties: { + name: type: "string" + runOnce: type: "boolean" + schedule: type: "string" + targetSize: { + format: "int32" + type: "integer" + } + } + required: ["name", "schedule", "targetSize"] + type: "object" + } + type: "array" + } + scaleTargetRef: { + properties: { + apiVersion: type: "string" + kind: type: "string" + name: type: "string" + } + required: ["apiVersion", "kind", "name"] + type: "object" + } + } + required: ["jobs", "scaleTargetRef"] + type: "object" + } + status: { + properties: { + conditions: { + items: { + properties: { + jobId: type: "string" + lastProbeTime: { + format: "date-time" + type: "string" + } + message: type: "string" + name: type: "string" + runOnce: type: "boolean" + schedule: type: "string" + state: type: "string" + targetSize: { + format: "int32" + type: "integer" + } + } + required: ["jobId", "lastProbeTime", "name", "runOnce", "schedule", "state", "targetSize"] + type: "object" + } + type: "array" + } + excludeDates: { + items: type: "string" + type: "array" + } + scaleTargetRef: { + properties: { + apiVersion: type: "string" + kind: type: "string" + name: type: "string" + } + required: ["apiVersion", "kind", "name"] + type: "object" + } + } + type: "object" + } + } + type: "object" + } + version: "v1beta1" + versions: [{ + name: "v1beta1" + served: true + storage: true + }] + } + status: { + acceptedNames: { + kind: "" + plural: "" + } + conditions: [] + storedVersions: [] + } +} diff --git a/experimental/addons/cronhpa/resources/rbac/controller-clusterrole.cue b/experimental/addons/cronhpa/resources/rbac/controller-clusterrole.cue new file mode 100644 index 00000000..ef6f3d1a --- /dev/null +++ b/experimental/addons/cronhpa/resources/rbac/controller-clusterrole.cue @@ -0,0 +1,36 @@ +package main + +controllerClusterRole: { + apiVersion: "rbac.authorization.k8s.io/v1" + kind: "ClusterRole" + metadata: name: "kubernetes-cronhpa-controller-role" + rules: [{ + apiGroups: ["*"] + resources: ["*/scale"] + verbs: ["get", "list", "update"] + }, { + apiGroups: ["extensions"] + resources: ["*"] + verbs: ["get", "list", "watch", "update"] + }, { + apiGroups: ["apps"] + resources: ["*"] + verbs: ["get", "list", "watch", "update"] + }, { + apiGroups: [""] + resources: ["configmaps", "events"] + verbs: ["get", "list", "watch", "create", "update", "patch"] + }, { + apiGroups: ["autoscaling"] + resources: ["horizontalpodautoscalers"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] + }, { + apiGroups: ["autoscaling.alibabacloud.com"] + resources: ["cronhorizontalpodautoscalers", "elasticworkloads"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] + }, { + apiGroups: ["admissionregistration.k8s.io"] + resources: ["mutatingwebhookconfigurations", "validatingwebhookconfigurations"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete", "patch"] + }] +} diff --git a/experimental/addons/cronhpa/resources/rbac/controller-rolebinding.cue b/experimental/addons/cronhpa/resources/rbac/controller-rolebinding.cue new file mode 100644 index 00000000..2ff82834 --- /dev/null +++ b/experimental/addons/cronhpa/resources/rbac/controller-rolebinding.cue @@ -0,0 +1,19 @@ +package main + +controllerRoleBinding: { + apiVersion: "rbac.authorization.k8s.io/v1" + kind: "ClusterRoleBinding" + metadata: { + name: "kubernetes-cronhpa-controller-rolebinding" + } + roleRef: { + apiGroup: "rbac.authorization.k8s.io" + kind: "ClusterRole" + name: "kubernetes-cronhpa-controller-role" + } + subjects: [{ + kind: "ServiceAccount" + name: "kubernetes-cronhpa-controller" + namespace: "kube-system" + }] +} diff --git a/experimental/addons/cronhpa/schemas/cronhpaschema.yaml b/experimental/addons/cronhpa/schemas/cronhpaschema.yaml new file mode 100644 index 00000000..48b2177c --- /dev/null +++ b/experimental/addons/cronhpa/schemas/cronhpaschema.yaml @@ -0,0 +1,131 @@ +- sort: 100 + label: ImagePullPolicy + description: Specify the imagePullPolicy of the image + validate: + required: true + defaultValue: Always + immutable: false + jsonKey: imagePullPolicy + uiType: Input +- sort: 101 + label: ImageTag + description: Specify the image tag of cronhpa controller, eg. "v1.4.1" + validate: + required: true + defaultValue: v1.4.1-b8cd52c-aliyun + immutable: false + jsonKey: imageTag + uiType: Input +- sort: 102 + label: Namespace + description: Specify the namespace to install + validate: + required: true + defaultValue: vela-system + immutable: false + jsonKey: namespace + uiType: Input +- sort: 103 + label: Registry + description: Specify the image registry of cronhpa controller, eg. "registry.aliyuncs.com/acs" + validate: + required: true + defaultValue: registry.aliyuncs.com + immutable: false + jsonKey: registry + uiType: Input +- sort: 104 + label: Replicas + description: Specify the replicas. + validate: + required: true + defaultValue: 1 + immutable: false + jsonKey: replicas + uiType: Number +- sort: 105 + label: Repository + description: Specify the image repository of cronhpa controller, eg. "kubernetes-cronhpa-controller" + validate: + required: true + defaultValue: acs/kubernetes-cronhpa-controller + immutable: false + jsonKey: repository + uiType: Input +- sort: 106 + label: Resources + description: Specifies the attributes of the resource required + validate: + required: true + immutable: false + jsonKey: resources + uiType: Group + subParameters: + - sort: 100 + label: Limits + description: '' + validate: + required: true + immutable: false + jsonKey: limits + uiType: Group + subParameters: + - sort: 100 + label: Cpu + description: '' + validate: + required: true + defaultValue: 1 + immutable: false + jsonKey: cpu + uiType: Number + - sort: 101 + label: Memory + description: '' + validate: + required: true + defaultValue: 100Mi + immutable: false + jsonKey: memory + uiType: Input + - sort: 101 + label: Requests + description: '' + validate: + required: true + immutable: false + jsonKey: requests + uiType: Group + subParameters: + - sort: 100 + label: Cpu + description: '' + validate: + required: true + defaultValue: 1 + immutable: false + jsonKey: cpu + uiType: Number + - sort: 101 + label: Memory + description: '' + validate: + required: true + defaultValue: 100Mi + immutable: false + jsonKey: memory + uiType: Input +- sort: 107 + label: Clusters + description: Specify the clusters to install + validate: + immutable: false + jsonKey: clusters + uiType: Strings +- sort: 108 + label: ImagePullSecrets + description: Specify the names of imagePullSecret for private image registry, eg. "{a,b,c}" + validate: + immutable: false + jsonKey: imagePullSecrets + uiType: Strings \ No newline at end of file diff --git a/experimental/addons/cronhpa/template.cue b/experimental/addons/cronhpa/template.cue new file mode 100644 index 00000000..9ae14ef6 --- /dev/null +++ b/experimental/addons/cronhpa/template.cue @@ -0,0 +1,47 @@ +package main + +output: { + apiVersion: "core.oam.dev/v1beta1" + kind: "Application" + spec: { + components: [ { + type: "k8s-objects" + name: "cronhpa-rbac" + properties: objects: [ + controllerClusterRole, + controllerRoleBinding, + ] + }, + { + type: "k8s-objects" + name: "cronhpa-CRD" + properties: objects: [ + cronhpaCRD, + ] + }, + cronController] + policies: [{ + type: "topology" + name: "deploy-topology" + properties: { + if parameter.clusters != _|_ { + clusters: parameter.clusters + } + if parameter.clusters == _|_ { + clusterLabelSelector: {} + } + namespace: parameter.namespace + } + }, { + type: "garbage-collect" + name: "not-gc-CRD" + properties: { + rules: [{ + selector: resourceTypes: ["CustomResourceDefinition"] + strategy: "never" + }, + ] + } + }] + } +}