diff --git a/.github/workflows/code-checks.yaml b/.github/workflows/code-checks.yaml index 61aeb89e..80e1b71f 100644 --- a/.github/workflows/code-checks.yaml +++ b/.github/workflows/code-checks.yaml @@ -14,7 +14,7 @@ on: jobs: check-code: - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 diff --git a/.gitignore b/.gitignore index 422e58fd..2d947efd 100644 --- a/.gitignore +++ b/.gitignore @@ -132,3 +132,6 @@ dmypy.json static/open-iconic/ repos/ + +#Other +values-local* diff --git a/README.md b/README.md index fdc8330b..8dece4ff 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,9 @@ This repository contains Helm charts maintained by Scaleout Systems AB. The repo **Note:** The main branch is now the new default branch. For getting the latest version of these charts please clone the main branch and not the master. + ## Getting started -To be able to deploy Helm chrats from this repository you first need to add this repository as a source of charts. +To be able to deploy Helm charts from this repository you first need to add this repository as a source of charts. ```bash $ helm repo add scaleout https://scaleoutsystems.github.io/charts/scaleout/stackn diff --git a/scaleout/stackn/.helmignore b/scaleout/stackn/.helmignore index fe7f356e..0cfdee50 100644 --- a/scaleout/stackn/.helmignore +++ b/scaleout/stackn/.helmignore @@ -25,3 +25,5 @@ stackn-*.tgz .vscode/ modules/ examples/ +# Values file +.values-* diff --git a/scaleout/stackn/Chart.yaml b/scaleout/stackn/Chart.yaml index fbdb0ca4..7fbb322e 100644 --- a/scaleout/stackn/Chart.yaml +++ b/scaleout/stackn/Chart.yaml @@ -1,10 +1,8 @@ apiVersion: v1 -appVersion: "0.6.0" -description: A Helm chart for deploying STACKn by Scaleout -name: stackn -version: 0.2.0 +appVersion: "0.17.0" +description: A Helm chart for deploying studio +name: studio +version: 0.5.6 maintainers: - - email: morgan@scaleoutsystems.com - name: Morgan Ekmefjord - email: fredrik@scaleoutsystems.com name: Fredrik Wrede diff --git a/scaleout/stackn/README.md b/scaleout/stackn/README.md index 851838aa..eba92632 100644 --- a/scaleout/stackn/README.md +++ b/scaleout/stackn/README.md @@ -7,38 +7,42 @@ STACKn A Helm chart for deploying STACKn by Scaleout -Current chart version is 0.2.0 +Current chart version is 0.4.1 ## Chart Requirements | Repository | Name | Version | Optional | |------------|------|---------|----------| -| https://charts.bitnami.com/bitnami | postgresql | 11.6.14 | No -| https://charts.bitnami.com/bitnami | postgresql-ha | 9.2.0 | Yes -| https://grafana.github.io/helm-charts | grafana | 6.8.4 | Yes -| https://prometheus-community.github.io/helm-charts | prometheus | 13.8.0 | Yes -| https://stakater.github.io/stakater-charts | reloader | v0.0.86 | No - +| https://charts.bitnami.com/bitnami | postgresql | 12.2.7 | No +| https://charts.bitnami.com/bitnami | redis | 17.7.4 | No +| https://charts.bitnami.com/bitnami | rabbitmq | 11.9.1 | No +| https://charts.bitnami.com/bitnami | common | 2.0.4 | No +| https://stakater.github.io/stakater-charts | reloader | v1.0.15 | Yes + +## Notes +When using PVC's together with postgres, rabbitmq and and redis, credentials will to not sync if secrets are updated (for example if password values are left blank). If this happens, the solution +is to redeploy and delete previous created PVCs. To avoid the same problem again, either set password values or use existing secrets. The subcharts for postgres, rabbitmq and redis all come with a value +to set existing secret. Existing secrets is the recommended approch if are going to version control your values (GitOps) to avoid raw passwords in your version history. + +You can read more about the issue here: https://github.com/bitnami/charts/issues/2061 +Obs that stakater/reloader does not solve the issue. ## Configuration By default STACKn has been configured with a dns wildcard domain for localhost. To change this replace all occurences of studio.127.0.0.1.nip.io in values.yaml. -STACKn requires access to manipulate and create recourses in the k8s cluster. Thus, it needs the cluster config as a secret in ./templates/chart-controller-secret.yaml. - By default no StorageClassName is set and needs to provided in the values.yaml or by using `--set` argument. ### Quick deployment ```bash -# Generate k8s cluster config file - NOTE: we assume a k8s cluster is already installed and configured -cluster_config=$(cat ~/.kube/config | base64 | tr -d '\n') - # Deploy STACKn from this repository -helm install --set kubeconfig=$cluster_config --set global.postgresql.storageClass= stackn . +helm install --set global.postgresql.storageClass= studio . ``` All resources will by default be created in the Namescape "default". -STACKn studio will be avaliable at http://studio.127.0.0.1.nip.io +STACKn studio will be avaliable at https://studio.127.0.0.1.nip.io +Obs that you might have to make changes to your particular ingress controller (nginx is supported in this chart) to connect to the URL. +If the ingress does not work for any reason, you can try to port-forward the studio service port to your localhost. ## Deploy an SSL certificate @@ -47,132 +51,85 @@ For production you need a domain name with a wildcard SSL certificate. If your d kubectl create secret tls prod-ingress --cert fullchain.pem --key privkey.pem ``` -## Global values -Minimal requirement: `global.postgresql.storageClass` - -| Key | Type | Default | Description | -|-----|------|---------|-------------| -| global.studio.existingSecret | string | `""` | Use existing secret. See basic-secrets.yaml. | -| global.studio.storageClass | string | `""` | StorageClassName for PVC. Overrides `studio.storage.storageClass`. If `studio.storage.storageClass` is unset (default) will inherent from `global.postgresql.storageClass` | -| global.studio.superUser | string | `admin` | Django superUser. Obs will always be `admin` until fixed. | -| global.studio.superuserEmail | string | `'admin@test.com'` | Django superUser email. Obs will always be `admin@test.com` until fixed. | -| global.studio.superuserPassword | string | `""` | Django superUser password. If left empty, will generate. | -| global.postgresql.auth.username | string | `stackn` | Postgres user will be created | -| global.postgresql.auth.password | string | `""` | Postgres password for user above. If empty, will be generated and stored in secret `stackn-studio-postgres` | -| global.postgresql.auth.database | string | `stackn` | Postgres database will be created | -| global.postgresql.auth.postgresPassword | string | `""` | Postgres password for postgres user If empty, will be generated and stored in secret `stackn-studio-postgres` | -| global.postgresql.auth.existingSecret | string | `""` | will not create secret `stackn-studio-postgres`. Instead use existing secret for postgres| -| global.postgresql.storageClass | string | `""` | StorageClassName for PVC | - - - -## Values - -Minimal requirement: `kubeconfig` - -| Key | Type | Default | Description | -|-----|------|---------|-------------| -| celeryWorkers.replicas | int | `2` | | -| celeryWorkers.resources.limits.cpu | string | `"1000m"` | | -| celeryWorkers.resources.limits.memory | string | `"8Gi"` | | -| celeryWorkers.resources.requests.cpu | string | `"100m"` | | -| celeryWorkers.resources.requests.memory | string | `"1Gi"` | | -| chartcontroller.branch | string | `"develop"` | | -| chartcontroller.enabled | bool | `false` | | -| chartcontroller.image.pullPolicy | string | `"Always"` | | -| chartcontroller.image.repository | string | `"registry./chart-controller:develop"` | | -| kubeconfig | string | `""` | Encoded (base64) kubernetes config | -| docker-registry.enabled | bool | `false` | | -| docker-registry.ingress.enabled | bool | `true` | | -| docker-registry.ingress.hosts[0] | string | `"registry."` | | -| docker-registry.ingress.tls[0].hosts[0] | string | `"registry."` | | -| docker-registry.ingress.tls[0].secretName | string | `"prod-ingress"` | | -| docker-registry.persistence.accessMode | string | `"ReadWriteOnce"` | | -| docker-registry.persistence.enabled | bool | `true` | | -| docker-registry.persistence.size | string | `"2Gi"` | | -| docker-registry.persistence.storageClass | string | `"microk8s-hostpath"` | | -| domain | string | `studio.` | | -| auth_domain | string | `"stackn-studio.default.svc.cluster.local"` | | -| session_cookie_domain | string | `.` | | -| existingSecret | string | `""` | | -| fixtures | string | `""` | | -| grafana."grafana.ini".server.domain | string | `"grafana."` | | -| grafana."grafana.ini".server.root_url | string | `"%(protocol)s://%(domain)s/"` | | -| grafana."grafana.ini".server.serve_from_sub_path | bool | `true` | | -| grafana.enabled | bool | `false` | | -| grafana.ingress.enabled | bool | `true` | | -| grafana.ingress.hosts[0] | string | `"grafana."` | | -| grafana.ingress.path | string | `"/"` | | -| grafana.ingress.tls[0].hosts[0] | string | `"grafana."` | | -| grafana.ingress.tls[0].secretName | string | `"prod-ingress"` | | -| grafana.persistence.enabled | bool | `true` | | -| grafana.persistence.size | string | `"2Gi"` | | -| grafana.persistence.storageClassName | string | `"microk8s-hostpath"` | | -| grafana.persistence.type | string | `"pvc"` | | -| imagePullSecrets[0].name | string | `"regcred"` | | -| ingress.annotations | object | `{}` | | -| ingress.enabled | bool | `true` | | -| ingress.hosts[0].host | string | `"studio."` | | -| ingress.image.pullPolicy | string | `"Always"` | | -| ingress.image.repository | string | `"scaleoutsystems/ingress:develop"` | | -| ingress.tls[0].hosts[0] | string | `"studio."` | | -| ingress.tls[0].secretName | string | `"prod-ingress"` | | -| namespace | string | `"default"` | | -| postgresql-ha.enabled | bool | `false` | | -| postgresql.enabled | bool | `true` | | -| postgresql.existingSecret | string | `""` | | -| postgresql.fullnameOverride | string | `"stackn-studio-postgres"` | | -| postgresql.persistence.accessModes[0] | string | `"ReadWriteMany"` | | -| postgresql.persistence.enabled | bool | `true` | | -| postgresql.persistence.size | string | `"20Gi"` | | -| postgresql.persistence.storageClass | string | `"microk8s-hostpath"` | | -| postgresql.postgresqlDatabase | string | `"stackn"` | | -| postgresql.postgresqlPassword | string | `""` | | -| postgresql.postgresqlUsername | string | `"stackn"` | | -| prometheus.enabled | bool | `false` | | -| prometheus.server.ingress.enabled | bool | `true` | | -| prometheus.server.ingress.hosts[0] | string | `"prometheus."` | | -| prometheus.server.ingress.tls[0].hosts[0] | string | `"prometheus."` | | -| prometheus.server.ingress.tls[0].secretName | string | `"prod-ingress"` | | -| prometheus.server.persistentVolume.size | string | `"2Gi"` | | -| prometheus.server.persistentVolume.storageClass | string | `"microk8s-hostpath"` | | -| rabbit.password | string | `""` | | -| rabbit.username | string | `"admin"` | | -| reloader.enabled | bool | `true` | | -| reloader.namespace | string | `"default"` | | -| reloader.reloader.watchGlobally | bool | `false` | | -| service.type | string | `"ClusterIP"` | | -| storageClassName | string | `"microk8s-hostpath"` | | -| studio.debug | bool | `true` | | -| studio.init | bool | `true` | | -| studio.kubeconfig_file | string | `/app/chartcontroller/kubeconfig/config` | | -| studio.kubeconfig_dir | string | `/app/chartcontroller/kubeconfig/` | | -| studio.image.pullPolicy | string | `"Always"` | | -| studio.image.repository | string | `"ghcr.io/scaleoutsystems/stackn/studio:develop"` | | -| studio.media.storage.accessModes | string | `"ReadWriteMany"` | | -| studio.media.storage.size | string | `"5Gi"` | | -| studio.media.storage.storageClassName | string | `"microk8s-hostpath"` | | -| studio.replicas | int | `1` | | -| studio.resources.limits.cpu | string | `"1000m"` | | -| studio.resources.limits.memory | string | `"4Gi"` | | -| studio.resources.requests.cpu | string | `"400m"` | | -| studio.resources.requests.memory | string | `"2Gi"` | | -| studio.servicename | string | `"studio"` | | -| studio.static.image | string | `"ghcr.io/scaleoutsystems/stackn/ingress:develop"` | | -| studio.static.replicas | int | `1` | | -| studio.static.resources.limits.cpu | int | `1` | | -| studio.static.resources.limits.memory | string | `"512Mi"` | | -| studio.static.resources.requests.cpu | string | `"100m"` | | -| studio.static.resources.requests.memory | string | `"256Mi"` | | -| studio.storage.StorageClassName | string | `"microk8s-hostpath"` | | -| studio.storage.size | string | `"2Gi"` | | -| studio.superUser | string | `"admin"` | | -| studio.superuserEmail | string | `"admin@test.com"` | | -| studio.superuserPassword | string | `""` | | +This secret should be in the same namespace as studio deployment. + +## Enabling network policies +If networkPolicy.enable = true, you have to make sure the correct kubernetes endpoint IP is provided in networkPolicy.kubernetes.cidr, and the correct port networkPolicy.kubernetes.port. This is to enable access of some services to the kubernetes API server through a created Service Account. To get your cluster's kubernetes endpoint run: +``` +kubectl get endpoints kubernetes +``` + +Further, for ingress resources you need to set networkPolicy.ingress_controller_namespace. If value can vary depending on your cluster configuration, but for NGINX ingress controller it's usually "ingress-nginx". + +## Example deployment +``` +global: + studio: + superuserPassword: adminstudio # Django superuser password, username is admin + postgresql: + auth: + username: studio + password: studiopostgrespass + postgresPassword: postgres + database: studio + storageClass: local-path + +namespace: default +networkPolicy: + enable: true + kubernetes: + cidr: 127.0.0.1/32 # To get kubernetes api server endpoints run: $ kubectl get endpoints kubernetes + port: 6443 + internal_cidr: # in-cluster IpBlock cidr, used in allow-internet-[egress|ingress] policy, e.g: + - 10.0.0.0/8 + - 192.168.0.0/16 + - 172.0.0.0/20 + +studio: + debug: false + inactive_users: false #Users that sign-up can be inactive by default if desired + csrf_trusted_origins: "https://studio.127.0.0.1.nip.io:8082" #extra trusted origin for django server, for example if you port-forward to port 8082 + image: # using a local image registry with hostname k3d-registry + repository: k3d-registry:35187/stackn:develop #This image can be built from Dockerfile (https://github.com/scaleoutsystems/stackn) + pullPolicy: Always # used to ensure that each time we redeploy always pull the latest image + static: + image: k3d-registry:35187/stackn-nginx:develop #This image can be built from Dockerfile.nginx (https://github.com/scaleoutsystems/stackn) + media: + storage: + accessModes: ReadWriteOnce + +accessmode: ReadWriteOnce + +# Postgres deploy with a single-pod database: +postgresql: + primary: + persistence: + size: "2Gi" + accessModes: + - ReadWriteOnce + storageClass: local-path + +rabbit: + password: rabbitmqpass + +redis: + master: + persistence: + enabled: false + replica: + persistence: + enabled: false + +celeryFlower: + enabled: false + +reloader: + enabled: true +``` + ## Maintainers | Name | Email | Url | | ---- | ------ | --- | -| Morgan Ekmefjord | morgan@scaleoutsystems.com | | | Fredrik Wrede | fredrik@scaleoutsystems.com | | diff --git a/scaleout/stackn/charts/common-2.14.1.tgz b/scaleout/stackn/charts/common-2.14.1.tgz new file mode 100644 index 00000000..f443a7c4 Binary files /dev/null and b/scaleout/stackn/charts/common-2.14.1.tgz differ diff --git a/scaleout/stackn/charts/grafana-6.8.4.tgz b/scaleout/stackn/charts/grafana-6.8.4.tgz deleted file mode 100644 index 52228f22..00000000 Binary files a/scaleout/stackn/charts/grafana-6.8.4.tgz and /dev/null differ diff --git a/scaleout/stackn/charts/mongodb-14.4.6.tgz b/scaleout/stackn/charts/mongodb-14.4.6.tgz new file mode 100644 index 00000000..feec5a39 Binary files /dev/null and b/scaleout/stackn/charts/mongodb-14.4.6.tgz differ diff --git a/scaleout/stackn/charts/postgresql-11.6.14.tgz b/scaleout/stackn/charts/postgresql-11.6.14.tgz deleted file mode 100644 index 4fe5253d..00000000 Binary files a/scaleout/stackn/charts/postgresql-11.6.14.tgz and /dev/null differ diff --git a/scaleout/stackn/charts/postgresql-12.2.7.tgz b/scaleout/stackn/charts/postgresql-12.2.7.tgz new file mode 100644 index 00000000..a62d8586 Binary files /dev/null and b/scaleout/stackn/charts/postgresql-12.2.7.tgz differ diff --git a/scaleout/stackn/charts/postgresql-ha-9.2.0.tgz b/scaleout/stackn/charts/postgresql-ha-9.2.0.tgz deleted file mode 100644 index 26b02f84..00000000 Binary files a/scaleout/stackn/charts/postgresql-ha-9.2.0.tgz and /dev/null differ diff --git a/scaleout/stackn/charts/prometheus-13.8.0.tgz b/scaleout/stackn/charts/prometheus-13.8.0.tgz deleted file mode 100644 index 7f876480..00000000 Binary files a/scaleout/stackn/charts/prometheus-13.8.0.tgz and /dev/null differ diff --git a/scaleout/stackn/charts/reloader-v0.0.86.tgz b/scaleout/stackn/charts/reloader-v0.0.86.tgz deleted file mode 100644 index b3399b0c..00000000 Binary files a/scaleout/stackn/charts/reloader-v0.0.86.tgz and /dev/null differ diff --git a/scaleout/stackn/charts/reloader-v1.0.15.tgz b/scaleout/stackn/charts/reloader-v1.0.15.tgz new file mode 100644 index 00000000..9505045d Binary files /dev/null and b/scaleout/stackn/charts/reloader-v1.0.15.tgz differ diff --git a/scaleout/stackn/requirements.yaml b/scaleout/stackn/requirements.yaml index 526a90b3..a660b45c 100644 --- a/scaleout/stackn/requirements.yaml +++ b/scaleout/stackn/requirements.yaml @@ -1,41 +1,23 @@ # version x.x.x corresponds to "latest" dependencies: - # - name: openfaas - # version: 5.6.5 - # repository: "https://openfaas.github.io/faas-netes/" - # condition: openfaas.enabled - - # - name: argo-events - # version: 0.14.0 - # repository: "https://argoproj.github.io/argo-helm" - # condition: argo-events.enabled - - # - name: argo - # version: 0.7.3 - # repository: "https://argoproj.github.io/argo-helm" - # condition: argo.enabled - - - name: prometheus - version: 13.8.0 - repository: https://prometheus-community.github.io/helm-charts - condition: prometheus.enabled - - - name: grafana - version: 6.8.4 - repository: https://grafana.github.io/helm-charts - condition: grafana.enabled - name: reloader - version: v0.0.86 + version: v1.0.15 repository: https://stakater.github.io/stakater-charts condition: reloader.enabled - - name: postgresql-ha - version: 9.2.0 - repository: https://charts.bitnami.com/bitnami - condition: postgresql-ha.enabled - - name: postgresql - version: 11.6.14 + version: 12.2.7 repository: https://charts.bitnami.com/bitnami condition: postgresql.enabled + + - name: common + repository: https://charts.bitnami.com/bitnami + tags: + - bitnami-common + version: 2.14.1 + + - name: mongodb + repository: https://charts.bitnami.com/bitnami + version: 14.4.6 + condition: mongodb.enabled diff --git a/scaleout/stackn/templates/_helper.tpl b/scaleout/stackn/templates/_helper.tpl index 03775630..fc782151 100644 --- a/scaleout/stackn/templates/_helper.tpl +++ b/scaleout/stackn/templates/_helper.tpl @@ -25,7 +25,7 @@ Get the STACKn password secret. {{- else if .Values.existingSecret -}} {{- printf "%s" (tpl .Values.existingSecret $) -}} {{- else -}} - stackn + {{ include "common.names.fullname" . }} {{- end -}} {{- end -}} @@ -101,7 +101,6 @@ Return postgres secret {* HOLDER FOR HA MODE IN FUTURE RELEASE *} {{- end -}} {{- end -}} - {{/* Return STACKn studio storageClass */}} @@ -126,27 +125,4 @@ Return STACKn studio media storageClass {{- else -}} {{- .Values.global.postgresql.storageClass -}} {{- end -}} -{{- end -}} - - -{{/* -Return STACKn rabbit password -*/}} -{{- define "stackn.rabbit.password" -}} -{{- if .Values.rabbit.password -}} - {{- .Values.rabbit.password -}} -{{- else -}} - {{- randAlphaNum 10 -}} -{{- end -}} -{{- end -}} - -{{/* -Return STACKn rabbit username -*/}} -{{- define "stackn.rabbit.username" -}} -{{- if .Values.rabbit.username -}} - {{- .Values.rabbit.username -}} -{{- else -}} - admin -{{- end -}} -{{- end -}} +{{- end -}} \ No newline at end of file diff --git a/scaleout/stackn/templates/basic-secrets.yaml b/scaleout/stackn/templates/basic-secrets.yaml index a6da9c53..06aea97e 100644 --- a/scaleout/stackn/templates/basic-secrets.yaml +++ b/scaleout/stackn/templates/basic-secrets.yaml @@ -8,6 +8,17 @@ metadata: namespace: {{ .Release.Namespace }} type: Opaque data: - studio-superuser-password: {{ include "stackn.studio.superuser.password" . | b64enc | quote }} - rabbit-password: {{ include "stackn.rabbit.password" . | b64enc | quote }} + studio-superuser-password: {{ include "common.secrets.passwords.manage" (dict "secret" (include "common.names.fullname" .) "key" "studio-superuser-password" "providedValues" (list "global.studio.superuserPassword" "studio.superuserPassword") "context" $) }} + studio-event-listener-user-password: {{ include "common.secrets.passwords.manage" (dict "secret" (include "common.names.fullname" .) "key" "studio-event-listener-user-password" "providedValues" (list "global.studio.eventListenerUserPassword" "studio.eventListenerUserPassword") "context" $) }} + studio-argocd-token: {{ .Values.studio.argocd.token | b64enc }} + django-secret-key: {{ include "common.secrets.passwords.manage" (dict "secret" (include "common.names.fullname" .) "key" "django-secret-key" "providedValues" (list "studio.djangoSecret") "length" 50 "strong" true "context" $) }} + {{ if .Values.studio.emailService.enabled }} + email-host-user: {{ .Values.studio.emailService.hostUser | b64enc }} + email-host-password: {{ .Values.studio.emailService.hostPassword | b64enc }} + email-api-key: {{ .Values.studio.emailService.apiKey | b64enc }} + argo-cd-token: {{ .Values.studio.argocd.token | b64enc }} + {{ end }} + {{ if .Values.studio.harbor.enabled }} + harbor-creds: {{ printf "%s:%s" .Values.studio.harbor.username .Values.studio.harbor.password | b64enc | b64enc }} + {{ end }} {{- end -}} \ No newline at end of file diff --git a/scaleout/stackn/templates/celery-beat-deployment.yaml b/scaleout/stackn/templates/celery-beat-deployment.yaml deleted file mode 100644 index aabce71e..00000000 --- a/scaleout/stackn/templates/celery-beat-deployment.yaml +++ /dev/null @@ -1,102 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - annotations: - kompose.cmd: kompose convert - kompose.version: 1.20.0 () - creationTimestamp: null - labels: - io.kompose.service: {{ .Release.Name }}-celery-beat - name: {{ .Release.Name }}-celery-beat - name: {{ .Release.Name }}-celery-beat -spec: - replicas: 1 - strategy: - type: Recreate - selector: - matchLabels: - name: {{ .Release.Name }}-celery-beat - template: - metadata: - annotations: - kompose.cmd: kompose convert - kompose.version: 1.20.0 () - creationTimestamp: null - labels: - io.kompose.service: {{ .Release.Name }}-celery-beat - name: {{ .Release.Name }}-celery-beat - spec: - initContainers: - - name: wait-for-db - image: postgres - command: ['sh', '-c', 'until pg_isready --host={{ .Values.postgresql.fullnameOverride }}.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local --port={{ .Values.postgresql.primary.service.ports.postgresql }}; do echo waiting for database; sleep 5; done;'] - resources: - limits: - cpu: "100m" - memory: "512Mi" - requests: - cpu: "100m" - memory: "512Mi" - - name: wait-for-studio - image: busybox - command: ['sh', '-c', "until nslookup {{ .Release.Name }}-{{ .Values.studio.servicename }}.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for {{ .Release.Name }}-{{ .Values.studio.servicename }} service; sleep 30; done"] - resources: - limits: - cpu: "100m" - memory: "512Mi" - requests: - cpu: "100m" - memory: "512Mi" - containers: - - args: - - sh - - ./scripts/run_beat.sh - env: - - name: BASE_PATH - value: "/app" - - name: KUBECONFIG - value: {{ .Values.studio.kubeconfig_file | quote }} - - name: GET_HOSTS_FROM - value: dns - - name: POSTGRES_DB - value: {{ .Values.postgresql.global.postgresql.auth.database }} - - name: POSTGRES_USER - value: {{ .Values.postgresql.global.postgresql.auth.database }} - - name: POSTGRES_PASSWORD - valueFrom: - secretKeyRef: - name: {{ include "stackn.postgres.secretName" . }} - key: password - - name: RABBITMQ_DEFAULT_PASS - valueFrom: - secretKeyRef: - name: {{ include "stackn.secretName" . }} - key: rabbit-password - image: {{ .Values.studio.image.repository }} - imagePullPolicy: {{ .Values.studio.image.pullPolicy }} - name: {{ .Release.Name }}-celery-beat - resources: - limits: - cpu: "500m" - memory: "4Gi" - requests: - cpu: "100m" - memory: "512Mi" - volumeMounts: - - mountPath: /app/studio/settings.py - subPath: settings.py - name: {{ .Release.Name}}-settings-configmap - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - restartPolicy: Always - volumes: - - name: {{ .Release.Name}}-settings-configmap - configMap: - name: {{ .Release.Name}}-settings-configmap - items: - - key: settings.py - path: settings.py - -status: {} diff --git a/scaleout/stackn/templates/celery-worker-deployment.yaml b/scaleout/stackn/templates/celery-worker-deployment.yaml deleted file mode 100644 index a55914a0..00000000 --- a/scaleout/stackn/templates/celery-worker-deployment.yaml +++ /dev/null @@ -1,107 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - annotations: - reloader.stakater.com/auto: "true" - labels: - io.kompose.service: {{ .Release.Name }}-celery-worker - name: {{ .Release.Name }}-celery-worker - name: {{ .Release.Name }}-celery-worker -spec: - replicas: {{ .Values.celeryWorkers.replicas | default 2 }} - strategy: - type: Recreate - selector: - matchLabels: - name: {{ .Release.Name }}-celery-worker - template: - metadata: - annotations: - kompose.cmd: kompose convert - kompose.version: 1.20.0 () - creationTimestamp: null - labels: - io.kompose.service: {{ .Release.Name }}-celery-worker - name: {{ .Release.Name }}-celery-worker - spec: - initContainers: - - name: wait-for-db - image: postgres - command: ['sh', '-c', 'until pg_isready --host={{ .Values.postgresql.fullnameOverride }}.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local --port={{ .Values.postgresql.primary.service.ports.postgresql }}; do echo waiting for database; sleep 5; done;'] - resources: - limits: - cpu: "100m" - memory: "512Mi" - requests: - cpu: "100m" - memory: "512Mi" - - name: wait-for-studio - image: busybox - command: ['sh', '-c', "until nslookup {{ .Release.Name }}-{{ .Values.studio.servicename }}.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for {{ .Release.Name }}-{{ .Values.studio.servicename }} service; sleep 5; done"] - resources: - limits: - cpu: "100m" - memory: "512Mi" - requests: - cpu: "100m" - memory: "512Mi" - containers: - - args: - - sh - - ./scripts/run_worker.sh - env: - - name: BASE_PATH - value: "/app" - - name: GET_HOSTS_FROM - value: dns - - name: POSTGRES_PASSWORD - valueFrom: - secretKeyRef: - name: {{ include "stackn.postgres.secretName" . }} - key: password - - name: RABBITMQ_DEFAULT_PASS - valueFrom: - secretKeyRef: - name: {{ include "stackn.secretName" . }} - key: rabbit-password - - name: KUBECONFIG - value: {{ .Values.studio.kubeconfig_file | quote }} - image: {{ .Values.studio.image.repository }} - imagePullPolicy: {{ .Values.studio.image.pullPolicy }} - name: {{ .Release.Name }}-celery-worker - resources: - limits: - cpu: {{ .Values.celeryWorkers.resources.limits.cpu }} - memory: {{ .Values.celeryWorkers.resources.limits.memory }} - requests: - cpu: {{ .Values.celeryWorkers.resources.requests.cpu }} - memory: {{ .Values.celeryWorkers.resources.requests.memory }} - volumeMounts: - - name: config - mountPath: {{ .Values.studio.kubeconfig_dir | quote }} - readOnly: true - - mountPath: /app/studio/settings.py - subPath: settings.py - name: {{ .Release.Name}}-settings-configmap - - name: mediavol - mountPath: {{ .Values.studio.media.mount_path }} - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - restartPolicy: Always - volumes: - - name: config - secret: - secretName: {{ .Release.Name }}-chart-controller-secret - - name: {{ .Release.Name}}-settings-configmap - configMap: - name: {{ .Release.Name}}-settings-configmap - items: - - key: settings.py - path: settings.py - - name: mediavol - persistentVolumeClaim: - claimName: {{ .Release.Name }}-studio-media - -status: {} diff --git a/scaleout/stackn/templates/chart-controller-secret.yaml b/scaleout/stackn/templates/chart-controller-secret.yaml deleted file mode 100644 index 988d3327..00000000 --- a/scaleout/stackn/templates/chart-controller-secret.yaml +++ /dev/null @@ -1,9 +0,0 @@ -{{- if .Values.chartcontroller.addSecret }} -apiVersion: v1 -kind: Secret -metadata: - name: {{ .Release.Name }}-chart-controller-secret -type: Opaque -data: - config: {{ .Values.kubeconfig }} -{{- end }} diff --git a/scaleout/stackn/templates/cloudnativepg-cluster.yaml b/scaleout/stackn/templates/cloudnativepg-cluster.yaml new file mode 100644 index 00000000..3161b2c0 --- /dev/null +++ b/scaleout/stackn/templates/cloudnativepg-cluster.yaml @@ -0,0 +1,58 @@ +{{ if and .Values.studio.cloudnativepg.enabled .Values.studio.cloudnativepg.create_new }} +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + name: {{ .Values.studio.cloudnativepg.clusterName }} +spec: + instances: {{ .Values.studio.cloudnativepg.spec.instances }} + storage: + size: {{ .Values.studio.cloudnativepg.spec.storage.size }} + {{ if .Values.studio.minio_backup.enabled }} + backup: + barmanObjectStore: + destinationPath: s3://studio-backups + serverName: {{ .Values.studio.cloudnativepg.clusterName }} + endpointURL: {{ .Values.studio.minio_backup.host }}:{{ .Values.studio.minio_backup.port }} + s3Credentials: + accessKeyId: + name: {{ .Values.studio.minio_backup.secretName }} + key: access_key + secretAccessKey: + name: {{ .Values.studio.minio_backup.secretName }} + key: secret_key + {{ end }} +--- +# Base backup runs at midnight every day +{{ if .Values.studio.minio_backup.enabled}} +apiVersion: postgresql.cnpg.io/v1 +kind: ScheduledBackup +metadata: + name: base-backup +spec: + schedule: "0 0 0 * * *" + backupOwnerReference: self + cluster: + name: studio-db +{{ end }} +{{ end }} + + + +# Example of how to bootstrap from backups for a cluster +# called studio-cluster2 + # bootstrap: + # recovery: + # source: studio-cluster2 + + # externalClusters: + # - name: studio-cluster2 + # barmanObjectStore: + # destinationPath: s3://studio-backups + # endpointURL: http://minio-fedn-hl:9000 + # s3Credentials: + # accessKeyId: + # name: aws-creds + # key: ACCESS_KEY_ID + # secretAccessKey: + # name: aws-creds + # key: ACCESS_SECRET_KEY \ No newline at end of file diff --git a/scaleout/stackn/templates/deployment-frontend.yaml b/scaleout/stackn/templates/deployment-frontend.yaml new file mode 100644 index 00000000..486994c3 --- /dev/null +++ b/scaleout/stackn/templates/deployment-frontend.yaml @@ -0,0 +1,81 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: fedn-frontend +spec: + replicas: {{ .Values.frontend.replicas }} + selector: + matchLabels: + app: fedn-frontend + strategy: + type: {{ .Values.frontend.strategy.type }} + template: + metadata: + labels: + app: fedn-frontend + spec: + automountServiceAccountToken: {{ .Values.frontend.automountServiceAccountToken }} + {{- if .Values.frontend.securityContext.enabled }} + securityContext: + runAsUser: {{ .Values.frontend.securityContext.runAsUser }} + runAsGroup: {{ .Values.frontend.securityContext.runAsGroup }} + fsGroup: {{ .Values.frontend.securityContext.fsGroup }} + allowPrivilegeEscalation: {{ .Values.frontend.securityContext.allowPrivilegeEscalation }} + privileged: {{ .Values.frontend.securityContext.privileged }} + readOnlyRootFilesystem: {{ .Values.frontend.securityContext.readOnlyRootFilesystem }} + runAsNonRoot: {{ .Values.frontend.securityContext.runAsNonRoot }} + capabilities: + drop: + - ALL + {{- end }} + imagePullSecrets: + - name: {{ .Values.frontend.image.pullSecret }} + containers: + - name: fedn-frontend + imagePullPolicy: {{ .Values.frontend.image.pullPolicy }} + image: {{ .Values.frontend.image.repository | default "harbor.scaleoutsystems.com/fedn/fedn-front-end:main" }} + ports: + - containerPort: 3000 + env: + {{ if .Values.frontend.debug }} + - name: NODE_ENV + value: "development" + {{ end }} + - name: API_URL + value: {{ printf "http://%s-%s:8080" .Release.Name .Values.studio.servicename | quote }} + - name: NEXT_PUBLIC_API_DOMAIN + value: {{ .Values.domain | quote }} + - name: NEXT_PUBLIC_USE_FEDN_PROXY + value: "true" + {{ if .Values.frontend.recaptcha.enabled }} + - name: RECAPTCHA_SECRET_KEY + valueFrom: + secretKeyRef: + name: {{ .Values.frontend.recaptcha.existingSecret }} + key: {{ .Values.frontend.recaptcha.existingSecretKey }} + - name: NEXT_PUBLIC_RECAPTCHA_SITE_KEY + value: {{ .Values.frontend.recaptcha.siteKey }} + - name: NEXT_PUBLIC_RECAPTCHA_ACTION) + value: {{ .Values.frontend.recaptcha.action }} + {{ end }} + resources: + limits: + cpu: {{ .Values.frontend.resources.limits.cpu }} + memory: {{ .Values.frontend.resources.limits.memory }} + requests: + cpu: {{ .Values.frontend.resources.requests.cpu }} + memory: {{ .Values.frontend.resources.requests.memory }} + {{- if .Values.frontend.readinessProbe.enabled }} + readinessProbe: + tcpSocket: + port: {{ .Values.frontend.readinessProbe.tcpSocket.port }} + initialDelaySeconds: {{ .Values.frontend.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.frontend.readinessProbe.periodSeconds }} + {{- end }} + {{- if .Values.frontend.livenessProbe.enabled }} + livenessProbe: + tcpSocket: + port: {{ .Values.frontend.livenessProbe.tcpSocket.port }} + initialDelaySeconds: {{ .Values.frontend.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.frontend.livenessProbe.periodSeconds }} + {{- end }} diff --git a/scaleout/stackn/templates/event-listener-deployment.yaml b/scaleout/stackn/templates/event-listener-deployment.yaml new file mode 100644 index 00000000..763a2b9d --- /dev/null +++ b/scaleout/stackn/templates/event-listener-deployment.yaml @@ -0,0 +1,68 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + name: studio-event-listener + name: studio-event-listener +spec: + replicas: 1 + strategy: + type: RollingUpdate + selector: + matchLabels: + name: studio-event-listener + template: + metadata: + labels: + name: studio-event-listener + app: stackn-studio + allow-api-access: "true" + spec: + automountServiceAccountToken: true + serviceAccountName: studio + imagePullSecrets: + - name: {{ .Values.eventListener.image.pullSecret }} + containers: + - image: "{{ .Values.eventListener.image.repository | default "harbor.scaleoutsystems.com/studio/studio-kube-controller:{{ .Chart.AppVersion }}" }}" + imagePullPolicy: {{ .Values.eventListener.image.pullPolicy }} + name: studio-event-listener + resources: + limits: + cpu: 100m + memory: 200Mi + requests: + cpu: 50m + memory: 20Mi + {{- if .Values.studio.securityContext.enabled }} + securityContext: + runAsUser: {{ .Values.studio.securityContext.runAsUser }} + runAsGroup: {{ .Values.studio.securityContext.runAsGroup }} + allowPrivilegeEscalation: {{ .Values.studio.securityContext.allowPrivilegeEscalation }} + privileged: {{ .Values.studio.securityContext.privileged }} + capabilities: + drop: + - all + {{- end }} + env: + - name: STUDIO_SERVICE_NAME + value: {{ .Values.eventListener.studioServiceName | quote }} + - name: STUDIO_SERVICE_PORT + value: {{ .Values.eventListener.studioServicePort | quote }} + - name: APP_STATUS_ENDPOINT + value: {{ .Values.eventListener.appStatusEndpoint | quote }} + - name: APP_STATUSES_ENDPOINT + value: {{ .Values.eventListener.appStatusesEndpoint | quote }} + restartPolicy: Always + securityContext: + fsGroup: {{ .Values.studio.securityContext.fsGroup }} + initContainers: + - name: wait-for-studio + image: busybox:1.28.4 + command: ['sh', '-c', "until nslookup {{ .Release.Name }}-{{ .Values.studio.servicename }}; do echo waiting for {{ .Release.Name }}-{{ .Values.studio.servicename }} service; sleep 30; done"] + resources: + limits: + cpu: "100m" + memory: "512Mi" + requests: + cpu: "100m" + memory: "512Mi" diff --git a/scaleout/stackn/templates/grpc-ingress.yaml b/scaleout/stackn/templates/grpc-ingress.yaml new file mode 100644 index 00000000..fa35b421 --- /dev/null +++ b/scaleout/stackn/templates/grpc-ingress.yaml @@ -0,0 +1,37 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ .Release.Name }}-grpc-ingress + annotations: + nginx.ingress.kubernetes.io/configuration-snippet: | + if ($request_uri ~* "^/fedn.Connector/AcceptingClients") { return 403; } + if ($request_uri ~* "^/fedn.Connector/ListActiveClients") { return 403; } + if ($request_uri ~* "^/fedn.Control/Start") { return 403; } + if ($request_uri ~* "^/fedn.Control/Stop") { return 403; } + if ($request_uri ~* "^/fedn.Control/FlushAggregationQueue") { return 403; } + if ($request_uri ~* "^/fedn.Control/SetAggregator") { return 403; } + if ($http_grpc_server) { grpc_pass grpc://$http_grpc_server.default.svc.cluster.local:12080; } + nginx.ingress.kubernetes.io/proxy-body-size: "0" + nginx.ingress.kubernetes.io/proxy-set-headers: X-Forwarded-Proto:$scheme + nginx.ingress.kubernetes.io/server-snippet: | + grpc_read_timeout 86400s; + grpc_send_timeout 86400s; + labels: + io.kompose.service: {{ .Release.Name }}-ingress +spec: + ingressClassName: nginx + tls: + - hosts: + - {{ .Values.grpc_domain }} + secretName: prod-ingress + rules: + - host: {{ .Values.grpc_domain }} + http: + paths: + - path: / + backend: + service: + name: {{ $.Release.Name }}-studio + port: + number: 8080 + pathType: Prefix diff --git a/scaleout/stackn/templates/ingress-frontend.yaml b/scaleout/stackn/templates/ingress-frontend.yaml new file mode 100644 index 00000000..1dab263c --- /dev/null +++ b/scaleout/stackn/templates/ingress-frontend.yaml @@ -0,0 +1,32 @@ +{{- if .Values.frontend.ingress.enabled }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: fedn-frontend-ingress + namespace: default + annotations: + nginx.ingress.kubernetes.io/rewrite-target: / +spec: + ingressClassName: nginx + rules: + {{- range .Values.frontend.ingress.hosts }} + - host: {{ . | quote }} + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: {{ $.Values.frontend.service.name }} + port: + number: {{ $.Values.frontend.service.port }} + {{- end }} + {{- if .Values.frontend.ingress.tls.enabled }} + tls: + - hosts: + {{- range .Values.frontend.ingress.tls.hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .Values.frontend.ingress.tls.existingSecret }} + {{- end }} +{{- end }} diff --git a/scaleout/stackn/templates/ingress-platform.yaml b/scaleout/stackn/templates/ingress-platform.yaml index 7e53f36b..d0be4cda 100644 --- a/scaleout/stackn/templates/ingress-platform.yaml +++ b/scaleout/stackn/templates/ingress-platform.yaml @@ -4,13 +4,14 @@ kind: Ingress metadata: name: {{ .Release.Name }}-ingress annotations: - {{- with .Values.ingress.annotations }} - {{- toYaml . | nindent 4 }} - {{- end }} + nginx.ingress.kubernetes.io/configuration-snippet: | + if ($request_uri ~ ^/api/internal) { return 403; } + nginx.ingress.kubernetes.io/proxy-body-size: "0" + nginx.ingress.kubernetes.io/proxy-set-headers: X-Forwarded-Proto:$scheme labels: io.kompose.service: {{ .Release.Name }}-ingress spec: - # ingressClassName: public + ingressClassName: nginx {{- if .Values.ingress.tls }} tls: {{- range .Values.ingress.tls }} @@ -29,22 +30,24 @@ spec: - path: / backend: service: - name: {{ $.Release.Name }}-studio + name: fedn-frontend-service port: - number: 8080 + number: 80 pathType: ImplementationSpecific - - path: /static/ + - path: /api/ backend: service: - {{ if $.Values.studio.debug }} name: {{ $.Release.Name }}-studio port: number: 8080 - {{ else }} + pathType: ImplementationSpecific + {{- if $.Values.studio.static.enabled }} + - path: /static/ + backend: + service: name: {{ $.Release.Name }}-static port: number: 8081 - {{ end }} pathType: ImplementationSpecific - path: /media/ backend: @@ -53,6 +56,7 @@ spec: port: number: 8081 pathType: ImplementationSpecific + {{- end }} {{- end }} {{- end }} diff --git a/scaleout/stackn/templates/media-vol.yaml b/scaleout/stackn/templates/media-vol.yaml deleted file mode 100644 index 579c60b6..00000000 --- a/scaleout/stackn/templates/media-vol.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: {{ .Release.Name }}-studio-media - annotations: - "helm.sh/resource-policy": keep -spec: - accessModes: - - {{ .Values.studio.media.storage.accessModes | default "ReadWriteMany"}} - storageClassName: {{ include "stackn.studio.media.storageclass" . }} - resources: - requests: - storage: {{ .Values.studio.media.storage.size | default "5Gi" }} diff --git a/scaleout/stackn/templates/mongo-express-deployment.yaml b/scaleout/stackn/templates/mongo-express-deployment.yaml new file mode 100644 index 00000000..e0413b6c --- /dev/null +++ b/scaleout/stackn/templates/mongo-express-deployment.yaml @@ -0,0 +1,62 @@ +{{ if .Values.mongoexpress.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Release.Name }}-mongo-express + namespace: {{ .Values.namespace }} + annotations: + reloader.stakater.com/auto: "true" +spec: + replicas: {{ .Values.mongoexpress.replicas }} + selector: + matchLabels: + release: {{ .Release.Name }} + app: stackn-studio + pod: mongo-express + template: + metadata: + labels: + release: {{ .Release.Name }} + app: stackn-studio + networking/allow-internet-egress: "false" + type: app + pod: mongo-express + spec: + automountServiceAccountToken: false + enableServiceLinks: false + initContainers: + - name: wait-for-db + image: busybox + env: + - name: DB_SERVICE + value: {{ include "mongodb.service.nameOverride" .Subcharts.mongodb }} + - name: DB_PORT + value: {{ .Values.mongodb.service.ports.mongodb | quote }} + command: ["sh", "-c", "until nc -z $DB_SERVICE $DB_PORT > /dev/null; do echo Waiting for master.; sleep 2; done;"] + containers: + - name: mongo-express + image: mongo-express:latest + env: + - name: ME_CONFIG_MONGODB_ENABLE_ADMIN + value: "true" + - name: ME_CONFIG_BASICAUTH + value: "false" + - name: ME_CONFIG_BASICAUTH_USERNAME + value: "" + - name: ME_CONFIG_BASICAUTH_PASSWORD + value: "" + - name: ME_CONFIG_MONGODB_AUTH_USERNAME + value: {{ .Values.mongodb.auth.rootUser }} + - name: ME_CONFIG_MONGODB_AUTH_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "mongodb.fullname" .Subcharts.mongodb }} + key: mongodb-root-password + - name: ME_CONFIG_MONGODB_SERVER + value: {{ include "mongodb.service.nameOverride" .Subcharts.mongodb }} + - name: ME_CONFIG_MONGODB_PORT + value: {{ .Values.mongodb.service.ports.mongodb | quote }} + imagePullPolicy: IfNotPresent + ports: + - containerPort: 8081 +{{- end }} \ No newline at end of file diff --git a/scaleout/stackn/templates/mongo-express-service.yaml b/scaleout/stackn/templates/mongo-express-service.yaml new file mode 100644 index 00000000..c2871b36 --- /dev/null +++ b/scaleout/stackn/templates/mongo-express-service.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Release.Name }}-mongo-express + namespace: {{ .Values.namespace }} +spec: + ports: + - port: {{ .Values.mongoexpress.service.port }} + targetPort: 8081 + protocol: TCP + selector: + release: {{ .Release.Name }} \ No newline at end of file diff --git a/scaleout/stackn/templates/mongodb-backup-job.yaml b/scaleout/stackn/templates/mongodb-backup-job.yaml new file mode 100644 index 00000000..e5077abf --- /dev/null +++ b/scaleout/stackn/templates/mongodb-backup-job.yaml @@ -0,0 +1,47 @@ +{{ if .Values.mongodb.backups.enabled }} +apiVersion: batch/v1 +kind: CronJob +metadata: + name: mongodb-backup-to-minio +spec: + schedule: {{ .Values.mongodb.backups.backupSchedule | default "*/30 * * * *" | quote}} + jobTemplate: + spec: + template: + spec: + imagePullSecrets: + - name: {{ .Values.imagePullSecrets.name }} + containers: + - name: mongo-backup + image: {{ .Values.mongodb.backups.image }} + imagePullPolicy: Always + env: + - name: MONGO_SERVICE_HOST + value: {{ include "mongodb.service.nameOverride" .Subcharts.mongodb }} + - name: MONGO_SERVICE_PORT + value: {{ .Values.mongodb.service.ports.mongodb | quote }} + - name: MONGO_USERNAME + value: {{ .Values.mongodb.auth.rootUser | quote }} + - name: MONGO_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "mongodb.fullname" .Subcharts.mongodb }} + key: mongodb-root-password + - name: S3HOST + value: {{ .Values.studio.minio_backup.host }} + - name: S3PORT + value: {{ .Values.studio.minio_backup.port | quote }} + - name : S3BUCKET + value: {{ .Values.studio.minio_backup.mongodb_bucket }} + - name: S3ACCESS_KEY + valueFrom: + secretKeyRef: + name: {{ .Values.studio.minio_backup.secretName }} + key: access_key + - name: S3SECRET_KEY + valueFrom: + secretKeyRef: + name: {{ .Values.studio.minio_backup.secretName }} + key: secret_key + restartPolicy: OnFailure +{{ end }} \ No newline at end of file diff --git a/scaleout/stackn/templates/mongorestorejob.yaml b/scaleout/stackn/templates/mongorestorejob.yaml new file mode 100644 index 00000000..ee13fcff --- /dev/null +++ b/scaleout/stackn/templates/mongorestorejob.yaml @@ -0,0 +1,55 @@ +{{ if eq .Values.mongodb.restoreFromFile.enabled true }} +apiVersion: batch/v1 +kind: Job +metadata: + name: mongodb-restore-job +spec: + template: + spec: + imagePullSecrets: + - name: {{ .Values.imagePullSecrets.name }} + initContainers: + - name: wait-for-db + image: busybox + env: + - name: DB_SERVICE + value: {{ include "mongodb.service.nameOverride" .Subcharts.mongodb }} + - name: DB_PORT + value: {{ .Values.mongodb.service.ports.mongodb | quote }} + command: ["sh", "-c", "until nc -z $DB_SERVICE $DB_PORT > /dev/null; do echo Waiting for master.; sleep 2; done;"] + containers: + - name: mongo-restore + image: {{ .Values.mongodb.restoreFromFile.image }} + imagePullPolicy: Always + env: + - name: MONGO_SERVICE_HOST + value: {{ include "mongodb.service.nameOverride" .Subcharts.mongodb }} + - name: MONGO_SERVICE_PORT + value: {{ .Values.mongodb.service.ports.mongodb | quote }} + - name: MONGO_USERNAME + value: {{ .Values.mongodb.auth.rootUser | quote }} + - name: MONGO_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "mongodb.fullname" .Subcharts.mongodb }} + key: mongodb-root-password + - name: S3HOST + value: {{ .Values.studio.minio_backup.host }} + - name: S3PORT + value: {{ .Values.studio.minio_backup.port | quote }} + - name : S3BUCKET + value: mongodb-backups + - name: S3ACCESS_KEY + valueFrom: + secretKeyRef: + name: {{ .Values.studio.minio_backup.secretName }} + key: access_key + - name: S3SECRET_KEY + valueFrom: + secretKeyRef: + name: {{ .Values.studio.minio_backup.secretName }} + key: secret_key + - name: BACKUPFILENAME + value: {{ .Values.mongodb.restoreFromFile.backupFileName }} + restartPolicy: OnFailure +{{ end }} \ No newline at end of file diff --git a/scaleout/stackn/templates/network-policies.yaml b/scaleout/stackn/templates/network-policies.yaml new file mode 100644 index 00000000..bfbaee76 --- /dev/null +++ b/scaleout/stackn/templates/network-policies.yaml @@ -0,0 +1,286 @@ +# {{- if .Values.networkPolicy.enable }} +# apiVersion: networking.k8s.io/v1 +# kind: NetworkPolicy +# metadata: +# name: default-deny-ingress +# namespace: {{ .Values.namespace | default "default" }} +# spec: +# podSelector: +# matchLabels: {} +# policyTypes: +# - Ingress +# --- +# apiVersion: networking.k8s.io/v1 +# kind: NetworkPolicy +# metadata: +# name: default-deny-egress +# namespace: {{ .Values.namespace | default "default" }} +# spec: +# podSelector: +# matchLabels: {} +# policyTypes: +# - Egress +# egress: +# - to: +# - namespaceSelector: +# matchLabels: +# kubernetes.io/metadata.name: kube-system +# ports: +# - protocol: UDP +# port: 53 +# - protocol: TCP +# port: 53 +# --- +# # Certain services (such as celery-workers) need to allow egress to k8s api-server +# # To get the IP and port (usually 6443) of the api-server: +# # $ kubectl get endpoints kubernetes +# apiVersion: networking.k8s.io/v1 +# kind: NetworkPolicy +# metadata: +# name: {{ .Release.Name }}-allow-api-access +# namespace: {{ .Values.namespace | default "default" }} +# spec: +# podSelector: +# matchLabels: +# allow-api-access: "true" +# policyTypes: +# - Egress +# egress: +# - to: +# - ipBlock: +# cidr: {{ .Values.networkPolicy.kubernetes.cidr }} +# ports: +# - protocol: TCP +# port: {{ .Values.networkPolicy.kubernetes.port }} +# --- +# {{- if .Values.reloader.enabled }} +# apiVersion: networking.k8s.io/v1 +# kind: NetworkPolicy +# metadata: +# name: reloader-allow-api-access +# namespace: {{ .Values.namespace | default "default" }} +# spec: +# podSelector: +# matchLabels: +# app: {{ .Release.Name }}-reloader +# policyTypes: +# - Egress +# egress: +# - to: +# - ipBlock: +# cidr: {{ .Values.networkPolicy.kubernetes.cidr }} +# ports: +# - protocol: TCP +# port: {{ .Values.networkPolicy.kubernetes.port }} +# --- +# apiVersion: networking.k8s.io/v1 +# kind: NetworkPolicy +# metadata: +# name: allow-egress-to-reloader +# namespace: {{ .Values.namespace | default "default" }} +# spec: +# podSelector: +# matchLabels: +# app: {{ .Release.Name }}-reloader +# policyTypes: +# - Egress +# egress: +# - to: +# - podSelector: +# matchLabels: +# app: {{ .Release.Name }}-reloader +# --- +# apiVersion: networking.k8s.io/v1 +# kind: NetworkPolicy +# metadata: +# name: allow-ingress-from-reloader +# namespace: {{ .Values.namespace | default "default" }} +# spec: +# podSelector: +# matchLabels: +# app: {{ .Release.Name }}-reloader +# policyTypes: +# - Ingress +# ingress: +# - from: +# - podSelector: +# matchLabels: +# app: {{ .Release.Name }}-reloader +# --- +# {{- end }} +# apiVersion: networking.k8s.io/v1 +# kind: NetworkPolicy +# metadata: +# name: allow-egress-to-studio +# namespace: {{ .Values.namespace | default "default" }} +# spec: +# podSelector: +# matchLabels: +# app: stackn-studio +# policyTypes: +# - Egress +# egress: +# - to: +# - podSelector: +# matchLabels: +# app: stackn-studio +# --- +# apiVersion: networking.k8s.io/v1 +# kind: NetworkPolicy +# metadata: +# name: allow-egress-to-studio-web +# namespace: {{ .Values.namespace | default "default" }} +# spec: +# podSelector: +# matchLabels: +# networking/allow-egress-to-studio-web: "true" +# policyTypes: +# - Egress +# egress: +# - to: +# - podSelector: +# matchLabels: +# web: studio-web +# --- +# apiVersion: networking.k8s.io/v1 +# kind: NetworkPolicy +# metadata: +# name: allow-ingress-from-project-to-studio-web +# namespace: {{ .Values.namespace | default "default" }} +# spec: +# podSelector: +# matchLabels: +# web: studio-web +# policyTypes: +# - Ingress +# ingress: +# - from: +# - podSelector: +# matchLabels: +# app: lab +# --- +# apiVersion: networking.k8s.io/v1 +# kind: NetworkPolicy +# metadata: +# name: allow-egress-from-celery-worker-to-project +# namespace: {{ .Values.namespace | default "default" }} +# spec: +# podSelector: +# matchLabels: +# name: {{ .Release.Name }}-celery-worker +# policyTypes: +# - Egress +# egress: +# - to: +# - podSelector: +# matchLabels: +# app: mlflow +# --- +# apiVersion: networking.k8s.io/v1 +# kind: NetworkPolicy +# metadata: +# name: allow-egress-from-studio-web-to-project +# namespace: {{ .Values.namespace | default "default" }} +# spec: +# podSelector: +# matchLabels: +# web: studio-web +# policyTypes: +# - Egress +# egress: +# - to: +# - podSelector: +# matchLabels: +# app: fedn-api-server +# --- +# apiVersion: networking.k8s.io/v1 +# kind: NetworkPolicy +# metadata: +# name: allow-egress-from-studio-web-to-minio +# namespace: {{ .Values.namespace | default "default" }} +# spec: +# podSelector: +# matchLabels: +# web: studio-web +# policyTypes: +# - Egress +# egress: +# - to: +# - podSelector: +# matchLabels: +# app: minio +# --- +# apiVersion: networking.k8s.io/v1 +# kind: NetworkPolicy +# metadata: +# name: allow-ingress-from-studio +# namespace: {{ .Values.namespace | default "default" }} +# spec: +# podSelector: +# matchLabels: +# app: stackn-studio +# policyTypes: +# - Ingress +# ingress: +# - from: +# - podSelector: +# matchLabels: +# app: stackn-studio +# --- +# # To limit this egress rule for internal IPs, set +# # .Values.networkPolicy.internal_cidr +# apiVersion: networking.k8s.io/v1 +# kind: NetworkPolicy +# metadata: +# name: allow-internet-egress +# namespace: {{ .Values.namespace | default "default" }} +# spec: +# podSelector: +# matchLabels: +# networking/allow-internet-egress: "true" +# policyTypes: +# - Egress +# egress: +# - to: +# - ipBlock: +# cidr: 0.0.0.0/0 +# except: +# {{- range $cidr := .Values.networkPolicy.internal_cidr }} +# - {{ $cidr }} +# {{- end }} + +# --- +# #This rule might not be needed, but is here for utility. Currently no resources use this rule. +# apiVersion: networking.k8s.io/v1 +# kind: NetworkPolicy +# metadata: +# name: allow-internet-ingress +# namespace: {{ .Values.namespace | default "default" }} +# spec: +# podSelector: +# matchLabels: +# networking/allow-internet-ingress: "true" +# policyTypes: +# - Ingress +# ingress: +# - from: +# - ipBlock: +# cidr: 0.0.0.0/0 +# except: +# {{- range $cidr := .Values.networkPolicy.internal_cidr }} +# - {{ $cidr }} +# {{- end }} +# --- +# kind: NetworkPolicy +# apiVersion: networking.k8s.io/v1 +# metadata: +# namespace: {{ .Values.namespace | default "default" }} +# name: allow-ingress-controller +# spec: +# podSelector: {} +# ingress: +# - from: +# - namespaceSelector: +# matchLabels: +# kubernetes.io/metadata.name: {{ .Values.networkPolicy.ingress_controller_namespace }} # <- This should allow traffic from ingress namespace +# {{- end }} diff --git a/scaleout/stackn/templates/nginx-conf.yaml b/scaleout/stackn/templates/nginx-conf.yaml index dee66d58..4c9a8112 100644 --- a/scaleout/stackn/templates/nginx-conf.yaml +++ b/scaleout/stackn/templates/nginx-conf.yaml @@ -1,3 +1,4 @@ +{{ if .Values.studio.static.enabled }} kind: ConfigMap apiVersion: v1 metadata: @@ -6,51 +7,19 @@ metadata: data: # Configuration values can be set as key-value properties nginx.conf: |- - user nginx; - worker_processes 1; - - error_log /var/log/nginx/error.log warn; - pid /var/run/nginx.pid; - - events { - worker_connections 1024; - } - + pid /tmp/nginx.pid; + worker_processes 4; + events { worker_connections 512; } http { - include /etc/nginx/mime.types; - default_type application/octet-stream; - log_format main '$remote_addr - $remote_user [$time_local] "$request" ' - '$status $body_bytes_sent "$http_referer" ' - '"$http_user_agent" "$http_x_forwarded_for"'; - access_log /var/log/nginx/access.log main; - sendfile on; - #tcp_nopush on; - keepalive_timeout 65; - - #gzip on; - - upstream django { - server {{ .Release.Name }}-{{ .Values.studio.servicename }}:8080; - } - - map $http_upgrade $connection_upgrade { - default upgrade; - '' close; - } - + include /etc/nginx/mime.types; server { - listen 80 default_server; - listen [::]:80 default_server; - - server_name _; - client_max_body_size 0; - location / { - proxy_pass http://django; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header Host $http_host; - proxy_set_header X-Real-IP $remote_addr; - - - } + listen 8081; + client_max_body_size 0; + large_client_header_buffers 4 128k; + location / { + etag on; + expires max; + } } } +{{ end }} diff --git a/scaleout/stackn/templates/nginx-deployment.yaml b/scaleout/stackn/templates/nginx-deployment.yaml index 108a1162..b285a655 100644 --- a/scaleout/stackn/templates/nginx-deployment.yaml +++ b/scaleout/stackn/templates/nginx-deployment.yaml @@ -1,3 +1,4 @@ +{{ if .Values.studio.static.enabled }} apiVersion: apps/v1 kind: Deployment metadata: @@ -13,6 +14,8 @@ spec: app: stackn-studio type: app pod: nginx-static + strategy: + type: {{ .Values.studio.static.strategy.type }} template: metadata: annotations: @@ -25,28 +28,34 @@ spec: type: app pod: nginx-static spec: + automountServiceAccountToken: false volumes: - name: rp-conf configMap: name: {{ .Release.Name }}-static-config - - name: mediavol - persistentVolumeClaim: - claimName: {{ .Release.Name }}-studio-media containers: - name: static - image: {{ .Values.studio.static.image }} + image: '{{ .Values.studio.static.image | default (printf "harbor.scaleoutsystems.com/studio/studio-nginx:%s" .Chart.AppVersion) }}' imagePullPolicy: {{ .Values.studio.static.pullPolicy }} + # securityContext: + # runAsUser: 101 + # runAsGroup: 101 + # allowPrivilegeEscalation: false + # privileged: false + # capabilities: + # drop: + # - all volumeMounts: - name: rp-conf mountPath: /etc/nginx/nginx.conf subPath: nginx.conf - - name: mediavol - mountPath: /etc/nginx/html/media resources: limits: cpu: {{ .Values.studio.static.resources.limits.cpu }} memory: {{ .Values.studio.static.resources.limits.memory }} requests: cpu: {{ .Values.studio.static.resources.requests.cpu }} - memory: {{ .Values.studio.static.resources.requests.cpu }} - + memory: {{ .Values.studio.static.resources.requests.memory }} + imagePullSecrets: + - name: {{ .Values.imagePullSecrets.name }} +{{ end }} diff --git a/scaleout/stackn/templates/nginx-service.yaml b/scaleout/stackn/templates/nginx-service.yaml index cafaf874..34cefc08 100644 --- a/scaleout/stackn/templates/nginx-service.yaml +++ b/scaleout/stackn/templates/nginx-service.yaml @@ -1,3 +1,4 @@ +{{- if .Values.studio.static.enabled }} apiVersion: v1 kind: Service metadata: @@ -12,3 +13,4 @@ spec: pod: nginx-static status: loadBalancer: {} +{{ end }} diff --git a/scaleout/stackn/templates/rabbit-deployment.yaml b/scaleout/stackn/templates/rabbit-deployment.yaml deleted file mode 100644 index 99ee3c56..00000000 --- a/scaleout/stackn/templates/rabbit-deployment.yaml +++ /dev/null @@ -1,45 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - annotations: - kompose.cmd: kompose convert - kompose.version: 1.20.0 () - creationTimestamp: null - labels: - io.kompose.service: {{ .Release.Name }}-rabbit - name: {{ .Release.Name }}-rabbit - name: {{ .Release.Name }}-rabbit -spec: - replicas: 1 - strategy: {} - selector: - matchLabels: - name: {{ .Release.Name }}-rabbit - template: - metadata: - annotations: - kompose.cmd: kompose convert - kompose.version: 1.20.0 () - creationTimestamp: null - labels: - io.kompose.service: {{ .Release.Name }}-rabbit - name: {{ .Release.Name }}-rabbit - spec: - containers: - - env: - - name: RABBITMQ_DEFAULT_PASS - valueFrom: - secretKeyRef: - name: {{ include "stackn.secretName" . }} - key: rabbit-password - - name: RABBITMQ_DEFAULT_USER - value: {{ include "stackn.rabbit.username" . }} - image: rabbitmq:3.8 - name: {{ .Release.Name }}-rabbit - ports: - - containerPort: 5672 - - containerPort: 15672 - resources: {} - hostname: rabbit - restartPolicy: Always -status: {} diff --git a/scaleout/stackn/templates/rabbit-service.yaml b/scaleout/stackn/templates/rabbit-service.yaml deleted file mode 100644 index fbe6d077..00000000 --- a/scaleout/stackn/templates/rabbit-service.yaml +++ /dev/null @@ -1,22 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - annotations: - kompose.cmd: kompose convert - kompose.version: 1.20.0 () - creationTimestamp: null - labels: - io.kompose.service: {{ .Release.Name }}-rabbit - name: {{ .Release.Name }}-rabbit -spec: - ports: - - name: "5672" - port: 5672 - targetPort: 5672 - - name: "15672" - port: 15672 - targetPort: 15672 - selector: - io.kompose.service: {{ .Release.Name }}-rabbit -status: - loadBalancer: {} diff --git a/scaleout/stackn/templates/redis-deployment.yaml b/scaleout/stackn/templates/redis-deployment.yaml deleted file mode 100644 index 7223f095..00000000 --- a/scaleout/stackn/templates/redis-deployment.yaml +++ /dev/null @@ -1,36 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - annotations: - kompose.cmd: kompose convert - kompose.version: 1.20.0 () - creationTimestamp: null - labels: - io.kompose.service: {{ .Release.Name }}-redis - name: {{ .Release.Name }}-redis - name: {{ .Release.Name }}-redis -spec: - replicas: 1 - strategy: {} - selector: - matchLabels: - name: {{ .Release.Name }}-redis - template: - metadata: - annotations: - kompose.cmd: kompose convert - kompose.version: 1.20.0 () - creationTimestamp: null - labels: - io.kompose.service: {{ .Release.Name }}-redis - name: {{ .Release.Name }}-redis - spec: - containers: - - image: redis - name: {{ .Release.Name }}-redis - ports: - - containerPort: 6379 - resources: {} - hostname: redis - restartPolicy: Always -status: {} diff --git a/scaleout/stackn/templates/redis-service.yaml b/scaleout/stackn/templates/redis-service.yaml deleted file mode 100644 index 0bf46bdb..00000000 --- a/scaleout/stackn/templates/redis-service.yaml +++ /dev/null @@ -1,19 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - annotations: - kompose.cmd: kompose convert - kompose.version: 1.20.0 () - creationTimestamp: null - labels: - io.kompose.service: {{ .Release.Name }}-redis - name: {{ .Release.Name }}-redis -spec: - ports: - - name: "6379" - port: 6379 - targetPort: 6379 - selector: - io.kompose.service: {{ .Release.Name }}-redis -status: - loadBalancer: {} diff --git a/scaleout/stackn/templates/role.yaml b/scaleout/stackn/templates/role.yaml new file mode 100644 index 00000000..4088f6c7 --- /dev/null +++ b/scaleout/stackn/templates/role.yaml @@ -0,0 +1,18 @@ +{{- if .Values.rbac.create }} +kind: Role +apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} +metadata: + name: {{ printf "%s-chart-controller" (include "common.names.fullname" .) }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +rules: + - apiGroups: ["", "apps", "networking.k8s.io", "autoscaling"] + resources: ["*"] + verbs: ["*"] +{{- end }} \ No newline at end of file diff --git a/scaleout/stackn/templates/rolebinding.yaml b/scaleout/stackn/templates/rolebinding.yaml new file mode 100644 index 00000000..c9818226 --- /dev/null +++ b/scaleout/stackn/templates/rolebinding.yaml @@ -0,0 +1,20 @@ +apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} +kind: RoleBinding +metadata: + name: {{ printf "%s-chart-controller" (include "common.names.fullname" .) }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ printf "%s-chart-controller" (include "common.names.fullname" .) }} +subjects: +- kind: ServiceAccount + name: {{ include "common.names.fullname" .}} + namespace: {{ .Values.namespace }} \ No newline at end of file diff --git a/scaleout/stackn/templates/service-account.yaml b/scaleout/stackn/templates/service-account.yaml new file mode 100644 index 00000000..bbeb880e --- /dev/null +++ b/scaleout/stackn/templates/service-account.yaml @@ -0,0 +1,10 @@ +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.serviceAccount.automountServiceAccountToken }} +automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }} +{{- end }} +metadata: + name: {{ include "common.names.fullname" .}} + namespace: {{ .Values.namespace | default .Release.Namespace }} +{{- end }} \ No newline at end of file diff --git a/scaleout/stackn/templates/service-frontend.yaml b/scaleout/stackn/templates/service-frontend.yaml new file mode 100644 index 00000000..e2aca416 --- /dev/null +++ b/scaleout/stackn/templates/service-frontend.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.frontend.service.name }} +spec: + type: LoadBalancer + ports: + - port: {{ .Values.frontend.service.port }} + targetPort: 3000 + selector: + app: fedn-frontend \ No newline at end of file diff --git a/scaleout/stackn/templates/studio-admin-rolebinding.yaml b/scaleout/stackn/templates/studio-admin-rolebinding.yaml deleted file mode 100644 index 016c005a..00000000 --- a/scaleout/stackn/templates/studio-admin-rolebinding.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: stackn-admin - namespace: default -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: admin -subjects: -- kind: ServiceAccount - name: default - namespace: default - diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index 3995632d..18001182 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -10,7 +10,7 @@ metadata: spec: replicas: {{ .Values.studio.replicas }} strategy: - type: Recreate + type: {{ .Values.studio.strategy.type }} selector: matchLabels: name: {{ .Release.Name }}-studio @@ -19,11 +19,33 @@ spec: labels: io.kompose.service: {{ .Release.Name }}-studio name: {{ .Release.Name }}-studio + web: studio-web + app: stackn-studio + allow-api-access: "true" + networking/allow-internet-egress: "true" spec: + automountServiceAccountToken: false + securityContext: + fsGroup: {{ .Values.studio.securityContext.fsGroup }} initContainers: - name: wait-for-db image: postgres - command: ['sh', '-c', 'until pg_isready --host={{ .Values.postgresql.fullnameOverride }}.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local --port={{ .Values.postgresql.primary.service.ports.postgresql }}; do echo waiting for database; sleep 2; done;'] + {{ if .Values.studio.cloudnativepg.enabled }} + env: + - name: POSTGRES_PORT + valueFrom: + secretKeyRef: + name: {{ .Values.studio.cloudnativepg.clusterName }}-app + key: port + - name: POSTGRES_HOST + valueFrom: + secretKeyRef: + name: {{ .Values.studio.cloudnativepg.clusterName }}-app + key: host + command: ['sh', '-c', 'until pg_isready --host=$POSTGRES_HOST --port=$POSTGRES_PORT; do echo waiting for database; sleep 2; done;'] + {{ else }} + command: ['sh', '-c', 'until pg_isready --host={{ .Values.postgresql.fullnameOverride }} --port={{ .Values.postgresql.primary.service.ports.postgresql }}; do echo waiting for database; sleep 2; done;'] + {{ end }} resources: limits: cpu: "100m" @@ -35,13 +57,130 @@ spec: - args: - sh - scripts/run_web.sh + ports: + - containerPort: 8080 env: - {{ if .Values.studio.debug }} - name: DEBUG + {{ if .Values.studio.debug }} value: "true" + {{ else }} + value: "false" {{ end }} + - name: DOMAIN + value: {{ .Values.domain }} + - name: AUTH_DOMAIN + value: {{ .Release.Name }}-studio.{{ .Values.namespace | default "default"}}.svc.{{ .Values.cluster_domain | default "cluster.local"}} + - name: STUDIO_URL + value: http://{{ .Release.Name }}-studio:8080 + - name: GRPC_DOMAIN + value: {{ .Values.grpc_domain | quote }} + - name: RELEASE_NAME + value: {{ .Release.Name }} + - name: SERVICE_NAME + value: {{ .Values.studio.servicename }} + - name: NAMESPACE + value: {{ .Values.namespace | default "default" }} + - name: CLUSTER_DOMAIN + value: {{ .Values.cluster_domain | default "cluster.local"}} + - name: STORAGE_CLASS + value: {{ .Values.studio.storage.storageClass }} - name: INIT value: {{ .Values.studio.init | quote }} + - name: CSRF_TRUSTED_ORIGINS + value: {{ .Values.studio.csrf_trusted_origins | quote}} + - name: KUBE_API_REQUEST_TIMEOUT + value: {{ .Values.studio.kube_api_request_timeout | quote }} + - name: EMAIL_SERVICE_ENABLED + value: {{ .Values.studio.emailService.enabled | quote}} + - name: EMAIL_HOST + value: {{ .Values.studio.emailService.host | quote}} + - name: EMAIL_PORT + value: {{ .Values.studio.emailService.port | quote }} + - name: EMAIL_DOMAIN_NAME + value: {{ .Values.studio.emailService.domainName | quote}} + - name: EMAIL_MAILGUN_API + value: {{ .Values.studio.emailService.apiEndpoint | quote}} + - name: NOTIFY_ON_ACCOUNT_REGISTER_LIST + value: "{{ range $index, $elem := .Values.studio.emailService.notifyOnAccountRegisterList }}{{ if $index }},{{ end }}{{ $elem }}{{ end }}" + {{ if .Values.studio.sentry.enabled }} + - name: SENTRY_ENABLED + value: "true" + - name: SENTRY_STUDIO_DSN + value: "{{ .Values.studio.sentry.studio_dsn }}" + - name: SENTRY_CONTROLLER_DSN + value: "{{ .Values.studio.sentry.controller_dsn }}" + - name: SENTRY_COMBINER_DSN + value: "{{ .Values.studio.sentry.combiner_dsn }}" + - name: SENTRY_ENVIRONMENT + value: "{{ .Values.studio.sentry.environment }}" + {{ end }} + - name: WELCOME_EMAIL_ON_NEW_USER + {{ if .Values.studio.welcomeEmail.enabled }} + value: "true" + {{ else }} + value: "false" + {{ end }} + - name: VERSION + value: "{{ .Values.studio.version | default .Chart.AppVersion }}" + - name: DEFAULT_FROM_EMAIL + value: {{ .Values.studio.emailService.smtpEmailFrom | quote}} + - name: SESSION_COOKIE_DOMAIN + value: {{ .Values.session_cookie_domain | quote }} + - name: STUDIO_ACCESSMODE + value: {{ .Values.accessmode }} + - name: CUSTOM_MIGRATIONS + value: "{{- if .Values.studio.custom_migrations.enabled }}{{- range $key, $value := .Values.studio.custom_migrations.apps }}{{ $key }}:{{ $value }},{{- end }}{{- end }}" + - name: ENABLE_PROJECT_EXTRA_SETTINGS + value: {{ .Values.studio.enable_project_extra_settings | quote }} + - name: DISCORD_ALERT_ON_NEW_USER + {{ if .Values.studio.discord.alert_on_new_user }} + value: "true" + {{ else }} + value: "false" + {{ end }} + - name: DISCORD_ALERT_WEBHOOK_URL + value: {{ .Values.studio.discord.alert_webhook_url | quote }} + - name: DISCORD_ALERT_ON_NEW_USER_MESSAGE + value: {{ .Values.studio.discord.alert_on_new_user_message | quote }} + - name: INACTIVE_USERS + {{ if .Values.studio.inactive_users }} + value: "true" + {{ else }} + value: "false" + {{ end }} + - name: CUSTOM_APPS + value: "{{- if .Values.studio.custom_apps.enabled }}{{- range .Values.studio.custom_apps.apps }}{{ . }},{{- end }}{{- end }}" + - name: AUTH_USER_MODEL + {{ if .Values.studio.auth_user_model.override }} + value: {{ .Values.studio.auth_user_model.model | quote }} + {{ else }} + value: "" + {{ end }} + {{ if .Values.studio.disabledAppInstanceFields.enabled }} + - name: DISABLED_APP_INSTANCE_FIELDS + value: "{{- range .Values.studio.disabledAppInstanceFields.fields }}{{ . }},{{- end }}" + {{- end }} + {{ if .Values.studio.jwt_auth.enabled }} + - name: ENABLE_JWT + value: "true" + {{ if .Values.studio.jwt_auth.existingSecret }} + - name: SIGNING_KEY + valueFrom: + secretKeyRef: + name: {{ .Values.studio.jwt_auth.existingSecret }} + key: private_key + {{ end }} + {{ if .Values.studio.jwt_auth.public_key }} + - name: VERIFYING_KEY + value: {{ .Values.studio.jwt_auth.public_key | quote }} + {{ end }} + - name: JWT_AUTH_ALGORITHM + value: {{ .Values.studio.jwt_auth.algorithm | quote }} + {{ if .Values.studio.jwt_auth.statelessUser }} + - name: JWT_STATELESS_USER_AUTH + value: "true" + {{ end }} + {{ end }} - name: DJANGO_SUPERUSER value: {{ include "stackn.studio.superuser" . }} - name: DJANGO_SUPERUSER_EMAIL @@ -51,32 +190,168 @@ spec: secretKeyRef: name: {{ include "stackn.secretName" . }} key: studio-superuser-password + - name: EVENT_LISTENER_USERNAME + value: {{ .Values.studio.eventListenerUsername | quote }} + - name: EVENT_LISTENER_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "stackn.secretName" . }} + key: studio-event-listener-user-password - name: GET_HOSTS_FROM value: dns + {{ if .Values.studio.cloudnativepg.enabled }} + - name: POSTGRES_NAME + valueFrom: + secretKeyRef: + name: {{ .Values.studio.cloudnativepg.clusterName }}-app + key: dbname + - name: POSTGRES_USER + valueFrom: + secretKeyRef: + name: {{ .Values.studio.cloudnativepg.clusterName }}-app + key: user + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.studio.cloudnativepg.clusterName }}-app + key: password + - name: POSTGRES_PORT + valueFrom: + secretKeyRef: + name: {{ .Values.studio.cloudnativepg.clusterName }}-app + key: port + - name: POSTGRES_HOST + valueFrom: + secretKeyRef: + name: {{ .Values.studio.cloudnativepg.clusterName }}-app + key: host + {{ else }} + - name: POSTGRES_NAME + value: {{ .Values.postgresql.auth.database }} + - name: POSTGRES_USER + value: {{ .Values.postgresql.auth.username }} + - name: POSTGRES_HOST + value: {{ .Values.postgresql.fullnameOverride }} + - name: POSTGRES_PORT + value: {{ .Values.postgresql.primary.service.ports.postgresql | quote }} - name: POSTGRES_PASSWORD valueFrom: secretKeyRef: name: {{ include "stackn.postgres.secretName" . }} key: password - - name: RABBITMQ_DEFAULT_PASS + {{ end }} + - name: DJANGO_SECRET valueFrom: secretKeyRef: name: {{ include "stackn.secretName" . }} - key: rabbit-password - - name: KUBECONFIG - value: {{ .Values.studio.kubeconfig_file | quote }} - image: {{ .Values.studio.image.repository }} + key: django-secret-key + {{ if .Values.studio.emailService.enabled }} + - name: EMAIL_HOST_USER + valueFrom: + secretKeyRef: + name: {{ include "stackn.secretName" . }} + key: email-host-user + - name: EMAIL_HOST_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "stackn.secretName" . }} + key: email-host-password + - name: EMAIL_API_KEY + valueFrom: + secretKeyRef: + name: {{ include "stackn.secretName" . }} + key: email-api-key + {{ end }} + - name: S3HOST + value: {{ .Values.studio.minio.host }} + - name: S3PORT + value: "{{ .Values.studio.minio.port | default 9000 }}" + - name: S3ACCESS_KEY + valueFrom: + secretKeyRef: + name: {{ .Values.studio.minio.secretName }} + key: CONSOLE_ACCESS_KEY + - name: S3SECRET_KEY + valueFrom: + secretKeyRef: + name: {{ .Values.studio.minio.secretName }} + key: CONSOLE_SECRET_KEY + {{ if .Values.studio.argocd.enabled }} + - name: ARGO_CD_ENABLED + value: "true" + - name: ARGO_CD_API_URL + value: {{ .Values.studio.argocd.url | default "" }} + - name: ARGO_CD_PROJECT + value: {{ .Values.studio.argocd.project | default "default" }} + - name: ARGO_CD_APP_NAMESPACE + value: {{ .Values.studio.argocd.namespace | default "default" }} + - name: ARGO_CD_SERVER + value: {{ .Values.studio.argocd.server | default "https://kubernetes.default.svc" }} + - name: ARGO_CD_TOKEN + valueFrom: + secretKeyRef: + name: {{ include "stackn.secretName" . }} + key: studio-argocd-token + {{ end }} + {{ if .Values.studio.recaptcha.enabled }} + - name: RECAPTCHA_ENABLED + value: "true" + - name: RECAPTCHA_SITE_KEY + valueFrom: + secretKeyRef: + name: recaptcha-keys + key: site-key + - name: RECAPTCHA_SECRET_KEY + valueFrom: + secretKeyRef: + name: recaptcha-keys + key: secret-key + {{ end }} + - name: CHART_REPO + value: {{ .Values.studio.project.repo }} + - name: CHART_PATH + value: {{ .Values.studio.project.path }} + - name: CHART_REVISION + value: {{ .Values.studio.project.revision | quote}} + {{ if .Values.mongodb.enabled }} + - name: MONGO_SERVICE_HOST + value: {{ include "mongodb.service.nameOverride" .Subcharts.mongodb }} + - name: MONGO_SERVICE_PORT + value: {{ .Values.mongodb.service.ports.mongodb | quote }} + - name: MONGO_USERNAME + value: {{ .Values.mongodb.auth.rootUser }} + - name: MONGO_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "mongodb.fullname" .Subcharts.mongodb }} + key: mongodb-root-password + - name: MONGO_ARCHITECTURE + value: {{ .Values.mongodb.architecture | default "standalone" }} + - name: MONGO_REPLICA_COUNT + value: {{ .Values.mongodb.replicaCount | default "1" | quote }} + - name: MONGO_REPLICA_SET_NAME + value: {{ .Values.mongodb.replicaSetName | default "rs0" }} + {{ end }} + {{ if .Values.studio.harbor.enabled }} + - name: HARBOR_ENABLED + value: "true" + - name: HARBOR_CREDS + valueFrom: + secretKeyRef: + name: {{ include "stackn.secretName" . }} + key: harbor-creds + - name: HARBOR_HOST + value: {{ .Values.studio.project.repo }} + - name: HARBOR_PATH + value: {{ .Values.studio.project.path }} + {{ end }} + {{ if .Values.frontend.ingress.enabled }} + - name: FRONTEND_DOMAIN + value: {{ (index .Values.frontend.ingress.hosts 0) }} + {{ end }} + image: '{{ .Values.studio.image.repository | default (printf "harbor.scaleoutsystems.com/studio/studio:%s" .Chart.AppVersion) }}' imagePullPolicy: {{ .Values.studio.image.pullPolicy }} name: {{ .Release.Name }}-studio - volumeMounts: - - name: kubeconfig - mountPath: {{ .Values.studio.kubeconfig_dir | quote }} - readOnly: true - - mountPath: /app/studio/settings.py - subPath: settings.py - name: {{ .Release.Name}}-settings-configmap - - name: mediavol - mountPath: {{ .Values.studio.media.mount_path }} resources: limits: cpu: {{ .Values.studio.resources.limits.cpu }} @@ -84,22 +359,30 @@ spec: requests: cpu: {{ .Values.studio.resources.requests.cpu }} memory: {{ .Values.studio.resources.requests.memory }} - - {{- with .Values.imagePullSecrets }} + {{- if .Values.studio.securityContext.enabled }} + securityContext: + runAsUser: {{ .Values.studio.securityContext.runAsUser }} + runAsGroup: {{ .Values.studio.securityContext.runAsGroup }} + allowPrivilegeEscalation: {{ .Values.studio.securityContext.allowPrivilegeEscalation }} + privileged: {{ .Values.studio.securityContext.privileged }} + capabilities: + drop: + - all + {{- end }} + {{- if .Values.studio.readinessProbe.enabled }} + readinessProbe: + tcpSocket: + port: {{ .Values.studio.readinessProbe.tcpSocket.port }} + initialDelaySeconds: {{ .Values.studio.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.studio.readinessProbe.periodSeconds }} + {{- end }} + {{- if .Values.studio.livenessProbe.enabled }} + livenessProbe: + tcpSocket: + port: {{ .Values.studio.livenessProbe.tcpSocket.port }} + initialDelaySeconds: {{ .Values.studio.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.studio.livenessProbe.periodSeconds }} + {{- end }} imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} + - name: {{ .Values.imagePullSecrets.name }} restartPolicy: Always - volumes: - - name: kubeconfig - secret: - secretName: {{ .Release.Name }}-chart-controller-secret - - name: {{ .Release.Name}}-settings-configmap - configMap: - name: {{ .Release.Name}}-settings-configmap - items: - - key: settings.py - path: settings.py - - name: mediavol - persistentVolumeClaim: - claimName: {{ .Release.Name }}-studio-media diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml deleted file mode 100644 index 0f26d86d..00000000 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ /dev/null @@ -1,292 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ .Release.Name }}-settings-configmap -data: - settings.py: |- - """ - Django settings for studio project. - - Generated by 'django-admin startproject' using Django 2.2.6. - - For more information on this file, see - https://docs.djangoproject.com/en/2.2/topics/settings/ - - For the full list of settings and their values, see - https://docs.djangoproject.com/en/2.2/ref/settings/ - """ - - import os - import sys - - AUTHENTICATION_BACKENDS = [ - 'social_core.backends.github.GithubOAuth2', - 'social_core.backends.google.GoogleOAuth2', - 'django.contrib.auth.backends.ModelBackend', - 'guardian.backends.ObjectPermissionBackend', - ] - - # Build paths inside the project like this: os.path.join(BASE_DIR, ...) - BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) - - # Crispy Forms - CRISPY_TEMPLATE_PACK="bootstrap4" - - # Quick-start development settings - unsuitable for production - # See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/ - - # SECURITY WARNING: keep the secret key used in production secret! - SECRET_KEY = 'pyey3^@n)$id1tc3_g7xcb55n7ii1989jy#&%!yk^z(u1us4@*' - - # SECURITY WARNING: don't run with debug turned on in production - {{ if .Values.studio.debug }} - DEBUG = True - {{ else }} - DEBUG = False - {{ end }} - - if DEBUG: - ALLOWED_HOSTS = ['*'] - else: - ALLOWED_HOSTS = ['{{ .Values.domain }}'] - - EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' - - # Application definition - - # Application definition - DEFAULT_APPS = [ - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', - ] - - THIRD_PARTY_APPS = [ - # add apps which you install using pip - "crispy_forms", - 'corsheaders', - 'django_celery_beat', - 'django_extensions', # for executing runscript among others - 'django_filters', - 'oauth2_provider', - 'rest_framework', - 'rest_framework.authtoken', - 'social_django', - 'tagulous', - 'guardian', - ] - - LOCAL_APPS = [ - # add local apps which you create using startapp - 'api', - 'apps', - 'common', - 'deployments', - 'monitor', - 'models', - 'projects', - 'portal', - ] - - # # Application definition - INSTALLED_APPS = DEFAULT_APPS + THIRD_PARTY_APPS + LOCAL_APPS - - OAUTH2_PROVIDER = { - # this is the list of available scopes - 'SCOPES': {'read': 'Read scope', 'write': 'Write scope', 'groups': 'Access to your groups'} - } - - MIDDLEWARE = [ - 'django.middleware.security.SecurityMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', - 'corsheaders.middleware.CorsMiddleware', - 'social_django.middleware.SocialAuthExceptionMiddleware', # Add - ] - - REST_FRAMEWORK = { - 'DEFAULT_AUTHENTICATION_CLASSES': [ - 'rest_framework.authentication.TokenAuthentication', - #'rest_framework.permissions.IsAuthenticated', - 'oauth2_provider.contrib.rest_framework.OAuth2Authentication', - ], - } - - # Django guardian 403 templates - GUARDIAN_RENDER_403 = True - GUARDIAN_TEMPLATE_403 = '403.html' - - # Main Url conf for loading all the routing path in Studio - ROOT_URLCONF = 'studio.urls' - - # IMPORTANT: Must be encrypted as secrets in K8S - # Github - SOCIAL_AUTH_GITHUB_KEY = 'to-be-fetched-from-k8s-secrets' - SOCIAL_AUTH_GITHUB_SECRET = 'to-be-fetched-from-k8s-secrets' - SOCIAL_AUTH_GITHUB_SCOPE = ['user:email'] # Ask for the user's email - - # Google - SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = 'to-be-fetched-from-k8s-secrets' - SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = 'to-be-fetched-from-k8s-secrets' - SOCIAL_AUTH_GOOGLE_OAUTH2_SCOPE = ['user:email'] # Ask for the user's email - - # Tagulous serialization settings - SERIALIZATION_MODULES = { - 'xml': 'tagulous.serializers.xml_serializer', - 'json': 'tagulous.serializers.json', - 'python': 'tagulous.serializers.python', - 'yaml': 'tagulous.serializers.pyyaml', - } - - STATICFILES_FINDERS = ( - 'django.contrib.staticfiles.finders.FileSystemFinder', - 'django.contrib.staticfiles.finders.AppDirectoriesFinder', - # other finders - 'compressor.finders.CompressorFinder', - ) - - TEMPLATE_LOADERS = ( - 'django.template.loaders.filesystem.Loader', - 'django.template.loaders.app_directories.Loader', - 'django.template.loaders.eggs.Loader', - ) - - TEMPLATES = [ - { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [os.path.join(BASE_DIR, 'templates'), os.path.join(BASE_DIR, 'common/templates')], - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', - 'social_django.context_processors.backends', # Add - 'social_django.context_processors.login_redirect', # Add - ], - 'libraries': { - 'custom_tags': 'models.templatetags.custom_tags', - } - }, - }, - ] - - WSGI_APPLICATION = 'studio.wsgi.application' - ASGI_APPLICATION = 'studio.asgi.application' - - # Database - # https://docs.djangoproject.com/en/2.2/ref/settings/#databases - - DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.postgresql', - 'NAME': '{{ .Values.postgresql.global.postgresql.auth.database }}', - 'USER': '{{ .Values.postgresql.global.postgresql.auth.username }}', - 'PASSWORD': os.environ.get('POSTGRES_PASSWORD'), - 'HOST': '{{ .Values.postgresql.fullnameOverride }}', - 'PORT': '{{ .Values.postgresql.primary.service.ports.postgresql }}', - } - } - - # Password validation - # https://docs.djangoproject.com/en/2.2/ref/settings/#auth-password-validators - - AUTH_PASSWORD_VALIDATORS = [ - { - 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', - }, - ] - - # Internationalization - # https://docs.djangoproject.com/en/2.2/topics/i18n/ - LANGUAGE_CODE = 'en-us' - TIME_ZONE = 'UTC' - USE_I18N = True - USE_L10N = True - USE_TZ = True - - # Static files (CSS, JavaScript, Images) - # https://docs.djangoproject.com/en/2.2/howto/static-files/ - #STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static'), ] - STATIC_URL = '/static/' - STATIC_ROOT = os.path.join(BASE_DIR, 'static/') - # Media Files for Studio apps - MEDIA_URL = {{ .Values.studio.media.mount_path | quote }} - MEDIA_ROOT = {{ .Values.studio.media.mount_path | quote }} - - # Related to user registration and authetication workflow - LOGIN_REDIRECT_URL = '/' - LOGIN_URL = 'login' - LOGOUT_URL = 'logout' - INACTIVE_USERS = False - - # Specific to Studio stack: - # Redis settings - REDIS_PORT = 6379 - REDIS_DB = 0 - REDIS_HOST = os.environ.get('REDIS_PORT_6379_TCP_ADDR', '{{ .Release.Name }}-redis') - #CHANNEL_LAYERS = { - # 'default': { - # 'BACKEND': 'channels_redis.core.RedisChannelLayer', - # 'CONFIG': { - # 'hosts': [(REDIS_HOST, REDIS_PORT),], - # }, - # }, - #} - # Celery settings - CELERY_BROKER_URL = 'amqp://{{ include "stackn.rabbit.username" . }}:{}@{{ .Release.Name }}-rabbit:5672//'.format(os.environ.get("RABBITMQ_DEFAULT_PASS")) - CELERY_RESULT_BACKEND = 'redis://%s:%d/%d' % (REDIS_HOST, REDIS_PORT, REDIS_DB) - CELERY_TASK_SERIALIZER = 'json' - CELERY_RESULT_SERIALIZER = 'json' - CELERY_ACCEPT_CONTENT = ['json'] - CELERY_TIMEZONE = "UTC" - CELERY_ENABLE_UTC = True - # For Model Objects creation (check models/models.py, pre_save_model() ) - VERSION_BACKEND = 'studio.version.Version' - - # Other Helm/k8s deployment settings - CHART_CONTROLLER_URL = 'http://{{ .Release.Name }}-chart-controller' #Not used - CHART_FOLDER = "/app/charts/apps" - EXTERNAL_KUBECONF = True - KUBECONFIG = {{ .Values.studio.kubeconfig_file | quote }} - NAMESPACE = {{ .Values.namespace | default "default" | quote }} - #PROMETHEUS_SVC = 'http://{{ .Release.Name }}-prometheus-server' - REGISTRY_SVC = '{{ .Release.Name }}-docker-registry' - STORAGECLASS = {{ include "stackn.studio.storageclass" . | quote }} - - # Local dependecies Models - PROJECTS_MODEL = 'projects.Project' - APPINSTANCE_MODEL = 'apps.AppInstance' - APPS_MODEL = 'apps.Apps' - APPCATEGORIES_MODEL = 'apps.AppCategories' - MODELS_MODEL = 'models.Model' - - # App statuses - APPS_STATUS_SUCCESS = ['Running', 'Succeeded', 'Success'] - APPS_STATUS_WARNING = ['Pending', 'Installed', - 'Waiting', 'Installing', 'Created'] - - DOMAIN = {{ .Values.domain | quote }} - AUTH_DOMAIN = '{{ .Release.Name }}-studio.default.svc.cluster.local' - AUTH_PROTOCOL = 'http' - STUDIO_URL = 'http://{{ .Release.Name }}-studio:8080' - # To enable sticky sessions for k8s ingress - SESSION_COOKIE_DOMAIN = {{ .Values.session_cookie_domain | quote }} - \ No newline at end of file diff --git a/scaleout/stackn/values-utility-script.sh b/scaleout/stackn/values-utility-script.sh deleted file mode 100755 index f0cc4455..00000000 --- a/scaleout/stackn/values-utility-script.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash - -# v0.1.0 -# Script can be improved by for example taking into account that this works only first time -# Later times strings such as and will already be overwritten - -set -e - -echo "Running the utility script for setting up variables within the values.yaml file..." -# Extract currently assigned IP address (which is connected to Internet!) - -echo "Extracting IP address..." -my_ip=$(ip route get 8.8.8.8 | awk -F"src " 'NR==1{split($2,a," ");print a[1]}') -echo "Your current IP address is: $my_ip" - -# Extract used network interface - Just for sysadmin purposes -#my_interface=$(ip route get 8.8.8.8 | awk -F"dev " 'NR==1{split($2,a," ");print a[1]}') - -# Replace field with extracted IP adress in values.yaml file -echo "Replacing $my_ip inside the values.yaml file..." -echo "Appending nip.io wildcardars..." -sed -i "s//$my_ip.nip.io/g" ./values.yaml -echo "Your current STACKn domain will be: $my_ip.nip.io" - - -# Generate k8s cluster config file - NOTE: we assume that microk8s is already installed and configured -cluster_config=$(microk8s.config | base64 | tr -d '\n') - -# Replace field in the chart-controller-secret.yaml file with the above create variable -sed -i "s//$cluster_config/g" ./templates/chart-controller-secret.yaml - -echo "Done" - diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index 1b6f7070..bb84c4fc 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -1,11 +1,15 @@ # This is a YAML-formatted file. # Declare variables to be passed into STACKn templates. -# REQUIREMENT: -# - set a storage class with ability to serve ReadWriteMany -# Name: storageClassName, and/or set anchor &śtorage_class -# Description: Set a storage class for the resources that are reused for multi-mount-points in cluster. To reduce wasteful copying we allow to use the same dataset volume to be mounted multiple times. -# Default: microk8s-hostpath, use nfs-client for docker-for-desktop +# NOTES: +# - set a storage class everywhere you can see storageClass: "" +# - if you want to use an existing secret, set the name of the secret everywhere you see existingSecret: "" +# furthermore, the Bitnami subcharts (postgresql) also usually have a existingSecret value +# - Bitnami subcharts (postgresql) also usually have existingStorage values +# - if NetworkPolicy is enabled, set the kubernetes api server endpoints and port +# - Please set all values named password, the chart do have features to generate passwords, +# but this is not always working as expected during upgrades. +# - Please do not change values with "Do not change unless you know what you are doing." #Set global values to overide default global: @@ -15,83 +19,297 @@ global: superuserEmail: "" ##these are currently not handled by stackn: default: admin@test.com existingSecret: "" storageClass: "" + eventListenerUserPassword: "" postgresql: auth: - username: stackn - password: "" - postgresPassword: "" - database: stackn - existingSecret: "" + username: studio # username for postgresql + password: "" # password for postgresql + postgresPassword: "" # password for postgresql + database: studio # database name for postgresql + existingSecret: "" # name of existing secret containing postgresPassword (optional) storageClass: -namespace: default -existingSecret: "" +namespace: default # namespace to deploy stackn in +existingSecret: "" # name of existing secret, should replace basic-secrets.yaml +serviceAccount: # service account for stackn + create: true # create service account + automountServiceAccountToken: true # automount service account token +rbac: # rbac for stackn + create: true # create rbac -studio: - servicename: studio - replicas: 1 - debug: true - init: true - kubeconfig_file: /app/chartcontroller/kubeconfig/config - kubeconfig_dir: /app/chartcontroller/kubeconfig/ - static: - replicas: 1 - image: ghcr.io/scaleoutsystems/stackn/ingress:v0.6.0 - pullPolicy: IfNotPresent - resources: - limits: - cpu: 1 - memory: "512Mi" - requests: - cpu: "100m" - memory: "256Mi" +commonLabels: {} # common labels for stackn +commonAnnotations: {} # common annotations for stackn + +networkPolicy: # network policy for stackn + enable: false # enable network policy + kubernetes: + cidr: # To get kubernetes api server endpoints run: $ kubectl get endpoints kubernetes + port: 6443 # port for kubernetes api server + internal_cidr: # in-cluster IpBlock cidr, used in allow-internet-[egress|ingress] policy, e.g: + - 10.0.0.0/8 + - 192.168.0.0/16 + - 172.0.0.0/20 + ingress_controller_namespace: kube-system # namespace for ingress controller + +frontend: + service: + name: fedn-frontend-service # name of frontend service + port: 80 # port for frontend service + replicas: 1 # number of frontend replicas + strategy: # strategy for frontend + type: RollingUpdate # type of strategy + image: # image for frontend + repository: harbor.scaleoutsystems.com/fedn/fedn-front-end:main + pullPolicy: Always # pull policy for frontend + pullSecret: harborsecret # pull secret for frontend + resources: # resources for frontend + limits: # limits for frontend + cpu: "1000m" # cpu limit for frontend + memory: "1Gi" # memory limit for frontend + requests: # requests for frontend + cpu: "100m" # cpu request for frontend + memory: "128Mi" # memory request for frontend + recaptcha: # recaptcha for frontend + enabled: false # enable recaptcha for frontend + existingSecret: "google-recaptcha-secret" # name of existing secret containing recaptcha secret + existingSecretKey: "key" # key in existing secret containing recaptcha secret + siteKey: "" # site key for recaptcha + action: "userRegister" # action for recaptcha + securityContext: # security context for frontend + enabled: true + runAsUser: 1001 + runAsGroup: 1001 + fsGroup: 1001 + runAsNonRoot: true + readOnlyRootFilesystem: true + allowPrivilegeEscalation: false + privileged: false + readinessProbe: # readiness probe for frontend + enabled: true + tcpSocket: + port: 3000 + initialDelaySeconds: 20 + periodSeconds: 10 + livenessProbe: # liveness probe for frontend + enabled: true + tcpSocket: + port: 3000 + initialDelaySeconds: 20 + periodSeconds: 20 + automountServiceAccountToken: false # automount service account token for frontend + debug: false # dev mode for frontend + ingress: # ingress for frontend + enabled: true # enable ingress for frontend + hosts: + - "fedn.scaleoutsystems.com" # host for frontend + tls: # tls for frontend + enabled: true # enable tls for frontend + hosts: + - "fedn.scaleoutsystems.com" + existingSecret: "fedn-tls" # name of existing secret containing tls certificate + + + +studio: # studio values + servicename: studio # name of studio service + replicas: 1 # number of studio replicas + strategy: # strategy for studio + type: RollingUpdate # type of strategy + debug: true # debug mode for studio Django server + init: true # init studio script (deprecated) + enable_project_extra_settings: false # enable project extra settings. Do not change unless you know what you are doing. + inactive_users: False # inactive users by default. When set to True, users will be inactive by default and need to be activated by an admin. + custom_apps: # custom apps for studio. Do not change unless you know what you are doing. + enabled: true + apps: + - "common" + custom_migrations: # custom migrations for studio. Do not change unless you know what you are doing. + enabled: false + apps: + user: "studio.migrations.user" + control: "studio.migrations.control" + auth_user_model: # auth user model for studio. Do not change unless you know what you are doing. + override: false + model: "user.User" + auth: # auth endpoint for studio. Do not change unless you know what you are doing. + endpoint: /auth/ # if JWT is enabled, this should be /api/token/verify + jwt_auth: # Use JWT authentication for REST and client authentication. Needs exsiting secret with private key. + enabled: false + algorithm: HS256 + public_key: "" # If algorithm is RS256, set RSA public key here + existingSecret: "" # name of existing secret containing private key, need "private_key" key + statelessUser: false # If true, user will be stateless, i.e. when verifying token, user will not be fetched from database + csrf_trusted_origins: # csrf trusted origins for studio. Add extra trusted origins for CSRF protection. + kube_api_request_timeout: 1 # timeout for kubernetes api requests, such as request to create/delete resources + static: # static values for studio, ngnix server for serving static files and media files + enabled: false # enable static for studio + replicas: 1 # number of static replicas + strategy: # strategy for static + type: Recreate # type of strategy + # image: harbor.scaleoutsystems.com/studio/studio-nginx:0.17.0 # image for static, use this value if you want to override default (usually you should not) + pullPolicy: IfNotPresent # pull policy for static + resources: # resources for static + limits: # limits for static + cpu: 1 # cpu limit for static + memory: "512Mi" # memory limit for static + requests: # requests for static + cpu: "100m" # cpu request for static + memory: "256Mi" # memory request for static image: #tell which image to deploy for studio - repository: ghcr.io/scaleoutsystems/stackn/studio:v0.6.0 #This image can be built from Dockerfile inside stackn/components/studio (https://github.com/scaleoutsystems/stackn) + repository: harbor.scaleoutsystems.com/studio/studio:0.17.0 # This image can be built from Dockerfile inside stackn/components/studio (https://github.com/scaleoutsystems/stackn) pullPolicy: IfNotPresent # used to ensure that each time we redeploy always pull the latest image resources: limits: cpu: "1000m" memory: "4Gi" requests: - cpu: "400m" + cpu: "20m" memory: "2Gi" storage: storageClass: "" - media: - storage: - storageClass: "" - size: "5Gi" - accessModes: ReadWriteMany - mount_path: /app/media/ superUser: admin superuserPassword: "" superuserEmail: admin@test.com + eventListenerUsername: "" + eventListenerUserPassword: "" + #version: studio + securityContext: + enabled: true + runAsUser: 1000 + runAsGroup: 1000 + fsGroup: 1000 + allowPrivilegeEscalation: false + privileged: false + readinessProbe: # readiness probe for studio. Do not change unless you know what you are doing. + enabled: true + tcpSocket: + port: 8080 + initialDelaySeconds: 20 + periodSeconds: 10 + livenessProbe: # liveness probe for studio. Do not change unless you know what you are doing. + enabled: true + tcpSocket: + port: 8080 + initialDelaySeconds: 20 + periodSeconds: 20 + djangoSecret: '' # django secret for studio (optional, will be generated if not set) + emailService: # email service for studio. Please concact Scaleout if you want to use this feature. + enabled: false + host: '' + port: 587 + hostUser: '' + hostPassword: '' + smtpEmailFrom: '' + domainName: '' + apiEndpoint: '' + apiKey: '' + notifyOnAccountRegisterList: + - '' + welcomeEmail: + enabled: false + disabledAppInstanceFields: # disabled app instance fields for studio. Do not change unless you know what you are doing. + enabled: false + fields: + - '' + discord: + alert_on_new_user: false + alert_webhook_url: '' + alert_on_new_user_message: '' -#kubernetes config -kubeconfig: "" + argocd: + enabled: true + url: '' + token: '' + project: "default" + namespace: "default" + server: "https://kubernetes.default.svc" + + recaptcha: + enabled: false + + sentry: + enabled: false + studio_dsn: "" + controller_dsn: "" + combiner_dsn: "" + environment: "" + + project: + repo: "harbor.scaleoutsystems.com" + path: "chart/fedn" + revision: "*" + + # Secret should have entries CLUSTER_ACCESS_KEY and CLUSTER_SECRET_KEY + minio: + enabled: true + host: minio-fedn-hl + secretName: minio-fedn-user-0 + port: "9000" + + # Secret should have entries access_key and secret_key + minio_backup: + enabled: true + host: http://minio-system-hl.minio-system.svc.cluster.local + secretName: minio-system-user-0 + port: "9000" + mongodb_bucket: studio-mongodb-backups + + harbor: + enabled: true + username: "" + password: "" + + # If you have installed the CloudnativePG operator, enable this and set the clusterName. + # You should also disable postgres below. + cloudnativepg: + enabled: false # Set to true if you want to use a CloudnativePG cluster + create_new: true # Set to true if you want to create a new postgres cluster. + clusterName: studio-db + spec: + instances: 3 + storage: + size: 20Gi + +# Pull secrets for studio, used to pull images from private repositories such as Harbor +# To create a pull secret run: $ kubectl create secret docker-registry --docker-server= --docker-username= --docker-password= +imagePullSecrets: + name: ghcrsecret + +#Genreal storage access mode +accessmode: ReadWriteMany + +# the cluster domain name (default cluster.local) +cluster_domain: cluster.local # Enable ingress if you want your to access the studio solution from a kubernetes host/localhost. domain: studio.127.0.0.1.nip.io -session_cookie_domain: .127.0.0.1.nip.io +grpc_domain: grpc.studio.127.0.0.1.nip.io # domain for grpc servers (combiners in FL) +session_cookie_domain: .127.0.0.1.nip.io # domain for session cookie, should be .domain ingress: enabled: true - annotations: {} hosts: - host: studio.127.0.0.1.nip.io - # setup TLS if you have a platform certificate or use 'tls-acme' if you have certbot deployed and want to generate a certificate. tls: - - secretName: prod-ingress + - secretName: prod-ingress # name of the secret containing the TLS certificate. Please contact Scaleout for details. hosts: - studio.127.0.0.1.nip.io ### A Postgres database for STACKn ### -# Here we use https://charts.bitnami.com/bitnami postgresql chart +# Here we use https://charts.bitnami.com/bitnami postgresql chart +# Please see the documentation for this Bitnami chart for more details on values: +# https://github.com/bitnami/charts/tree/main/bitnami/postgresql +# Please also observe the version we are using in requirements.yaml -# Postgres deploy with a single-pod database: postgresql: enabled: true - fullnameOverride: stackn-studio-postgres + fullnameOverride: studio-postgres + commonAnnotations: {"reloader.stakater.com/auto": "true"} + auth: + username: + password: + postgresPassword: + database: studio primary: service: ports: @@ -101,49 +319,58 @@ postgresql: size: "10Gi" accessModes: - ReadWriteMany + storageClass: + podLabels: {"app":"stackn-studio"} # Do not change unless you know what you are doing. + resources: + requests: + cpu: "100m" + memory: "256Mi" + limits: + cpu: "1000m" + memory: "1Gi" -# Will be added in future realease, for now keep "enabled:false" -postgresql-ha: - enabled: false - -### DEPLOY SECRETS WITH private helm chart 'secrets' from platform/secrets -## Name: imagePullSecret -## Description: Secret to pull images from our private repository. -imagePullSecrets: - - name: regcred - -## to create a regcred -## kubectl create secret docker-registry regcred --docker-server= --docker-username= --docker-password= +## MongoDB chart for FEDn statestore +# Please see the documentation for this Bitnami chart for more details on values: +# https://github.com/bitnami/charts/tree/main/bitnami/mongodb +# Please also observe the version we are using in requirements.yaml -celeryWorkers: - replicas: 2 - resources: - requests: - cpu: "100m" - memory: "1Gi" - limits: - cpu: "1000m" - memory: "8Gi" +mongodb: + backups: + enabled: false + image: harbor.scaleoutsystems.com/studio/mongo-backup:0.1.0 + backupSchedule: "*/30 * * * *" # backup schedule for mongodb + restoreFromFile: + enabled: false + image: harbor.scaleoutsystems.com/studio/mongo-restore:0.1.0 + backupFileName: "" + enabled: true + replicaSetName: "rs0" + commonAnnotations: {"reloader.stakater.com/auto": "true"} + podLabels: {"app":"stackn-studio","allow-api-access": "true"} -# default credentials for rabbitmq. override in production! -rabbit: - username: admin - password: "" +mongoexpress: + enabled: true + replicas: 1 + service: + port: 8081 -chartcontroller: - enabled: false - #addSecret -- if true create chart-controller-secret from cluster_config, if false it must be added manually - addSecret: true +eventListener: + studioServiceName: "studio-studio" + studioServicePort: "8080" + appStatusEndpoint: "api/internal/app/status" + appStatusesEndpoint: "api/internal/app/statuses" + image: + repository: harbor.scaleoutsystems.com/studio/studio-kube-controller:main + pullPolicy: IfNotPresent # used to ensure that each time we redeploy always pull the latest image + pullSecret: harborsecret # pull secret for event listener -docker-registry: - enabled: false -prometheus: +# Will be added in future realease, for now keep "enabled:false" +postgresql-ha: enabled: false -grafana: - enabled: false +# Enable reloader for (see reloader.stakater.com) auto reload of deployments when configmaps change reloader: enabled: true namespace: default