You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@devlake.apache.org by wa...@apache.org on 2022/06/02 06:37:24 UTC

[incubator-devlake] branch main updated: feat: support helm deployment

This is an automated email from the ASF dual-hosted git repository.

warren pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-devlake.git


The following commit(s) were added to refs/heads/main by this push:
     new 4dfa4b1d feat: support helm deployment
4dfa4b1d is described below

commit 4dfa4b1d85d435ec5ad2dd0919bd9abfd0d9a419
Author: Ji Bin <ma...@live.com>
AuthorDate: Wed May 25 03:46:37 2022 -0400

    feat: support helm deployment
    
    issue: #1991
    
    Signed-off-by: Ji Bin <ma...@live.com>
---
 deployment/helm/.helmignore                 |  23 +++++
 deployment/helm/Chart.yaml                  |  10 +++
 deployment/helm/README.md                   |  50 +++++++++++
 deployment/helm/templates/NOTES.txt         |  15 ++++
 deployment/helm/templates/_helpers.tpl      |  63 ++++++++++++++
 deployment/helm/templates/configmaps.yaml   |   9 ++
 deployment/helm/templates/deployments.yaml  |  82 ++++++++++++++++++
 deployment/helm/templates/services.yaml     |  81 ++++++++++++++++++
 deployment/helm/templates/statefulsets.yaml | 127 ++++++++++++++++++++++++++++
 deployment/helm/values.yaml                 | 126 +++++++++++++++++++++++++++
 10 files changed, 586 insertions(+)

