diff --git a/.eslintignore b/.eslintignore index 3c3629e6..d164bca5 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1 +1,3 @@ node_modules +helm/**/*.yml +helm/**/*.yaml diff --git a/.gitignore b/.gitignore index 125ad425..051a97f2 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,7 @@ Thumbs.db # Generated Docusaurus files .docusaurus/ .cache-loader/ + + +# Helm Chart +helm/values.yaml diff --git a/.prettierignore b/.prettierignore index 6e54f161..860be47a 100644 --- a/.prettierignore +++ b/.prettierignore @@ -3,3 +3,4 @@ coverage/ dist/ apps/frontend/public/mockServiceWorker.js +helm/ diff --git a/README.md b/README.md index a5991592..4d5d8669 100644 --- a/README.md +++ b/README.md @@ -115,6 +115,20 @@ npx nx run backend-e2e:e2e --spec apps/backend-e2e/src/e2e/user.cy.ts &> cypress > See **Cypress** documentation : > https://github.com/nrwl/nx/tree/master/packages/cypress/docs +## Deployment + +### Kubernetes + +You can deploy the datatlas stack on a kubernetes cluster using the provided helm chart. + +Copy the `helm/example.values.yaml` file to values.yaml and edit it to fit your needs. + +Then run the following command to deploy the stack: + +```sh +helm install datatlas ./helm --create-namespace --namespace datatlas +``` + ## Credits **DatAtlas** was created by [**Erasme**](https://www.erasme.org), the open innovation lab of Lyon 🇫🇷 metropolitan area. It's a part of the larger [**DatAgora**](https://www.erasme.org/DatAgora) initiative. diff --git a/helm/.helmignore b/helm/.helmignore new file mode 100644 index 00000000..0e8a0eb3 --- /dev/null +++ b/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/helm/Chart.yaml b/helm/Chart.yaml new file mode 100644 index 00000000..948b1ba1 --- /dev/null +++ b/helm/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: datatlas-chart +description: A Helm chart for Datatlas + +# 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 + +# 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: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "1.16.0" diff --git a/helm/example.values.yaml b/helm/example.values.yaml new file mode 100644 index 00000000..b640f5f0 --- /dev/null +++ b/helm/example.values.yaml @@ -0,0 +1,101 @@ +backend: + container: + name: frontend-container + strategy: + type: Recreate + image: + repository: erasme/datatlas-backend + tag: dev + pullPolicy: Always + service: + type: ClusterIP + port: 3333 + targetPort: 3333 + env: + POSTGRES_USER: docker + POSTGRES_PASSWORD: mypassword + POSTGRES_DATABASE: datatlas + POSTGRES_HOST: postgis + POSTGRES_PORT: "5432" + PASSWORD_SALT: mypassword + ADMIN_EMAIL: admin@example.org + ADMIN_PASSWORD: admin + DUMMY_EDITOR_EMAIL: editor@example.org + DUMMY_EDITOR_PASSWORD: editor + PAYLOAD_SIZE_LIMIT: 25mb + +frontend: + container: + name: frontend-container + strategy: + type: Recreate + image: + repository: erasme/datatlas-frontend + tag: dev + pullPolicy: Always + service: + type: ClusterIP + port: 8080 + targetPort: 8080 + env: + REACT_APP_DEFAULT_LOCALE: fr + REACT_APP_MAPBOX_ACCESS_TOKEN: mapxbox-token + REACT_APP_API_BASE_URL: https://mybackend/api + REACT_APP_MATOMO_SITE_ID: "172" + REACT_APP_MATOMO_TRACKER_URL: "//trackinginfo/" + REACT_APP_CONTACT_EMAIL: my@email.com + REACT_APP_MAX_TOOLIP_FIELDS: "3" + +postgisPgadmin: + strategy: + type: Recreate + replicaCount: 1 + postgis: + image: kartoza/postgis:15-3.3 + env: + POSTGRES_DB: postgres + POSTGRES_USER: docker + POSTGRES_PASS: mypassword + volumeMounts: + - mountPath: /var/lib/postgresql + subPath: postgis + pgadmin: + image: dpage/pgadmin4 + env: + PGADMIN_DEFAULT_EMAIL: my@email.com + PGADMIN_DEFAULT_PASSWORD: mypassword + volumeMounts: + - mountPath: /var/lib/pgadmin + subPath: pgadmin + debian: + image: debian + command: ["tail", "-f", "/dev/null"] + volumeMounts: + - mountPath: /var/lib/pgadmin + volume: + name: datatlas-dev + persistentVolumeClaim: + claimName: datatlas-dev + + postgisService: + type: ClusterIP + port: 5432 + targetPort: 5432 + + pgadminService: + type: ClusterIP + port: 80 + targetPort: 80 + +pvc: + datatlasDev: + name: datatlas-dev + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 2Gi + # Uncomment and modify the following line if you need to specify a StorageClass + storageClassName: "scw-bssd" + #storageClassName: "local-path" + diff --git a/helm/templates/deployments/backend-deployment.yaml b/helm/templates/deployments/backend-deployment.yaml new file mode 100644 index 00000000..c0015bb9 --- /dev/null +++ b/helm/templates/deployments/backend-deployment.yaml @@ -0,0 +1,28 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Values.backend.name | default "backend" }} + namespace: {{ .Release.Namespace }} + labels: + workload.user.cattle.io/workloadselector: apps.deployment-{{ .Release.Namespace }}-backend +spec: + replicas: {{ .Values.backend.replicas | default 1 }} + selector: + matchLabels: + workload.user.cattle.io/workloadselector: apps.deployment-{{ .Release.Namespace }}-backend + strategy: + type: {{ .Values.backend.strategy.type | default "Recreate" }} + template: + metadata: + labels: + workload.user.cattle.io/workloadselector: apps.deployment-{{ .Release.Namespace }}-backend + spec: + containers: + - name: {{ .Values.backend.container.name | default "backend" }} + image: "{{ .Values.backend.image.repository }}:{{ .Values.backend.image.tag | default "dev" }}" + imagePullPolicy: {{ .Values.backend.image.pullPolicy | default "Always" }} + env: + {{- range $key, $value := .Values.backend.env }} + - name: {{ $key }} + value: {{ $value | quote }} + {{- end }} diff --git a/helm/templates/deployments/frontend-deployment.yaml b/helm/templates/deployments/frontend-deployment.yaml new file mode 100644 index 00000000..2e3c2daf --- /dev/null +++ b/helm/templates/deployments/frontend-deployment.yaml @@ -0,0 +1,28 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Values.frontend.name | default "frontend" }} + namespace: {{ .Release.Namespace }} + labels: + workload.user.cattle.io/workloadselector: apps.deployment-{{ .Release.Namespace }}-frontend +spec: + replicas: {{ .Values.frontend.replicas | default 1 }} + selector: + matchLabels: + workload.user.cattle.io/workloadselector: apps.deployment-{{ .Release.Namespace }}-frontend + strategy: + type: {{ .Values.frontend.strategy.type | default "Recreate" }} + template: + metadata: + labels: + workload.user.cattle.io/workloadselector: apps.deployment-{{ .Release.Namespace }}-frontend + spec: + containers: + - name: {{ .Values.frontend.container.name | default "frontend" }} + image: "{{ .Values.frontend.image.repository }}:{{ .Values.frontend.image.tag | default "dev" }}" + imagePullPolicy: {{ .Values.frontend.image.pullPolicy | default "Always" }} + env: + {{- range $key, $value := .Values.frontend.env }} + - name: {{ $key }} + value: {{ $value | quote }} + {{- end }} diff --git a/helm/templates/deployments/postgis-pgadmin-deployment.yaml b/helm/templates/deployments/postgis-pgadmin-deployment.yaml new file mode 100644 index 00000000..bdbb9842 --- /dev/null +++ b/helm/templates/deployments/postgis-pgadmin-deployment.yaml @@ -0,0 +1,61 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: postgis-pgadmin + namespace: {{ .Release.Namespace }} + labels: + workload.user.cattle.io/workloadselector: apps.deployment-{{ .Release.Namespace }}-postgis-pgadmin +spec: + replicas: {{ .Values.postgisPgadmin.replicaCount }} + selector: + matchLabels: + workload.user.cattle.io/workloadselector: apps.deployment-{{ .Release.Namespace }}-postgis-pgadmin + strategy: + type: Recreate + template: + metadata: + labels: + workload.user.cattle.io/workloadselector: apps.deployment-{{ .Release.Namespace }}-postgis-pgadmin + spec: + initContainers: + - name: debian-setup + image: "{{ .Values.postgisPgadmin.debian.image }}" + command: ["sh", "-c", "chown -R 5050:5050 /var/lib/pgadmin"] + volumeMounts: + {{- range .Values.postgisPgadmin.debian.volumeMounts }} + - mountPath: {{ .mountPath }} + name: {{ $.Values.postgisPgadmin.volume.name }} + {{- end }} + containers: + - name: postgis + image: "{{ .Values.postgisPgadmin.postgis.image }}" + env: + - name: POSTGRES_DB + value: "{{ .Values.postgisPgadmin.postgis.env.POSTGRES_DB }}" + - name: POSTGRES_USER + value: "{{ .Values.postgisPgadmin.postgis.env.POSTGRES_USER }}" + - name: POSTGRES_PASS + value: "{{ .Values.postgisPgadmin.postgis.env.POSTGRES_PASS }}" + volumeMounts: + {{- range .Values.postgisPgadmin.postgis.volumeMounts }} + - mountPath: {{ .mountPath }} + name: {{ $.Values.postgisPgadmin.volume.name }} + subPath: {{ .subPath }} + {{- end }} + - name: pgadmin + image: "{{ .Values.postgisPgadmin.pgadmin.image }}" + env: + - name: PGADMIN_DEFAULT_EMAIL + value: "{{ .Values.postgisPgadmin.pgadmin.env.PGADMIN_DEFAULT_EMAIL }}" + - name: PGADMIN_DEFAULT_PASSWORD + value: "{{ .Values.postgisPgadmin.pgadmin.env.PGADMIN_DEFAULT_PASSWORD }}" + volumeMounts: + {{- range .Values.postgisPgadmin.pgadmin.volumeMounts }} + - mountPath: {{ .mountPath }} + name: {{ $.Values.postgisPgadmin.volume.name }} + subPath: {{ .subPath }} + {{- end }} + volumes: + - name: {{ .Values.postgisPgadmin.volume.name }} + persistentVolumeClaim: + claimName: {{ .Values.postgisPgadmin.volume.persistentVolumeClaim.claimName }} diff --git a/helm/templates/pvc/datatlas-dev-pvc.yaml b/helm/templates/pvc/datatlas-dev-pvc.yaml new file mode 100644 index 00000000..94b3174e --- /dev/null +++ b/helm/templates/pvc/datatlas-dev-pvc.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ .Values.pvc.datatlasDev.name }} +spec: + accessModes: {{ toYaml .Values.pvc.datatlasDev.accessModes | nindent 4 }} + resources: + requests: + storage: {{ .Values.pvc.datatlasDev.resources.requests.storage }} + # Uncomment the following line if you're specifying a StorageClass + storageClassName: {{ .Values.pvc.datatlasDev.storageClassName | quote }} diff --git a/helm/templates/services/backend-service.yaml b/helm/templates/services/backend-service.yaml new file mode 100644 index 00000000..5b046056 --- /dev/null +++ b/helm/templates/services/backend-service.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Service +name: {{ .Values.frontend.name | default "frontend" }} +metadata: + name: {{ .Values.backend.name | default "backend" }} + namespace: {{ .Release.Namespace }} +spec: + clusterIP: None + type: {{ .Values.backend.service.type }} + ports: + - name: http + port: {{ .Values.backend.service.port }} + targetPort: {{ .Values.backend.service.targetPort }} + protocol: TCP + selector: + workload.user.cattle.io/workloadselector: apps.deployment-{{ .Release.Namespace }}-backend + strategy: + type: {{ .Values.frontend.strategy.type | default "Recreate" }} \ No newline at end of file diff --git a/helm/templates/services/frontend-service.yaml b/helm/templates/services/frontend-service.yaml new file mode 100644 index 00000000..6cfbfb56 --- /dev/null +++ b/helm/templates/services/frontend-service.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Service +name: {{ .Values.frontend.name | default "frontend" }} +metadata: + name: {{ .Values.frontend.name | default "frontend" }} + namespace: {{ .Release.Namespace }} +spec: + clusterIP: None + type: {{ .Values.frontend.service.type }} + ports: + - name: http + port: {{ .Values.frontend.service.port }} + targetPort: {{ .Values.frontend.service.targetPort }} + protocol: TCP + selector: + workload.user.cattle.io/workloadselector: apps.deployment-{{ .Release.Namespace }}-frontend + strategy: + type: {{ .Values.frontend.strategy.type | default "Recreate" }} \ No newline at end of file diff --git a/helm/templates/services/pgadmin-service.yaml b/helm/templates/services/pgadmin-service.yaml new file mode 100644 index 00000000..38501ab3 --- /dev/null +++ b/helm/templates/services/pgadmin-service.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Service +metadata: + name: pgadmin + namespace: {{ .Release.Namespace }} +spec: + clusterIP: None + type: {{ .Values.postgisPgadmin.pgadminService.type }} + ports: + - name: http + port: {{ .Values.postgisPgadmin.pgadminService.port }} + targetPort: {{ .Values.postgisPgadmin.pgadminService.targetPort }} + protocol: TCP + selector: + workload.user.cattle.io/workloadselector: apps.deployment-{{ .Release.Namespace }}-postgis-pgadmin + strategy: + type: {{ .Values.frontend.strategy.type | default "Recreate" }} \ No newline at end of file diff --git a/helm/templates/services/postgis-service.yaml b/helm/templates/services/postgis-service.yaml new file mode 100644 index 00000000..64042c9f --- /dev/null +++ b/helm/templates/services/postgis-service.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Service +metadata: + name: postgis + namespace: {{ .Release.Namespace }} +spec: + clusterIP: None + type: {{ .Values.postgisPgadmin.postgisService.type }} + ports: + - name: postgis + port: {{ .Values.postgisPgadmin.postgisService.port }} + targetPort: {{ .Values.postgisPgadmin.postgisService.targetPort }} + protocol: TCP + selector: + workload.user.cattle.io/workloadselector: apps.deployment-{{ .Release.Namespace }}-postgis-pgadmin + strategy: + type: {{ .Values.frontend.strategy.type | default "Recreate" }} \ No newline at end of file