From a8a229f9bc5092d27b77f93464ad680a7f32b0c3 Mon Sep 17 00:00:00 2001 From: amecea Date: Mon, 9 Dec 2024 16:14:09 +0200 Subject: [PATCH] Inital commit --- .github/workflows/publish-helm-chart.yml | 35 +++++++ .gitignore | 1 + README.md | 43 +++++++++ charts/twentycrm/Chart.yaml | 4 + charts/twentycrm/templates/_helpers.tpl | 9 ++ charts/twentycrm/templates/deployment-db.yaml | 66 +++++++++++++ .../twentycrm/templates/deployment-redis.yaml | 41 ++++++++ .../templates/deployment-server.yaml | 94 +++++++++++++++++++ .../templates/deployment-worker.yaml | 62 ++++++++++++ charts/twentycrm/templates/ingress.yaml | 38 ++++++++ charts/twentycrm/templates/pvc-db.yaml | 19 ++++ charts/twentycrm/templates/pvc-server.yaml | 19 ++++ charts/twentycrm/templates/secret-tokens.yaml | 18 ++++ charts/twentycrm/templates/secret.yaml | 22 +++++ charts/twentycrm/templates/service-db.yaml | 25 +++++ charts/twentycrm/templates/service-redis.yaml | 21 +++++ .../twentycrm/templates/service-server.yaml | 25 +++++ charts/twentycrm/values.yaml | 61 ++++++++++++ 18 files changed, 603 insertions(+) create mode 100644 .github/workflows/publish-helm-chart.yml create mode 100644 .gitignore create mode 100644 README.md create mode 100644 charts/twentycrm/Chart.yaml create mode 100644 charts/twentycrm/templates/_helpers.tpl create mode 100644 charts/twentycrm/templates/deployment-db.yaml create mode 100644 charts/twentycrm/templates/deployment-redis.yaml create mode 100644 charts/twentycrm/templates/deployment-server.yaml create mode 100644 charts/twentycrm/templates/deployment-worker.yaml create mode 100644 charts/twentycrm/templates/ingress.yaml create mode 100644 charts/twentycrm/templates/pvc-db.yaml create mode 100644 charts/twentycrm/templates/pvc-server.yaml create mode 100644 charts/twentycrm/templates/secret-tokens.yaml create mode 100644 charts/twentycrm/templates/secret.yaml create mode 100644 charts/twentycrm/templates/service-db.yaml create mode 100644 charts/twentycrm/templates/service-redis.yaml create mode 100644 charts/twentycrm/templates/service-server.yaml create mode 100644 charts/twentycrm/values.yaml diff --git a/.github/workflows/publish-helm-chart.yml b/.github/workflows/publish-helm-chart.yml new file mode 100644 index 0000000..a34da7e --- /dev/null +++ b/.github/workflows/publish-helm-chart.yml @@ -0,0 +1,35 @@ +name: Publish Helm Chart + +on: + push: + branches: + - master + paths: + - 'charts/**' + +jobs: + publish: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Set up Helm + uses: azure/setup-helm@v4 + with: + version: v3.12.3 + + - name: Create Helm package + run: | + mkdir -p chart-packages + helm package ./charts/twentycrm -d .work/charts/ + helm repo index .work/charts/ --url https://amecea.github.io/helm-twentycrm + + - name: Deploy to GitHub Pages + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: .work/charts/ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..925841a --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.work diff --git a/README.md b/README.md new file mode 100644 index 0000000..01b5e0d --- /dev/null +++ b/README.md @@ -0,0 +1,43 @@ +# TwentyCRM helm chart + + +This repository provides a helm chart to deploy TwentyCRM. + + +## Configuration + +For a complete list of configuration fields please check [values.yaml](./values.yaml) file. + + +| Field Name | Description | Default Value | +|----------------------------------|-------------------------------------------------------------------------------------------|-------------------------| +| `image` | Docker image for the application. | `twentycrm/twenty:latest` | +| `env` | List of environment variables for configuring the application. | `[]` | +| `secrets.accessToken` | Access token for authentication. | | +| `secrets.loginToken` | Login token for authentication. | | +| `secrets.refreshToken` | Refresh token for authentication. | | +| `secrets.fileToken` | File token for authentication. | | +| `server.replicas` | Number of server replicas. | `1` | +| `server.storage` | Storage size for the server. | `5Gi` | +| `server.storageClassName` | Storage class name for server persistence. | | +| `server.resources.requests.memory` | Memory resource request for the server. | `128Mi` | +| `server.resources.requests.cpu` | CPU resource request for the server. | `100m` | +| `worker.replicas` | Number of worker replicas. | `1` | +| `worker.resources.requests.memory` | Memory resource request for workers. | `128Mi` | +| `worker.resources.requests.cpu` | CPU resource request for workers. | `100m` | +| `db.image` | Docker image for the PostgreSQL database. | `twentycrm/twenty-postgres:latest` | +| `db.storage` | Storage size for the database. | `5Gi` | +| `db.storageClassName` | Storage class name for database persistence. | | +| `db.adminPassword` | Admin password for the database. | | +| `db.database` | Name of the database. | `twenty` | +| `db.user` | Database user name. | `twenty` | +| `db.password` | Password for the database user. | `twenty` | +| `db.resources.requests.memory` | Memory resource request for the database. | `256Mi` | +| `db.resources.requests.cpu` | CPU resource request for the database. | `100m` | +| `redis.image` | Docker image for Redis. | `redis:latest` | +| `redis.resources.requests.memory` | Memory resource request for Redis. | `128Mi` | +| `redis.resources.requests.cpu` | CPU resource request for Redis. | `20m` | +| `ingress.enabled` | Enable or disable ingress. | `true` | +| `ingress.host` | Hostname for the ingress. | `crm.example.com` | +| `ingress.class` | Ingress class name. | `nginx` | + diff --git a/charts/twentycrm/Chart.yaml b/charts/twentycrm/Chart.yaml new file mode 100644 index 0000000..aa2f682 --- /dev/null +++ b/charts/twentycrm/Chart.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +description: A Helm chart for https://github.com/twentyhq/twenty +name: twentycrm +version: 0.1.0 diff --git a/charts/twentycrm/templates/_helpers.tpl b/charts/twentycrm/templates/_helpers.tpl new file mode 100644 index 0000000..621ca21 --- /dev/null +++ b/charts/twentycrm/templates/_helpers.tpl @@ -0,0 +1,9 @@ +{{/* vim: set filetype=mustache: */}} + +{{/* +Expand the name of the chart. +*/}} +{{- define "name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + diff --git a/charts/twentycrm/templates/deployment-db.yaml b/charts/twentycrm/templates/deployment-db.yaml new file mode 100644 index 0000000..d39f88f --- /dev/null +++ b/charts/twentycrm/templates/deployment-db.yaml @@ -0,0 +1,66 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Release.Name }}-db + labels: + app: {{ template "name" . }} + chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + +spec: + progressDeadlineSeconds: 600 + replicas: 1 + strategy: + rollingUpdate: + maxSurge: 1 + maxUnavailable: 1 + type: RollingUpdate + + selector: + matchLabels: + app: {{ template "name" . }} + release: {{ .Release.Name }} + role: db + template: + metadata: + labels: + app: {{ template "name" . }} + release: {{ .Release.Name }} + role: db + spec: + securityContext: + fsGroup: 1001 + volumes: + - name: twentycrm-db-data + persistentVolumeClaim: + claimName: {{ .Release.Name }}-db-pvc + + containers: + - name: twentycrm-db + image: {{ .Values.db.image }} + imagePullPolicy: Always + env: + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Release.Name }}-app-secrets + key: PG_ADMIN_PASSWORD + + - name: POSTGRES_DATABASE + valueFrom: + secretKeyRef: + name: {{ .Release.Name }}-app-secrets + key: PG_DATABASE + + - name: BITNAMI_DEBUG + value: "true" + ports: + - containerPort: 5432 + name: tcp + protocol: TCP + resources: + {{- toYaml .Values.db.resources | indent 12 | printf "\n%s" }} + volumeMounts: + - mountPath: /bitnami/postgresql + name: twentycrm-db-data diff --git a/charts/twentycrm/templates/deployment-redis.yaml b/charts/twentycrm/templates/deployment-redis.yaml new file mode 100644 index 0000000..d8169bf --- /dev/null +++ b/charts/twentycrm/templates/deployment-redis.yaml @@ -0,0 +1,41 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Release.Name }}-redis + labels: + app: {{ template "name" . }} + chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + +spec: + progressDeadlineSeconds: 600 + replicas: 1 + strategy: + rollingUpdate: + maxSurge: 1 + maxUnavailable: 1 + type: RollingUpdate + + selector: + matchLabels: + app: {{ template "name" . }} + release: {{ .Release.Name }} + role: redis + template: + metadata: + labels: + app: {{ template "name" . }} + release: {{ .Release.Name }} + role: redis + spec: + containers: + - name: twentycrm-redis + image: {{ .Values.redis.image }} + imagePullPolicy: Always + ports: + - containerPort: 6379 + name: tcp + protocol: TCP + resources: + {{- toYaml .Values.redis.resources | indent 12 | printf "\n%s" }} diff --git a/charts/twentycrm/templates/deployment-server.yaml b/charts/twentycrm/templates/deployment-server.yaml new file mode 100644 index 0000000..f722f0d --- /dev/null +++ b/charts/twentycrm/templates/deployment-server.yaml @@ -0,0 +1,94 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Release.Name }}-server + labels: + app: {{ template "name" . }} + chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + +spec: + progressDeadlineSeconds: 600 + replicas: {{ .Values.server.replicas }} + strategy: + rollingUpdate: + maxSurge: 1 + maxUnavailable: 1 + type: RollingUpdate + selector: + matchLabels: + app: {{ template "name" . }} + release: {{ .Release.Name }} + role: server + + template: + metadata: + labels: + app: {{ template "name" . }} + release: {{ .Release.Name }} + role: server + annotations: + checksum/config: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }} + spec: + securityContext: + fsGroup: 1001 + + volumes: + - name: twentycrm-server-data + persistentVolumeClaim: + claimName: {{ .Release.Name }}-server-pvc + initContainers: + # if it's not ready at first start the db setup fail badly + - name: wait-db-ready + image: {{ .Values.db.image }} + command: ["pg_isready", "-d", "$(PG_DATABASE_URL)" ] + envFrom: + - secretRef: + name: {{ .Release.Name }}-app-secrets + + containers: + - name: twentycrm-server + image: {{ .Values.image }} + imagePullPolicy: Always + envFrom: + - secretRef: + name: {{ .Release.Name }}-app-secrets + - secretRef: + name: {{ .Release.Name }}-app-tokens + + env: + - name: PORT + value: "3000" + - name: SERVER_URL + value: "https://{{ .Values.ingress.host }}" + - name: FRONT_BASE_URL + value: "https://{{ .Values.ingress.host }}" + - name: ENABLE_DB_MIGRATIONS + value: "true" + - name: SIGN_IN_PREFILLED + value: "true" + - name: STORAGE_TYPE + value: "local" + - name: "MESSAGE_QUEUE_TYPE" + value: "pg-boss" + + ports: + - containerPort: 3000 + name: http-tcp + protocol: TCP + resources: + {{- toYaml .Values.server.resources | indent 12 | printf "\n%s" }} + volumeMounts: + - mountPath: /app/docker-data + name: twentycrm-server-data + - mountPath: /app/.local-storage + name: twentycrm-server-data + #livenessProbe: + # httpGet: + # path: "/healthz" + # port: 3000 + #readinessProbe: + # httpGet: + # path: "/healthz" + # port: 3000 diff --git a/charts/twentycrm/templates/deployment-worker.yaml b/charts/twentycrm/templates/deployment-worker.yaml new file mode 100644 index 0000000..1cd7386 --- /dev/null +++ b/charts/twentycrm/templates/deployment-worker.yaml @@ -0,0 +1,62 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Release.Name }}-worker + labels: + app: {{ template "name" . }} + chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + +spec: + progressDeadlineSeconds: 600 + replicas: {{ .Values.worker.replicas }} + strategy: + rollingUpdate: + maxSurge: 1 + maxUnavailable: 1 + type: RollingUpdate + selector: + matchLabels: + app: {{ template "name" . }} + release: {{ .Release.Name }} + role: worker + + template: + metadata: + labels: + app: {{ template "name" . }} + release: {{ .Release.Name }} + role: worker + annotations: + checksum/config: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }} + spec: + containers: + - name: twentycrm-worker + image: {{ .Values.image }} + imagePullPolicy: Always + envFrom: + - secretRef: + name: {{ .Release.Name }}-app-secrets + - secretRef: + name: {{ .Release.Name }}-app-tokens + env: + - name: SERVER_URL + value: "https://{{ .Values.ingress.host }}" + - name: FRONT_BASE_URL + value: "https://{{ .Values.ingress.host }}" + - name: ENABLE_DB_MIGRATIONS + value: "false" + - name: SIGN_IN_PREFILLED + value: "true" + - name: STORAGE_TYPE + value: "local" + - name: "MESSAGE_QUEUE_TYPE" + value: "pg-boss" + + command: + - yarn + - worker:prod + resources: + {{- toYaml .Values.worker.resources | indent 12 | printf "\n%s" }} + diff --git a/charts/twentycrm/templates/ingress.yaml b/charts/twentycrm/templates/ingress.yaml new file mode 100644 index 0000000..a1f9022 --- /dev/null +++ b/charts/twentycrm/templates/ingress.yaml @@ -0,0 +1,38 @@ +{{- if .Values.ingress.enabled }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ .Release.Name }} + labels: + app: {{ template "name" . }} + chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + annotations: + nginx.ingress.kubernetes.io/configuration-snippet: | + more_set_headers "X-Forwarded-For $http_x_forwarded_for"; + nginx.ingress.kubernetes.io/force-ssl-redirect: "false" + nginx.ingress.kubernetes.io/backend-protocol: "HTTP" + {{- range $key, $value := .Values.ingress.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} + +spec: + ingressClassName: {{ .Values.ingress.class }} + rules: + - host: {{ .Values.ingress.host }} + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: {{ .Release.Name }}-server + port: + name: http-tcp + + {{- if .Values.ingress.tls }} + tls: + {{- toYaml .Values.ingress.tls | indent 4 | printf "\n%s" }} + {{- end -}} +{{- end }} diff --git a/charts/twentycrm/templates/pvc-db.yaml b/charts/twentycrm/templates/pvc-db.yaml new file mode 100644 index 0000000..00e2098 --- /dev/null +++ b/charts/twentycrm/templates/pvc-db.yaml @@ -0,0 +1,19 @@ +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: {{ .Release.Name }}-db-pvc + labels: + app: {{ template "name" . }} + chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + accessModes: + - "ReadWriteOnce" + resources: + requests: + storage: {{ .Values.db.storage }} + {{- with .Values.db.className }} + storageClassName: {{ . }} + {{- end }} + diff --git a/charts/twentycrm/templates/pvc-server.yaml b/charts/twentycrm/templates/pvc-server.yaml new file mode 100644 index 0000000..f5649d5 --- /dev/null +++ b/charts/twentycrm/templates/pvc-server.yaml @@ -0,0 +1,19 @@ +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: {{ .Release.Name }}-server-pvc + labels: + app: {{ template "name" . }} + chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + accessModes: + - "ReadWriteOnce" + resources: + requests: + storage: {{ .Values.server.storage }} + {{- with .Values.server.storageClassName }} + storageClassName: {{ . }} + {{- end }} + diff --git a/charts/twentycrm/templates/secret-tokens.yaml b/charts/twentycrm/templates/secret-tokens.yaml new file mode 100644 index 0000000..f27f369 --- /dev/null +++ b/charts/twentycrm/templates/secret-tokens.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Secret +metadata: + name: {{ .Release.Name }}-app-tokens + annotations: + "helm.sh/hook": "pre-install" + labels: + app: {{ .Release.Name }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +type: Opaque +data: + ACCESS_TOKEN_SECRET: {{ default (randAlphaNum 32) .Values.secrets.accessToken | b64enc | quote }} + LOGIN_TOKEN_SECRET: {{ default (randAlphaNum 32) .Values.secrets.loginToken | b64enc | quote }} + REFRESH_TOKEN_SECRET: {{ default (randAlphaNum 32) .Values.secrets.refreshToken | b64enc | quote }} + FILE_TOKEN_SECRET: {{ default (randAlphaNum 32) .Values.secrets.fileToken | b64enc | quote }} + diff --git a/charts/twentycrm/templates/secret.yaml b/charts/twentycrm/templates/secret.yaml new file mode 100644 index 0000000..4d655d7 --- /dev/null +++ b/charts/twentycrm/templates/secret.yaml @@ -0,0 +1,22 @@ +apiVersion: v1 +kind: Secret +metadata: + name: {{ .Release.Name }}-app-secrets + labels: + app: {{ .Release.Name }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +type: Opaque +data: + PG_DATABASE: {{ .Values.db.database | b64enc | quote }} + PG_USER: {{ .Values.db.user | b64enc | quote }} + PG_ADMIN_PASSWORD: {{ required ".db.adminPassword is missing" .Values.db.password | b64enc | quote }} + PG_DATABASE_URL: {{ printf "postgres://%s:%s@%s-db/twenty" .Values.db.user .Values.db.password .Release.Name | b64enc | quote}} + + REDIS_HOST: {{ printf "%s-redis" .Release.Name |b64enc | quote}} + + {{- range $key, $value := .Values.env }} + {{ $key }}: {{ printf "%s" $value | b64enc | quote }} + {{- end }} + diff --git a/charts/twentycrm/templates/service-db.yaml b/charts/twentycrm/templates/service-db.yaml new file mode 100644 index 0000000..615c670 --- /dev/null +++ b/charts/twentycrm/templates/service-db.yaml @@ -0,0 +1,25 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Release.Name }}-db + labels: + app: {{ template "name" . }} + chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + +spec: + internalTrafficPolicy: Cluster + ports: + - port: 5432 + protocol: TCP + targetPort: 5432 + selector: + app: {{ template "name" . }} + release: {{ .Release.Name }} + role: db + sessionAffinity: ClientIP + sessionAffinityConfig: + clientIP: + timeoutSeconds: 10800 + type: ClusterIP diff --git a/charts/twentycrm/templates/service-redis.yaml b/charts/twentycrm/templates/service-redis.yaml new file mode 100644 index 0000000..74ab02b --- /dev/null +++ b/charts/twentycrm/templates/service-redis.yaml @@ -0,0 +1,21 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Release.Name }}-redis + labels: + app: {{ template "name" . }} + chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + +spec: + internalTrafficPolicy: Cluster + ports: + - port: 6379 + protocol: TCP + targetPort: 6379 + selector: + app: {{ template "name" . }} + release: {{ .Release.Name }} + role: redis + type: ClusterIP diff --git a/charts/twentycrm/templates/service-server.yaml b/charts/twentycrm/templates/service-server.yaml new file mode 100644 index 0000000..5a50b76 --- /dev/null +++ b/charts/twentycrm/templates/service-server.yaml @@ -0,0 +1,25 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Release.Name }}-server + labels: + app: {{ template "name" . }} + chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + internalTrafficPolicy: Cluster + ports: + - name: http-tcp + port: 3000 + protocol: TCP + targetPort: 3000 + selector: + app: {{ template "name" . }} + release: {{ .Release.Name }} + role: server + sessionAffinity: ClientIP + sessionAffinityConfig: + clientIP: + timeoutSeconds: 10800 + type: ClusterIP diff --git a/charts/twentycrm/values.yaml b/charts/twentycrm/values.yaml new file mode 100644 index 0000000..c974bd1 --- /dev/null +++ b/charts/twentycrm/values.yaml @@ -0,0 +1,61 @@ + +image: twentycrm/twenty:latest + +# A list of env that can be set: +# https://twenty.com/developers/section/self-hosting/self-hosting-var +env: [] + +secrets: + accessToken: + loginToken: + refreshToken: + fileToken: + + + +server: + replicas: 1 + storage: 5Gi + #storageClassName: + resources: + requests: + memory: "128Mi" + cpu: "100m" + +worker: + replicas: 1 + resources: + requests: + memory: "128Mi" + cpu: "100m" + +db: + image: twentycrm/twenty-postgres:latest + storage: 5Gi + #storageClassName: + + #adminPassword: some-random-string + + # those should be set in stone because are configured in init.sql + database: twenty + user: twenty + password: twenty + + resources: + requests: + memory: "256Mi" + cpu: "100m" + +redis: + image: redis:latest + resources: + requests: + memory: "128Mi" + cpu: "20m" + + + +ingress: + enabled: true + host: crm.example.com + class: nginx