diff --git a/deployment/helm/.helmignore b/deployment/helm/.helmignore
new file mode 100644
index 00000000..0e8a0eb3
--- /dev/null
+++ b/deployment/helm/.helmignore
@@ -0,0 +1,23 @@
+# Patterns to ignore when building packages.
+# This supports shell glob matching, relative path matching, and
+# negation (prefixed with !). Only one pattern per line.
+.DS_Store
+# Common VCS dirs
+.git/
+.gitignore
+.bzr/
+.bzrignore
+.hg/
+.hgignore
+.svn/
+# Common backup files
+*.swp
+*.bak
+*.tmp
+*.orig
+*~
+# Various IDEs
+.project
+.idea/
+*.tmproj
+.vscode/
diff --git a/deployment/helm/Chart.yaml b/deployment/helm/Chart.yaml
new file mode 100644
index 00000000..3af0e999
--- /dev/null
+++ b/deployment/helm/Chart.yaml
@@ -0,0 +1,10 @@
+apiVersion: v2
+name: devlake
+description: A Helm chart for devlake
+type: application
+
+# Chart version
+version: 0.1.0
+
+# devlake version
+appVersion: "0.11.0"
diff --git a/deployment/helm/README.md b/deployment/helm/README.md
new file mode 100644
index 00000000..d6e62142
--- /dev/null
+++ b/deployment/helm/README.md
@@ -0,0 +1,50 @@
+# Deploy devlake with helm
+
+## Prerequest
+
+- Helm >= 3.6.0
+- Kubernetes >= 1.19.0
+
+## Quick Install
+
+clone the code, and enter the deployment/helm folder.
+```
+helm install devlake .
+```
+
+And visit your devlake from the node port (32001 by default).
+
+## Parameters
+
+Some useful parameter for the chart, you could also check them in values.yaml
+
+| Parameter | Description | Default |
+|-----------|-------------|---------|
+| replicaCount  | Replica Count for devlake, currently not used  | 1  |
+| mysql.useExternal  | If use external mysql server, currently not used  |  false  |
+| mysql.externalServer  | External mysql server address  | 127.0.0.1  |
+| mysql.externalPort  | External mysql server port  | 3306  |
+| mysql.username  | username for mysql | merico  |
+| mysql.password  | password for mysql | merico  |
+| mysql.database  | database for mysql | lake  |
+| mysql.rootPassword  | root password for mysql | admin  |
+| mysql.storage.class  | storage class for mysql's volume | ""  |
+| mysql.storage.size  | volume size for mysql's data | 5Gi  |
+| mysql.image.repository  | repository for mysql's image | mysql  |
+| mysql.image.tag  | image tag for mysql's image | 8.0.26  |
+| mysql.image.pullPolicy  | pullPolicy for mysql's image | IfNotPresent  |
+| grafana.image.repository  | repository for grafana's image | mericodev/grafana  |
+| grafana.image.tag  | image tag for grafana's image | latest  |
+| grafana.image.pullPolicy  | pullPolicy for grafana's image | Always  |
+| lake.storage.class  | storage class for lake's volume | ""  |
+| lake.storage.size  | volume size for lake's data | 100Mi  |
+| lake.image.repository  | repository for lake's image | mericodev/lake  |
+| lake.image.tag  | image tag for lake's image | latest  |
+| lake.image.pullPolicy  | pullPolicy for lake's image | Always  |
+| ui.image.repository  | repository for ui's image | mericodev/config-ui  |
+| ui.image.tag  | image tag for ui's image | latest  |
+| ui.image.pullPolicy  | pullPolicy for ui's image | Always  |
+| service.type  | Service type for exposed service | NodePort  |
+| service.grafanaPort  | Service port for grafana | 32000  |
+| service.uiPort  | Service port for config ui | 32001  |
+| service.grafanaEndpoint  | The external grafana endpoint, used when ingress not configured  |  http://127.0.0.1:32000  |
\ No newline at end of file
diff --git a/deployment/helm/templates/NOTES.txt b/deployment/helm/templates/NOTES.txt
new file mode 100644
index 00000000..5745506f
--- /dev/null
+++ b/deployment/helm/templates/NOTES.txt
@@ -0,0 +1,15 @@
+
+Welcome to use devlake.
+
+Now please get the URL by running these commands:
+{{- if .Values.ingress.enabled }}
+{{- range $host := .Values.ingress.hosts }}
+  {{- range .paths }}
+  http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }}
+  {{- end }}
+{{- end }}
+{{- else if contains "NodePort" .Values.service.type }}
+  export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "devlake.fullname" . }}-ui)
+  export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
+  echo http://$NODE_IP:$NODE_PORT
+{{- end }}
\ No newline at end of file
diff --git a/deployment/helm/templates/_helpers.tpl b/deployment/helm/templates/_helpers.tpl
new file mode 100644
index 00000000..40d1c0b1
--- /dev/null
+++ b/deployment/helm/templates/_helpers.tpl
@@ -0,0 +1,63 @@
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "devlake.name" -}}
+{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
+{{- end }}
+
+{{/*
+Create a default fully qualified app name.
+We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
+If release name contains chart name it will be used as a full name.
+*/}}
+{{- define "devlake.fullname" -}}
+{{- if .Values.fullnameOverride }}
+{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
+{{- else }}
+{{- $name := default .Chart.Name .Values.nameOverride }}
+{{- if contains $name .Release.Name }}
+{{- .Release.Name | trunc 63 | trimSuffix "-" }}
+{{- else }}
+{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
+{{- end }}
+{{- end }}
+{{- end }}
+
+{{/*
+Create chart name and version as used by the chart label.
+*/}}
+{{- define "devlake.chart" -}}
+{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
+{{- end }}
+
+{{/*
+Common labels
+*/}}
+{{- define "devlake.labels" -}}
+helm.sh/chart: {{ include "devlake.chart" . }}
+{{ include "devlake.selectorLabels" . }}
+{{- if .Chart.AppVersion }}
+app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
+{{- end }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+{{- end }}
+
+{{/*
+Selector labels
+*/}}
+{{- define "devlake.selectorLabels" -}}
+app.kubernetes.io/name: {{ include "devlake.name" . }}
+app.kubernetes.io/instance: {{ .Release.Name }}
+{{- end }}
+
+{{/*
+Create the name of the service account to use
+*/}}
+{{- define "devlake.serviceAccountName" -}}
+{{- if .Values.serviceAccount.create }}
+{{- default (include "devlake.fullname" .) .Values.serviceAccount.name }}
+{{- else }}
+{{- default "default" .Values.serviceAccount.name }}
+{{- end }}
+{{- end }}
+
diff --git a/deployment/helm/templates/configmaps.yaml b/deployment/helm/templates/configmaps.yaml
new file mode 100644
index 00000000..0a7f1613
--- /dev/null
+++ b/deployment/helm/templates/configmaps.yaml
@@ -0,0 +1,9 @@
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: {{ include "devlake.fullname" . }}-config
+data:
+  MYSQL_USER: "{{ .Values.mysql.username }}"
+  MYSQL_PASSWORD: "{{ .Values.mysql.password }}"
+  MYSQL_DATABASE: "{{ .Values.mysql.database }}"
+  MYSQL_ROOT_PASSWORD: "{{ .Values.mysql.rootPassword }}"
diff --git a/deployment/helm/templates/deployments.yaml b/deployment/helm/templates/deployments.yaml
new file mode 100644
index 00000000..8f6d3013
--- /dev/null
+++ b/deployment/helm/templates/deployments.yaml
@@ -0,0 +1,82 @@
+---
+# grafana
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: {{ include "devlake.fullname" . }}-grafana
+  labels:
+    {{- include "devlake.labels" . | nindent 4 }}
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      {{- include "devlake.selectorLabels" . | nindent 6 }}
+  template:
+    metadata:
+      labels:
+        {{- include "devlake.selectorLabels" . | nindent 8 }}
+        devlakeComponent: grafana
+    spec:
+      containers:
+        - name: {{ .Chart.Name }}-grafana
+          image: "{{ .Values.grafana.image.repository }}:{{ .Values.grafana.image.tag }}"
+          imagePullPolicy: {{ .Values.grafana.image.pullPolicy }}
+          ports:
+            - containerPort: 3000
+          livenessProbe:
+            httpGet:
+              path: /api/health
+              port: 3000
+            initialDelaySeconds: 30
+            timeoutSeconds: 30
+          envFrom:
+            - configMapRef:
+                name: {{ include "devlake.fullname" . }}-config
+          env:
+            - name: GF_USERS_ALLOW_SIGN_UP
+              value: 'false'
+            - name: GF_DASHBOARDS_JSON_ENABLED
+              value: 'true'
+            - name: GF_LIVE_ALLOWED_ORIGINS
+              value: '*'
+            - name: MYSQL_URL
+              value: {{ include "devlake.fullname" . }}-mysql:3306
+
+---
+# devlake-ui
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: {{ include "devlake.fullname" . }}-ui
+  labels:
+    {{- include "devlake.labels" . | nindent 4 }}
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      {{- include "devlake.selectorLabels" . | nindent 6 }}
+  template:
+    metadata:
+      labels:
+        {{- include "devlake.selectorLabels" . | nindent 8 }}
+        devlakeComponent: ui
+    spec:
+      containers:
+        - name: {{ .Chart.Name }}-ui
+          image: "{{ .Values.ui.image.repository }}:{{ .Values.ui.image.tag }}"
+          imagePullPolicy: {{ .Values.ui.image.pullPolicy }}
+          ports:
+            - containerPort: 80
+          envFrom:
+            - configMapRef:
+                name: {{ include "devlake.fullname" . }}-config
+          env:
+            - name: DEVLAKE_ENDPOINT
+              # TODO: remove hardcoded `cluster.local`
+              value: {{ include "devlake.fullname" . }}-lake.{{ .Release.Namespace }}.svc.cluster.local:8080
+            - name: GRAFANA_ENDPOINT
+              value: "{{ .Values.service.grafanaEndpoint }}"
+            # - name: ADMIN_USER
+            #   value: "admin"
+            # - name: ADMIN_PASS
+            #   value: "admin"
\ No newline at end of file
diff --git a/deployment/helm/templates/services.yaml b/deployment/helm/templates/services.yaml
new file mode 100644
index 00000000..dc9e60b1
--- /dev/null
+++ b/deployment/helm/templates/services.yaml
@@ -0,0 +1,81 @@
+# mysql services
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ include "devlake.fullname" . }}-mysql
+  labels:
+    {{- include "devlake.labels" . | nindent 4 }}
+spec:
+  selector:
+    {{- include "devlake.selectorLabels" . | nindent 4 }}
+    devlakeComponent: mysql
+  ports:
+    - protocol: TCP
+      name: mysql
+      port: 3306
+      targetPort: 3306
+
+# grafana services
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ include "devlake.fullname" . }}-grafana
+  labels:
+    {{- include "devlake.labels" . | nindent 4 }}
+spec:
+  type: {{ .Values.service.type }}
+  selector:
+    {{- include "devlake.selectorLabels" . | nindent 4 }}
+    devlakeComponent: grafana
+  ports:
+    - protocol: TCP
+      name: grafana
+      port: {{ .Values.service.grafanaPort }}
+      targetPort: 3000
+      {{- if eq .Values.service.type "NodePort" }}
+      nodePort: {{ .Values.service.grafanaPort }}
+      {{- end }}
+
+
+
+# devlake services
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ include "devlake.fullname" . }}-lake
+  labels:
+    {{- include "devlake.labels" . | nindent 4 }}
+spec:
+  selector:
+    {{- include "devlake.selectorLabels" . | nindent 4 }}
+    devlakeComponent: lake
+  ports:
+    - protocol: TCP
+      name: devlake
+      port: 8080
+      targetPort: 8080
+
+---
+# ui
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ include "devlake.fullname" . }}-ui
+  labels:
+    {{- include "devlake.labels" . | nindent 4 }}
+spec:
+  type: {{ .Values.service.type }}
+  selector:
+    {{- include "devlake.selectorLabels" . | nindent 4 }}
+    devlakeComponent: ui
+  ports:
+    - protocol: TCP
+      name: ui
+      port: {{ .Values.service.uiPort }}
+      targetPort: 80
+      {{- if eq .Values.service.type "NodePort" }}
+      nodePort: {{ .Values.service.uiPort }}
+      {{- end }}
diff --git a/deployment/helm/templates/statefulsets.yaml b/deployment/helm/templates/statefulsets.yaml
new file mode 100644
index 00000000..2fb44ceb
--- /dev/null
+++ b/deployment/helm/templates/statefulsets.yaml
@@ -0,0 +1,127 @@
+---
+# mysql statefulset
+apiVersion: apps/v1
+kind: StatefulSet
+metadata:
+  name: {{ include "devlake.fullname" . }}-mysql
+  labels:
+    {{- include "devlake.labels" . | nindent 4 }}
+spec:
+  replicas: 1
+  serviceName: {{ include "devlake.fullname" . }}-mysql
+  selector:
+    matchLabels:
+      {{- include "devlake.selectorLabels" . | nindent 6 }}
+  template:
+    metadata:
+      labels:
+        {{- include "devlake.selectorLabels" . | nindent 8 }}
+        devlakeComponent: mysql
+    spec:
+      containers:
+        - name: {{ .Chart.Name }}-mysql
+          image: "{{ .Values.mysql.image.repository }}:{{ .Values.mysql.image.tag }}"
+          imagePullPolicy: {{ .Values.mysql.image.pullPolicy }}
+          ports:
+            - name: mysql
+              containerPort: 3306
+              protocol: TCP
+          livenessProbe:
+            exec:
+              command:
+                - "sh"
+                - "-c"
+                - "mysqladmin ping -u root -p{{ .Values.mysql.rootPassword }}"
+            initialDelaySeconds: 60
+            timeoutSeconds: 30
+          {{- with .Values.mysql.resources }}
+          resources:
+            {{- toYaml . | nindent 12 }}
+          {{- end }}
+          envFrom:
+            - configMapRef:
+                name: {{ include "devlake.fullname" . }}-config
+          volumeMounts:
+            - mountPath: /var/lib/mysql
+              name: {{ include "devlake.fullname" . }}-mysql-data
+      {{- with .Values.mysql.nodeSelector }}
+      nodeSelector:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- with .Values.mysql.affinity }}
+      affinity:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- with .Values.mysql.tolerations }}
+      tolerations:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+  volumeClaimTemplates:
+    - metadata:
+        name: {{ include "devlake.fullname" . }}-mysql-data
+      spec:
+        accessModes: [ "ReadWriteOnce" ]
+        {{- with .Values.mysql.storage.class }}
+        storageClassName: "{{ . }}"
+        {{- end }}
+        resources:
+          requests:
+            storage: "{{ .Values.mysql.storage.size }}"
+
+
+---
+# devlake
+# TODO: graceful startup: init container for waiting mysql ready
+apiVersion: apps/v1
+kind: StatefulSet
+metadata:
+  name: {{ include "devlake.fullname" . }}-lake
+  labels:
+    {{- include "devlake.labels" . | nindent 4 }}
+spec:
+  replicas: 1
+  serviceName: {{ include "devlake.fullname" . }}-lake
+  selector:
+    matchLabels:
+      {{- include "devlake.selectorLabels" . | nindent 6 }}
+  template:
+    metadata:
+      labels:
+        {{- include "devlake.selectorLabels" . | nindent 8 }}
+        devlakeComponent: lake
+    spec:
+      containers:
+        - name: {{ .Chart.Name }}-lake
+          image: "{{ .Values.lake.image.repository }}:{{ .Values.lake.image.tag }}"
+          imagePullPolicy: {{ .Values.lake.image.pullPolicy }}
+          ports:
+            - containerPort: 8080
+          livenessProbe:
+            httpGet:
+              path: /blueprints
+              port: 8080
+              scheme: HTTP
+            initialDelaySeconds: 60
+            timeoutSeconds: 30
+          envFrom:
+            - configMapRef:
+                name: {{ include "devlake.fullname" . }}-config
+          env:
+            - name: DB_URL
+              value: mysql://{{ .Values.mysql.username }}:{{ .Values.mysql.password }}@{{ include "devlake.fullname" . }}-mysql:3306/{{ .Values.mysql.database }}?charset=utf8mb4&parseTime=True
+            - name: ENV_PATH
+              value: /app/config/.env
+          volumeMounts:
+            - mountPath: /app/config
+              name: {{ include "devlake.fullname" . }}-lake-config
+  volumeClaimTemplates:
+    - metadata:
+        name: {{ include "devlake.fullname" . }}-lake-config
+      spec:
+        accessModes: [ "ReadWriteOnce" ]
+        {{- with .Values.lake.storage.class }}
+        storageClassName: "{{ . }}"
+        {{- end }}
+        resources:
+          requests:
+            storage: "{{ .Values.lake.storage.size }}"
diff --git a/deployment/helm/values.yaml b/deployment/helm/values.yaml
new file mode 100644
index 00000000..276d5989
--- /dev/null
+++ b/deployment/helm/values.yaml
@@ -0,0 +1,126 @@
+# replica count for dev
+replicaCount: 1
+
+mysql:
+  # if use external mysql server, please set true
+  #   by default using false, chart will create a single mysql instance
+  # TODO(matrixji): add support external mysql server
+  useExternal: false
+
+  # the external mysql server address
+  externalServer: 127.0.0.1
+
+  # external mysql port
+  externalPort: 3306
+
+  # the username for devlake database
+  username: merico
+
+  # the password for devlake database
+  password: merico
+
+  # the database for devlake
+  database: lake
+
+  # root password for mysql, only used when use_external=true
+  rootPassword: admin
+
+  # storage for mysql
+  storage:
+    # the storage class for pv, leave empty will using default
+    class: ""
+    size: 5Gi
+
+  # image for mysql
+  image:
+    repository: mysql
+    tag: 8.0.26
+    pullPolicy: IfNotPresent
+  
+  # resources config for mysql if have
+  resources: {}
+
+  # nodeSelector config for mysql if have
+  nodeSelector: {}
+
+  # tolerations config for mysql if have
+  tolerations: []
+
+  # affinity config for mysql if have
+  affinity: {}
+
+
+grafana:
+  # image for grafana
+  image:
+    repository: mericodev/grafana
+    tag: latest
+    pullPolicy: Always
+  
+  resources: {}
+
+  nodeSelector: {}
+
+  tolerations: []
+
+  affinity: {}
+
+
+lake:
+  image:
+    repository: mericodev/lake
+    tag: latest
+    pullPolicy: Always
+  # storage for config
+  storage:
+    # the storage class for pv, leave empty will using default
+    class: ""
+    size: 100Mi
+
+  resources: {}
+
+  nodeSelector: {}
+
+  tolerations: []
+
+  affinity: {}
+
+ui:
+  image:
+    repository: mericodev/config-ui
+    tag: latest
+    pullPolicy: Always
+
+  resources: {}
+
+  nodeSelector: {}
+
+  tolerations: []
+
+  affinity: {}
+
+service:
+  type: NodePort
+  # service port for grafana
+  grafanaPort: 32000
+  # service port for devlake-ui
+  uiPort: 32001
+  # the external endpoint for grafana, only used when ingress not enabled
+  grafanaEndpoint: http://127.0.0.1:32000
+
+# TODO(matrixji) support ingress.
+ingress:
+  enabled: false
+  className: ""
+  annotations: {}
+    # kubernetes.io/ingress.class: nginx
+    # kubernetes.io/tls-acme: "true"
+  hosts:
+    - host: chart-example.local
+      paths:
+        - path: /
+          pathType: ImplementationSpecific
+  tls: []
+  #  - secretName: chart-example-tls
+  #    hosts:
+  #      - chart-example.local
\ No newline at end of file