From ffa2517c98c7d1fa09ae8a38bc11aa6a40851b35 Mon Sep 17 00:00:00 2001 From: bjwswang Date: Fri, 13 Oct 2023 10:37:43 +0800 Subject: [PATCH] feat: able to automatically build and publish lowcode components Signed-off-by: bjwswang --- Makefile | 11 +- pipeline/lowcode/README.md | 165 ++++++++++++++++++ pipeline/lowcode/chart-template/Chart.yaml | 22 +++ .../chart-template/templates/deployment.yaml | 26 +++ .../chart-template/templates/ingress.yaml | 43 +++++ .../chart-template/templates/portal.yaml | 7 + .../chart-template/templates/service.yaml | 17 ++ pipeline/lowcode/chart-template/values.yaml | 16 ++ pipeline/lowcode/kustomization.yaml | 8 + pipeline/lowcode/pipeline.yaml | 109 ++++++++++++ .../lowcode/sample/install-component.yaml | 12 ++ pipeline/lowcode/sample/pre-publish.yaml | 33 ++++ pipeline/lowcode/sample/publish.yaml | 48 +++++ pipeline/lowcode/sample/schema.json | 118 +++++++++++++ pipeline/lowcode/task-build-chart.yaml | 99 +++++++++++ pipeline/lowcode/task-build-image.yaml | 94 ++++++++++ pipeline/lowcode/task-fetch-source.yaml | 50 ++++++ 17 files changed, 877 insertions(+), 1 deletion(-) create mode 100644 pipeline/lowcode/README.md create mode 100644 pipeline/lowcode/chart-template/Chart.yaml create mode 100644 pipeline/lowcode/chart-template/templates/deployment.yaml create mode 100644 pipeline/lowcode/chart-template/templates/ingress.yaml create mode 100644 pipeline/lowcode/chart-template/templates/portal.yaml create mode 100644 pipeline/lowcode/chart-template/templates/service.yaml create mode 100644 pipeline/lowcode/chart-template/values.yaml create mode 100644 pipeline/lowcode/kustomization.yaml create mode 100644 pipeline/lowcode/pipeline.yaml create mode 100644 pipeline/lowcode/sample/install-component.yaml create mode 100644 pipeline/lowcode/sample/pre-publish.yaml create mode 100644 pipeline/lowcode/sample/publish.yaml create mode 100644 pipeline/lowcode/sample/schema.json create mode 100644 pipeline/lowcode/task-build-chart.yaml create mode 100644 pipeline/lowcode/task-build-image.yaml create mode 100644 pipeline/lowcode/task-fetch-source.yaml diff --git a/Makefile b/Makefile index 7d1c1de4..27b1327e 100644 --- a/Makefile +++ b/Makefile @@ -263,4 +263,13 @@ catalog-push: ## Push a catalog image. # Verify code validity .PHONY: verify verify: - @hack/verify-all.sh \ No newline at end of file + @hack/verify-all.sh + +.PHONY: deploy-lowcode +deploy-lowcode: kustomize + mkdir -p out && cd pipeline/lowcode && tar -zcf ../../out/template.tgz chart-template + kubectl create -nyunti-system --dry-run=client configmap chart-template-cm --from-file=./out/template.tgz -oyaml | kubectl apply -f - + $(KUSTOMIZE) build pipeline/lowcode | kubectl apply -f - +rerun: + kubectl delete -f pipeline/lowcode/sample/publish.yaml + kubectl apply -f pipeline/lowcode/sample/publish.yaml \ No newline at end of file diff --git a/pipeline/lowcode/README.md b/pipeline/lowcode/README.md new file mode 100644 index 00000000..a2e18268 --- /dev/null +++ b/pipeline/lowcode/README.md @@ -0,0 +1,165 @@ +# Lowcode pipelines + +> NOTE: All lowcode resources managed under namespace `yunti-system` by default + +Here we use [tekton](https://tekton.dev/) to build and publish a lowcode component. The overall workflow is: + +1. fetch source from minio +2. build dockerimage for lowcode component and push it to docker registry(dockerhub/private registry) +3. build helm charts for lowcode component with pre-defined [chart template](./chart-template/) and push this component to a private component repository(chartmuseum) + + +## Dependent components + +- Component [Minio](https://github.com/kubebb/components/tree/main/charts/minio) to store lowcode component's source code +- Component [Tekton](https://github.com/kubebb/components/tree/main/charts/tekton-operator) to run the workflow + +## Pipeline + +We defined a [pipeline lowcode-publish](./pipeline.yaml) which contains 3 sequencial tasks: + +- Task [fetch-source](./task-fetch-source.yaml) +- Task [build-image](./task-build-image.yaml) +- Task [build-chart](./task-build-chart.yaml) + + +### Parameters + +| Parameter | Default | Description | +|---------------|----------------|----------------| +| SOURCE_MINIO_HOST | my-minio.kubebb-addons.svc.cluster.local | minio host/domain to fetch | +| SOURCE_PATH | "" | The path where stores the component lowcode materials | +| SOURCE_SCHEMA_PATH | "schema.json" | The relative path of schema json file to `bucket/object/` | +| SOURCE_MINIO_ACCESS_KEY | "" | | +| SOURCE_MINIO_SECRET_KEY | "" | | +| APP_IMAGE | "" | The component's image name along with tag | +| REPOSITORY_URL | http://chartmuseum.kubebb-addons.svc.cluster.local:8080 | The url for the component repository | +| REPOSITORY_USER | "" | The username for repository auth | +| REPOSITORY_PASSWORD | "" | The password for the repository auth | + +### Chart render + +We use this [template](./chart-template/Chart.yaml) to render the chart.Below is the relevant mappings +| Key in schema or others | Key in Chart | Description | +|---------------|-----------------------------|----------------| +| Schema .version | Chart.yaml version | Component portal entry and path | +| params IMAGE | values.yaml image | Component portal entry and path | +| Schema .meta.namespace | Chart.yaml name | Component name | +| Schema .meta.name | Chart.yaml annotations.core.kubebb.k8s.com.cn/displayname | Component display name | +| Schema .meta.description | Chart.yaml description | Component's description | +| Schema .meta.git_url | Chart.yaml sources | Component's git url | +| Schema .meta.basename | templates.portal.yaml .spec.entry & .spec.path | Component portal entry and path | + +## Sample + +Clone this project: + +```shell +git clone https://github.com/kubebb/core.git +cd core +``` + +### Prerequsites + +0. deploy kubebb + +Follow [official document](https://kubebb.github.io/website/docs/quick-start/core_quickstart) + +1. deploy minio + +```shell + kubectl apply -f https://raw.githubusercontent.com/kubebb/components/main/examples/minio/componentplan.yaml +``` + +2. deploy chartmuseum + +```shell + kubectl apply -f https://raw.githubusercontent.com/kubebb/components/main/examples/chartmuseum/componentplan.yaml +``` + +3. deploy tekton-operator with https://github.com/kubebb/components/tree/main/examples/tekton-operator + +```shell + kubectl apply -f https://raw.githubusercontent.com/kubebb/components/main/examples/tekton-operator/componentplan.yaml +``` + +4. deploy the lowcode pipelines + +```shell +make deploy-lowcode +``` + +### Build component `hello-world` + +#### 1. Upload component's schema to minio + +- Bucket: `yunti` +- Object: `hello-world` + +Upload `pipeline/lowcode/sample/schema.json` under `yunti/hello-world` + + +#### 2. Apply resources to pre-publish + +1. Update dockerconfig + +To push image to image registry,we mount this [`dockerconfig-secret`](./sample/pre-publish.yaml#1) in the kaniko pod. So make sure you have created this secret with the correct auth info. + +2. Update Dockerfile + +This pipelinerun use `dockerfile` configured in configmap [dockerfile-cm](./sample/pre-publish.yaml#13). Update according to your need. + +3. Update pvc + +This pipelinerun requires a PVC `sample-publish-ws-pvc` to store source and artifacts. You need to update it based on your environment. + +4. Apply this [pre-publish](./sample/pre-publish.yaml) + +```shell + kubectl apply -f pipeline/lowcode/sample/pre-publish.yaml +``` + +#### 4. Apply resources(pipelinerun) to build and publish this component + +```shell + kubectl apply -f pipeline/lowcode/sample/publish.yaml +``` + +#### 5. Watch pipelinerun + +```shell + kubectl get pods --watch -nyunti-system +``` + + +#### 6. Get the component + +> Make sure you have add the above chartmuseum repo .In case you didnt, you can add it with this [componentplan](https://github.com/kubebb/components/blob/main/examples/chartmuseum/repository_chartmuseum.yaml) + +```shell +❯ kubectl get components -nkubebb-system -l kubebb.component.repository=chartmuseum +NAME AGE +chartmuseum.hello-world 4m18s +``` + +#### 7. Deploy the above component + +```shell + kubectl apply -f pipeline/lowcode/sample/install-component.yaml +``` + +Check the install status: + +```shell +kubectl get componentplan hello-world -oyaml +``` + +When `InstallSuccess`, you can access this component by: + +1. do port-forward + +```shell + kubectl port-forward svc/hello-world 8066:8066 +``` + +2. access in browser `http://localhost:8066/umi-demo-public` diff --git a/pipeline/lowcode/chart-template/Chart.yaml b/pipeline/lowcode/chart-template/Chart.yaml new file mode 100644 index 00000000..30a7de25 --- /dev/null +++ b/pipeline/lowcode/chart-template/Chart.yaml @@ -0,0 +1,22 @@ +apiVersion: v2 +name: TEMPLATE_NAMESPACE +annotations: + core.kubebb.k8s.com.cn/displayname: TEMPLATE_NAME +description: TEMPLATE_DESCRIPTION +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: TEMPLATE_VERSION + +sources: + - TEMPLATE_GIT_URL + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application diff --git a/pipeline/lowcode/chart-template/templates/deployment.yaml b/pipeline/lowcode/chart-template/templates/deployment.yaml new file mode 100644 index 00000000..39944f81 --- /dev/null +++ b/pipeline/lowcode/chart-template/templates/deployment.yaml @@ -0,0 +1,26 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: TEMPLATE_NAMESPACE + namespace: {{ .Release.Namespace }} + labels: + app: TEMPLATE_NAMESPACE +spec: + selector: + matchLabels: + app: TEMPLATE_NAMESPACE + replicas: 1 + template: + metadata: + labels: + app: TEMPLATE_NAMESPACE + spec: + containers: + - image: {{ .Values.image }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + name: TEMPLATE_NAMESPACE + ports: + - containerPort: 80 + protocol: TCP + resources: {{ toYaml .Values.resources | nindent 10 }} + terminationGracePeriodSeconds: 30 \ No newline at end of file diff --git a/pipeline/lowcode/chart-template/templates/ingress.yaml b/pipeline/lowcode/chart-template/templates/ingress.yaml new file mode 100644 index 00000000..a3ccf88b --- /dev/null +++ b/pipeline/lowcode/chart-template/templates/ingress.yaml @@ -0,0 +1,43 @@ +{{- if .Values.ingress.enable }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + description: TEMPLATE_NAMESPACE-ingress + displayName: TEMPLATE_NAMESPACE-ingress + httpSend: / + ingress-lb: {{ .Values.ingress.ingressClassName }} + kubernetes.io/ingress.class: {{ .Values.ingress.ingressClassName }} + nginx.ingress.kubernetes.io/configuration-snippet: | + proxy_cache static-cache; + proxy_cache_valid 404 10m; + proxy_cache_use_stale error timeout updating http_404 http_500 http_502 http_503 http_504; + proxy_cache_bypass $http_x_purge; + add_header X-Cache-Status $upstream_cache_status; # check X-Cache-Status to see if it's HIT + rewrite ^/(TEMPLATE_NAMESPACE-apis)(/|$)(.*)$ /$3 break; + nginx.ingress.kubernetes.io/enable-access-log: "false" + nginx.ingress.kubernetes.io/enable-rewrite-log: "false" + nginx.ingress.kubernetes.io/load-balance: round_robin + nginx.ingress.kubernetes.io/proxy-body-size: "" + nginx.ingress.kubernetes.io/proxy-buffering: "on" + nginx.ingress.kubernetes.io/proxy-connect-timeout: "60" + nginx.ingress.kubernetes.io/server-alias: "" + nginx.ingress.kubernetes.io/ssl-redirect: "true" + nginx.ingress.kubernetes.io/upstream-vhost: $host + labels: + ingress-lb: {{ .Values.ingress.ingressClassName }} + name: TEMPLATE_NAMESPACE + namespace: {{ .Release.Namespace }} +spec: + rules: + - host: portal.{{ .Values.ingress.ingressDomain }} + http: + paths: + - backend: + service: + name: TEMPLATE_NAMESPACE + port: + number: 80 + path: TEMPLATE_BASENAME-public + pathType: ImplementationSpecific +{{- end }} \ No newline at end of file diff --git a/pipeline/lowcode/chart-template/templates/portal.yaml b/pipeline/lowcode/chart-template/templates/portal.yaml new file mode 100644 index 00000000..7cff8535 --- /dev/null +++ b/pipeline/lowcode/chart-template/templates/portal.yaml @@ -0,0 +1,7 @@ +apiVersion: core.kubebb.k8s.com.cn/v1alpha1 +kind: Portal +metadata: + name: TEMPLATE_NAMESPACE +spec: + entry: /TEMPLATE_NAMESPACE-public/index.html + path: /TEMPLATE_NAMESPACE diff --git a/pipeline/lowcode/chart-template/templates/service.yaml b/pipeline/lowcode/chart-template/templates/service.yaml new file mode 100644 index 00000000..8bfe6290 --- /dev/null +++ b/pipeline/lowcode/chart-template/templates/service.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + app: TEMPLATE_NAMESPACE + name: TEMPLATE_NAMESPACE + namespace: {{ .Release.Namespace }} +spec: + ports: + - name: http + port: 80 + protocol: TCP + targetPort: 80 + selector: + app: TEMPLATE_NAMESPACE + sessionAffinity: None + type: ClusterIP diff --git a/pipeline/lowcode/chart-template/values.yaml b/pipeline/lowcode/chart-template/values.yaml new file mode 100644 index 00000000..aefada03 --- /dev/null +++ b/pipeline/lowcode/chart-template/values.yaml @@ -0,0 +1,16 @@ +image: TEMPLATE_IMAGE +imagePullPolicy: IfNotPresent +resources: + limits: + cpu: 5000m + memory: 1280Mi + requests: + cpu: 500m + memory: 512Mi + +# ingress configurations for component +ingress: + # set enable to `true` to enable ingress + enable: false + ingressClassName: portal-ingress + ingressDomain: 172.18.0.2.nip.io diff --git a/pipeline/lowcode/kustomization.yaml b/pipeline/lowcode/kustomization.yaml new file mode 100644 index 00000000..0eaedaf0 --- /dev/null +++ b/pipeline/lowcode/kustomization.yaml @@ -0,0 +1,8 @@ +# Adds namespace to all resources. +namespace: yunti-system + +bases: + - ./pipeline.yaml + - ./task-fetch-source.yaml + - ./task-build-image.yaml + - ./task-build-chart.yaml diff --git a/pipeline/lowcode/pipeline.yaml b/pipeline/lowcode/pipeline.yaml new file mode 100644 index 00000000..c2c745c7 --- /dev/null +++ b/pipeline/lowcode/pipeline.yaml @@ -0,0 +1,109 @@ +apiVersion: tekton.dev/v1beta1 +kind: Pipeline +metadata: + name: lowcode-publish + annotations: + tekton.dev/tags: lowcode-publish + tekton.dev/displayName: "LowcodePublish" + tekton.dev/platforms: "linux/amd64" +spec: + description: >- + The pipeline used for publish a lowcode component + + workspaces: + - name: source-ws + description: Location where source is stored. + - name: dockerfile-ws + description: Location where dockerfile is stored.= + - name: dockerconfig-ws + description: Location where docker push credentail is stored. + - name: charttemplate-ws + description: Location where component's chart templates are stored. + + params: + - name: SOURCE_PATH + description: minio's soruce path which is BUCKET + - name: SCHEMA_PATH + description: relative path to `SOURCE_PATH` of the component's schema + - name: SOURCE_MINIO_HOST + description: minio host/domain to fetch (my-minio.default.svc.cluster.local) + # minio deployed with https://github.com/kubebb/components/tree/main/examples/minio + default: "my-minio.default.svc.cluster.local" + - name: SOURCE_MINIO_ACCESS_KEY + type: string + description: the accessKey used to fetch minio object + - name: SOURCE_MINIO_SECRET_KEY + type: string + description: the secretKey used to fetch minio object + - name: APP_IMAGE + description: The name of the image to build (required) + - name: REPOSITORY_URL + description: The url for the component repository + # chartmuseum deployed with https://github.com/kubebb/components/tree/main/examples/chartmuseum + default: "http://chartmuseum.kubebb-system.svc.cluster.local:8080" + - name: REPOSITORY_USER + description: The username for the component repository + - name: REPOSITORY_PASSWORD + description: The password for the component repository + tasks: + - name: fetch-source + retries: 3 + taskRef: + name: fetch-source + params: + - name: path + value: $(params.SOURCE_PATH) + - name: host + value: $(params.SOURCE_MINIO_HOST) + - name: accessKey + value: $(params.SOURCE_MINIO_ACCESS_KEY) + - name: secretKey + value: $(params.SOURCE_MINIO_SECRET_KEY) + workspaces: + - name: output + workspace: source-ws + - name: build-image + retries: 3 + runAfter: + - fetch-source + taskRef: + name: build-image + workspaces: + - name: source + workspace: source-ws + - name: dockerfile + workspace: dockerfile-ws + - name: dockerconfig + workspace: dockerconfig-ws + params: + - name: SCHEMA_PATH + value: $(params.SCHEMA_PATH) + - name: IMAGE + value: $(params.APP_IMAGE) + - name: EXTRA_ARGS + value: + - --skip-tls-verify + - --insecure + - --ignore-path=/product_uuid + - name: build-chart + retries: 3 + runAfter: + - build-image + taskRef: + name: build-chart + workspaces: + - name: source + workspace: source-ws + - name: charttemplate + workspace: charttemplate-ws + params: + - name: SCHEMA_PATH + value: $(params.SCHEMA_PATH) + - name: IMAGE + value: $(params.APP_IMAGE)@$(tasks.build-image.results.IMAGE_DIGEST) + - name: REPOSITORY_URL + value: $(params.REPOSITORY_URL) + - name: REPOSITORY_USER + value: $(params.REPOSITORY_USER) + - name: REPOSITORY_PASSWORD + value: $(params.REPOSITORY_PASSWORD) diff --git a/pipeline/lowcode/sample/install-component.yaml b/pipeline/lowcode/sample/install-component.yaml new file mode 100644 index 00000000..35a3f789 --- /dev/null +++ b/pipeline/lowcode/sample/install-component.yaml @@ -0,0 +1,12 @@ +apiVersion: core.kubebb.k8s.com.cn/v1alpha1 +kind: ComponentPlan +metadata: + name: hello-world + namespace: default +spec: + approved: true + name: hello-world + version: 0.0.2 + component: + name: chartmuseum.hello-world + namespace: kubebb-system diff --git a/pipeline/lowcode/sample/pre-publish.yaml b/pipeline/lowcode/sample/pre-publish.yaml new file mode 100644 index 00000000..49b488d0 --- /dev/null +++ b/pipeline/lowcode/sample/pre-publish.yaml @@ -0,0 +1,33 @@ +apiVersion: v1 +kind: Secret +metadata: + name: dockerconfig-secret + namespace: yunti-system +data: + # echo -n '{"auths":{"https://index.docker.io/v1/":{"auth":"a3ViZWJiOmRja3JfcGF0X1VpMGtvajNFR0taT0JUZ2tFTzBDNmxGcS1mbw=="}}}' | base64 + # auth的值是 echo -n "testuser:testpassword" | base64 + config.json: eyJhdXRocyI6eyJodHRwczovL2luZGV4LmRvY2tlci5pby92MS8iOnsiYXV0aCI6ImEzVmlaV0ppT21SamEzSmZjR0YwWDFWcE1HdHZhak5GUjB0YVQwSlVaMnRGVHpCRE5teEdjUzFtYnc9PSJ9fX0= +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: dockerfile-cm + namespace: yunti-system +data: + Dockerfile: | + FROM yuntihub/lowcode-code-generator:2.2.1 as builder + + COPY ./schema.json /usr/src/app/ + + RUN lowcode-code-generator -i schema.json -o /usr/src/app/ -s umi + RUN ni + + # package files + RUN cp config/api.sample.ts config/api.ts && npm run build + # generate menu + RUN cd dist/*/ && /menu-generator --from=menu.json > /usr/src/app/menu.yaml + + FROM yuntihub/nginx:stable + COPY --from=builder /usr/src/app/dist /usr/share/nginx/static + COPY --from=builder /usr/src/app/menu.yaml /usr/share/nginx/static/menu.yaml + COPY --from=builder /usr/src/app/default.conf /etc/nginx/conf.d/ diff --git a/pipeline/lowcode/sample/publish.yaml b/pipeline/lowcode/sample/publish.yaml new file mode 100644 index 00000000..2a4b7224 --- /dev/null +++ b/pipeline/lowcode/sample/publish.yaml @@ -0,0 +1,48 @@ +apiVersion: tekton.dev/v1beta1 +kind: PipelineRun +metadata: + name: sample-publish + namespace: yunti-system + labels: + description: "A_PipelineRun_For_LowcodePublish" +spec: + pipelineRef: + name: lowcode-publish + params: + - name: SOURCE_PATH + value: yunti/hello-world + - name: SCHEMA_PATH + value: schema.json + - name: SOURCE_MINIO_HOST + value: my-minio.kubebb-addons.svc.cluster.local:9000 + - name: SOURCE_MINIO_ACCESS_KEY + value: "nthU72RLoo5WnkKb" + - name: SOURCE_MINIO_SECRET_KEY + value: "UvKHPGAVOMViNzedF2eiq4aeADyfDrSz" + - name: APP_IMAGE + value: kubebb/hello-world:0.0.1 + - name: REPOSITORY_URL + value: "http://chartmuseum.kubebb-addons.svc.cluster.local:8080" + - name: REPOSITORY_USER + value: "admin" + - name: REPOSITORY_PASSWORD + value: "password" + workspaces: + - name: source-ws + volumeClaimTemplate: + spec: + storageClassName: "" # openebs-hostpath + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 500Mi + - name: dockerconfig-ws + secret: + secretName: dockerconfig-secret + - name: dockerfile-ws + configmap: + name: dockerfile-cm + - name: charttemplate-ws + configMap: + name: chart-template-cm diff --git a/pipeline/lowcode/sample/schema.json b/pipeline/lowcode/sample/schema.json new file mode 100644 index 00000000..dd5af29a --- /dev/null +++ b/pipeline/lowcode/sample/schema.json @@ -0,0 +1,118 @@ +{ + "version": "1.0.0", + "meta": { + "name": "示例组件", + "namespace": "hello-world", + "version": "0.0.1", + "description": "demo portal init by @yunti/lowcode-code-generator with umijs template", + "port": "8168", + "basename": "/umi-demo", + "git_url": "https://gitlab.dev.21vianet.com/sbg2-tenxcloud/contrib/tenx-ui/demos/umi-demo-portal.git" + }, + "config": { + "antd": { + "configProvider": { + "theme": { + "token": { + "colorPrimary": "#00b96b" + } + } + } + } + }, + "componentsMap": [ + { + "componentName": "Page", + "destructuring": true, + "exportName": "Page", + "package": "@tenx-ui/materials", + "version": "1.5.11-beta.3" + } + ], + "componentsTree": [ + { + "componentName": "Page", + "condition": true, + "fileName": "Test", + "id": "page-dgf1j", + "isLocked": false, + "meta": { + "title": "test", + "router": "/test" + }, + "children": [ + { + "componentName": "h1", + "id": "node_ocljxuh74e1", + "props": { + "children": "Hello World!" + } + } + ] + } + ], + "constants": { + "IS_PROD": { + "builtin": true, + "description": "是否为生产环境", + "mock": "false", + "type": "JSExpression", + "value": "process.env.NODE_ENV === 'production'" + }, + "IS_QIAN_KUN": { + "builtin": true, + "description": "是否为乾坤微前端环境", + "mock": "true", + "type": "JSExpression", + "value": "window.__POWERED_BY_QIANKUN__" + }, + "basename": { + "builtin": true, + "description": "应用路由前缀", + "type": "JSExpression", + "value": "'/umi-demo'" + } + }, + "utils": [ + { + "builtin": true, + "content": { + "componentName": "getAuthData", + "destructuring": true, + "exportName": "getAuthData", + "package": "@tenx-ui/auth-utils", + "subName": "", + "version": "0.0.1" + }, + "description": "获取认证数据", + "name": "getAuthData", + "type": "npm" + }, + { + "builtin": true, + "content": { + "componentName": "setAuthData", + "destructuring": true, + "exportName": "setAuthData", + "package": "@tenx-ui/auth-utils", + "version": "0.0.1" + }, + "description": "设置认证数据", + "name": "setAuthData", + "type": "npm" + }, + { + "builtin": true, + "content": { + "componentName": "removeAuthData", + "destructuring": true, + "exportName": "removeAuthData", + "package": "@tenx-ui/auth-utils", + "version": "0.0.1" + }, + "description": "移除认证数据", + "name": "removeAuthData", + "type": "npm" + } + ] +} \ No newline at end of file diff --git a/pipeline/lowcode/task-build-chart.yaml b/pipeline/lowcode/task-build-chart.yaml new file mode 100644 index 00000000..8e8aa95b --- /dev/null +++ b/pipeline/lowcode/task-build-chart.yaml @@ -0,0 +1,99 @@ +apiVersion: tekton.dev/v1beta1 +kind: Task +metadata: + name: build-chart + annotations: + tekton.dev/categories: "Helm Build" + tekton.dev/tags: build-chart + tekton.dev/displayName: "Build helm charts for component" + tekton.dev/platforms: "linux/amd64,linux/arm64,linux/ppc64le" +spec: + description: >- + This Task build helm charts for component with pre-defined helm templates. + params: + - name: SCHEMA_PATH + description: The relative path of the component schema json to workspace source + - name: IMAGE + description: The image for this component. + - name: REPOSITORY_URL + description: The url for the component repository + - name: REPOSITORY_USER + description: The username for the component repository + default: "admin" + - name: REPOSITORY_PASSWORD + description: The password for the component repository + default: "passw0rd" + workspaces: + - name: source + description: Holds the content and artifiacts + - name: charttemplate + description: Holds the chart template + + results: + - name: CHART_PACKAGE + description: The chart package name + + steps: + - name: extract-menus-as-needed + image: $(params.IMAGE) + workingDir: $(workspaces.source.path) + script: | + #!/usr/bin/env sh + set -e + echo "extract menu.yaml" + cp /usr/share/nginx/static/menu.yaml $(workspaces.source.path)/menu.yaml + + - name: build-and-push-chart + image: kubebb/rating:v0.1.3 + workingDir: $(workspaces.source.path) + script: | + #!/usr/bin/env sh + set -e + + echo "extract chart template" + tar -zxf "$(workspaces.charttemplate.path)/template.tgz" + + ls -tlr + + echo "copy menu.yaml to chart template" + cp $(workspaces.source.path)/menu.yaml $(workspaces.source.path)/chart-template/templates/menu.yaml + + schema_json=$(workspaces.source.path)/$(params.SCHEMA_PATH) + echo "read values from $schema_json using jq" + meta=$(jq -r '.meta' $schema_json) + + template_namespace=$(echo $meta | jq -r '.namespace') + template_name=$(echo $meta | jq -r '.name') + tempalte_version=$(echo $meta | jq -r '.version') + template_description=$(echo $meta | jq -r '.description') + template_basename=$(echo $meta | jq -r '.basename') + template_git_url=$(echo $meta | jq -r '.git_url') + + echo "use the extracted values as needed" + find "$(workspaces.source.path)/chart-template" -type f -name "*.yaml" -o -name "*.yml" | while read -r file; do + # Replace TEMPLATE_NAMESPACE with the new value in each file + sed -i "s#TEMPLATE_NAMESPACE#$template_namespace#g" "$file" + # Replace TEMPLATE_NAME with the new value in each file + sed -i "s#TEMPLATE_NAME#$template_name#g" "$file" + # Replace TEMPLATE_DESCRIPTION with the new value in each file + sed -i "s#TEMPLATE_DESCRIPTION#$template_description#g" "$file" + # Replace TEMPLATE_BASENAME with the new value in each file + sed -i "s#TEMPLATE_BASENAME#$template_basename#g" "$file" + # Replace TEMPLATE_GIT_URL with the new value in each file + sed -i "s#TEMPLATE_GIT_URL#$template_git_url#g" "$file" + # Replace TEMPLATE_VERSION with the new value in each file + sed -i "s#TEMPLATE_VERSION#$tempalte_version#g" "$file" + # Replace TEMPLATE_IMAGE with the new value in each file + sed -i "s#TEMPLATE_IMAGE#$(params.IMAGE)#g" "$file" + done + + echo "package this chart with helm" + helm package "$(workspaces.source.path)/chart-template" + + echo "push this chart with helm registry(chartmuseum)" + package_name="@${template_namespace}-${tempalte_version}.tgz" + curl -u $(params.REPOSITORY_USER):$(params.REPOSITORY_PASSWORD) \ + --data-binary "$package_name" \ + $(params.REPOSITORY_URL)/api/charts + + echo -n "${template_namespace}-${tempalte_version}.tgz" | tee "$(results.CHART_PACKAGE.path)" diff --git a/pipeline/lowcode/task-build-image.yaml b/pipeline/lowcode/task-build-image.yaml new file mode 100644 index 00000000..830616ac --- /dev/null +++ b/pipeline/lowcode/task-build-image.yaml @@ -0,0 +1,94 @@ +apiVersion: tekton.dev/v1beta1 +kind: Task +metadata: + name: build-image + labels: + app.kubernetes.io/version: "0.6" + annotations: + tekton.dev/pipelines.minVersion: "0.17.0" + tekton.dev/categories: Image Build + tekton.dev/tags: build-image + tekton.dev/displayName: "Build and upload container image using Kaniko" + tekton.dev/platforms: "linux/amd64,linux/arm64,linux/ppc64le" +spec: + description: >- + This Task builds a simple Dockerfile with kaniko and pushes to a registry. + This Task stores the image name and digest as results, allowing Tekton Chains to pick up + that an image was built & sign it. + params: + - name: CONTEXT + description: The build context used by Kaniko. + default: ./ + - name: SCHEMA_PATH + description: The relative path fo schema json to CONTEXT + - name: IMAGE + description: Name (reference) of the image to build. + - name: EXTRA_ARGS + type: array + default: [] + - name: BUILDER_IMAGE + description: The name of the image containing the Docker tool + default: "kubebb/kaniko-executor:v1.9.1" + workspaces: + - name: source + description: Holds the context and Dockerfile + - name: dockerfile + description: Holds the Dockerfile + mountPath: /kaniko/.dockerfile/ + - name: dockerconfig + description: Includes a docker `config.json` + optional: true + mountPath: /kaniko/.docker + results: + - name: IMAGE_DIGEST + description: Digest of the image just built. + steps: + - name: extract-files-as-needed + image: kubebb/bash:5.1.4 + workingDir: $(workspaces.source.path) + script: | + ls -ltrha + compress_files=$(find . -maxdepth 1 -type f -name "*.tar*" -o -name "*.zip") + if [ -z "$compress_files" ]; then + echo "There are no compressed files in the directory. Skip extract." + exit 0 + fi + for file in $compress_files; do + filename=$(basename -- "$file") + extension="${filename##*.}" + case "$extension" in + "tar") tar -xf "$file";; + "tar.gz"|"tgz") tar -xzf "$file" ;; + "tar.bz2"|"tbz2") tar -xjf "$file" ;; + "zip") unzip -q "$file" ;; + *) echo "Unknown compressed file format!" $file ;; + esac + done + echo "All compressed files have been extracted!" + ls -ltrha + exit 0 + - name: prepare-schema + workingDir: $(workspaces.source.path) + image: kubebb/bash:5.1.4 + script: | + set -e + src=$(workspaces.source.path)/$(params.CONTEXT)/$(params.SCHEMA_PATH) + dst=$(workspaces.source.path)/$(params.CONTEXT)/schema.json + + echo "Copying $src to $dst" + cp $src $(workspaces.source.path)/schema.json.bak + cp $(workspaces.source.path)/schema.json.bak $dst + - name: build-and-push + workingDir: $(workspaces.source.path) + image: $(params.BUILDER_IMAGE) + args: + - $(params.EXTRA_ARGS) + - --dockerfile=/kaniko/.dockerfile/Dockerfile + - --context=$(workspaces.source.path)/$(params.CONTEXT) # The user does not need to care the workspace and the source. + - --destination=$(params.IMAGE) + - --digest-file=$(results.IMAGE_DIGEST.path) + # kaniko assumes it is running as root, which means this example fails on platforms + # that default to run containers as random uid (like OpenShift). Adding this securityContext + # makes it explicit thatget po it needs to run as root. + securityContext: + runAsUser: 0 diff --git a/pipeline/lowcode/task-fetch-source.yaml b/pipeline/lowcode/task-fetch-source.yaml new file mode 100644 index 00000000..91d4bd07 --- /dev/null +++ b/pipeline/lowcode/task-fetch-source.yaml @@ -0,0 +1,50 @@ +apiVersion: tekton.dev/v1beta1 +kind: Task +metadata: + name: fetch-source + annotations: + tekton.dev/categories: Minio + tekton.dev/tags: minio + tekton.dev/displayName: "fetch sourcecode" + tekton.dev/platforms: "linux/amd64" +spec: + description: >- + The fetch-source Task will fetch a object from the provided minio host and credentials into the + output Workspace. + + workspaces: + - name: output + description: The minio fetch will be stored onto the volume backing this workspace + + params: + - name: path + type: string + description: minio's path which wraps bucket/object along with sub-path + - name: scheme + type: string + description: minio server scheme (http or https) + default: "http" + - name: host + type: string + description: minio host/domain to fetch (my-minio.default.svc.cluster.local) + default: my-minio.default.svc.cluster.local + - name: accessKey + type: string + description: the accessKey used to fetch minio object + - name: secretKey + type: string + description: the secretKey used to fetch minio object + - name: minioClientImage + type: string + default: "kubebb/minio-mc:RELEASE.2023-01-28T20-29-38Z" + description: the image used where the fetch-source(built from https://github.com/minio/mc) + steps: + - name: fetch + image: $(params.minioClientImage) + env: + - name: MC_HOST_minio + value: $(params.scheme)://$(params.accessKey):$(params.secretKey)@$(params.host) + - name: WORKSPACE_OUTPUT_PATH + value: $(workspaces.output.path) + args: + ["cp", --recursive, minio/$(params.path)/, $(workspaces.output.path)]