From ab907e87dbac43d174aa1bfae28e319c588b8686 Mon Sep 17 00:00:00 2001 From: "Schiller, Tjorben" Date: Tue, 30 Jul 2024 19:20:25 +0200 Subject: [PATCH] feat: fix postgres persistence BREAKING CHANGE: create db password secret; move values in frond- and backend; use ImplementationSpecific ingress path on backend --- README.md | 38 ++- .../terminfinder-backend/templates/NOTES.txt | 6 +- .../templates/deployment.yaml | 22 +- .../templates/secret-database.yaml | 7 + .../charts/terminfinder-backend/values.yaml | 80 +++--- .../terminfinder-frontend/templates/NOTES.txt | 4 +- .../templates/deployment.yaml | 18 +- .../charts/terminfinder-frontend/values.yaml | 49 +--- terminfinder-chart/values.yaml | 252 ------------------ 9 files changed, 99 insertions(+), 377 deletions(-) create mode 100644 terminfinder-chart/charts/terminfinder-backend/templates/secret-database.yaml diff --git a/README.md b/README.md index 7732d7d..a51ecb3 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,13 @@ It's recommended to use a dedicated PostgreSQL instance for production usage. 1. install and run minikube or other local K8s services https://kubernetes.io/docs/tasks/tools/ 2. use scripts in installation below +### Minikube + +```bash +$ minikube addons enable ingress +$ minikube tunnel +``` + ## Installation ### Recommendations @@ -31,31 +38,17 @@ It's recommended to use a dedicated PostgreSQL instance for production usage. CoreDNS. * For production usage, may use an own postgres instance. (Recommended, use the [Cloud Native PG Operator](https://cloudnative-pg.io) in Kubernetes) +* -### Installation steps +### Installation & upgrade steps 1. Prepare the value files. 2. Install the helm charts with `helm install ...` CLI Command: ```bash -# Create a namespace (or use default), where to work in: -$ kubectl create namespace terminfinder-demo - -# First installing the helm chart, to the name -$ helm install terminfinder-demo terminfinder-chart -n terminfinder-demo - -# Verify installation of helm charts: -$ helm list -n terminfinder-demo -$ kubectl get deploy -n terminfinder-demo -``` - -### Upgrade release - -To upgrade the helm chart, use the `helm upgrade ...` command: - -```bash -# Upgrade HelmChart -$ helm upgrade terminfinder-demo terminfinder-chart -n terminfinder-demo +$ helm upgrade --install -n tf --create-namespace tf1 terminfinder-chart +$ helm list -n tf +$ kubectl get pod,deploy,pvc,svc,ing,ep -n tf ``` ### Debug Container @@ -71,10 +64,9 @@ To delete the helm chart (release), use the `helm uninstall...` command. Note that the persistent volume may be available even if the helm release is uninstalled. ```bash -# Delete namespace -$ helm uninstall terminfinder-demo -n terminfinder-demo -$ kubectl delete pvc --all -n terminfinder-demo -$ kubectl delete namespace terminfinder-demo +$ helm uninstall tf1 -n tf +$ kubectl delete pvc --all -n tf +$ kubectl delete namespace tf ``` ## Using an own PostgreSQL DB instance diff --git a/terminfinder-chart/charts/terminfinder-backend/templates/NOTES.txt b/terminfinder-chart/charts/terminfinder-backend/templates/NOTES.txt index 22d413a..684edaa 100644 --- a/terminfinder-chart/charts/terminfinder-backend/templates/NOTES.txt +++ b/terminfinder-chart/charts/terminfinder-backend/templates/NOTES.txt @@ -17,6 +17,6 @@ {{- else if contains "ClusterIP" .Values.service.type }} export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "terminfinder-backend.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") - echo "Visit http://127.0.0.1:8080 to use your application" - kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT -{{- end }} \ No newline at end of file + echo "Visit http://127.0.0.1:{{ .Values.application.port}} to use your application" + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME {{ .Values.application.port }}:$CONTAINER_PORT +{{- end }} diff --git a/terminfinder-chart/charts/terminfinder-backend/templates/deployment.yaml b/terminfinder-chart/charts/terminfinder-backend/templates/deployment.yaml index ab9993e..323c637 100644 --- a/terminfinder-chart/charts/terminfinder-backend/templates/deployment.yaml +++ b/terminfinder-chart/charts/terminfinder-backend/templates/deployment.yaml @@ -1,4 +1,4 @@ -{{- $svc := .Values.global.postgresql.service.name | default (printf "%s-postgresql" .Release.Name) }} +{{- $svc := printf "%s-postgresql" .Release.Name }} apiVersion: apps/v1 kind: Deployment metadata: @@ -45,29 +45,33 @@ spec: - name: DB_USERNAME value: {{ .Values.global.postgresql.auth.username }} - name: ASPNETCORE_URLS - value: http://+:8080 - # Secrets: + value: {{printf "http://+:%d" (int .Values.application.port) }} - name: DB_PASSWORD valueFrom: secretKeyRef: - name: {{ .Values.global.postgresql.auth.existingSecret | default (printf "%s" $svc) }} - key: {{ .Values.global.postgresql.auth.secretKeys.userPasswordKey | default "password" }} - # Patches + name: {{ required "Postgres DB secret name not set" .Values.global.postgresql.auth.existingSecret }} + key: {{ required "Postgres DB password secretkey not set" .Values.global.postgresql.auth.secretKeys.userPasswordKey }} - name: Terminfinder__UseHttps value: "false" - name: Terminfinder__UseCors - value: "false" + value: {{ .Values.application.useCors | quote }} - name: Terminfinder__Log4NetConfigFilename value: log4net.Console.debug.config - name: ConnectionStrings__TerminfinderConnection value: "Server=$(DB_ADDRESS),$(DB_PORT);Database=$(DB_DATABASE);User ID=$(DB_USERNAME);password=$(DB_PASSWORD);" ports: - name: http - containerPort: 8080 + containerPort: {{ int .Values.application.port }} protocol: TCP + command: + - "dotnet" + - "Dataport.Terminfinder.WebAPI.dll" + {{- if .Values.application.migrateDB }} + - "--dbmigrate" + {{- end }} startupProbe: failureThreshold: 3 - periodSeconds: 10 + periodSeconds: 30 httpGet: path: /app port: http diff --git a/terminfinder-chart/charts/terminfinder-backend/templates/secret-database.yaml b/terminfinder-chart/charts/terminfinder-backend/templates/secret-database.yaml new file mode 100644 index 0000000..67fbcd3 --- /dev/null +++ b/terminfinder-chart/charts/terminfinder-backend/templates/secret-database.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: Secret +metadata: + name: postgresql-default-auth +type: kubernetes.io/basic-auth +stringData: + password: {{ randAlphaNum 20 | b64enc | quote }} diff --git a/terminfinder-chart/charts/terminfinder-backend/values.yaml b/terminfinder-chart/charts/terminfinder-backend/values.yaml index 054945d..a9c456b 100644 --- a/terminfinder-chart/charts/terminfinder-backend/values.yaml +++ b/terminfinder-chart/charts/terminfinder-backend/values.yaml @@ -1,19 +1,14 @@ -# Default values for terminfinder-backend. -# This is a YAML-formatted file. -# Declare variables to be passed into your templates. - global: postgresql: auth: - username: terminfinder database: terminfinder - existingSecret: "" # if not set, default: "{{ Release.Name }}-postgres" + username: terminfinder + existingSecret: postgresql-default-auth secretKeys: - userPasswordKey: "" # if not set, default: "password" + userPasswordKey: password service: - name: "" # if not set, default: "{{ Release.Name }}-postgres" ports: - postgresql: 5432 # Default port + postgresql: 5432 replicaCount: 1 @@ -22,17 +17,20 @@ image: pullPolicy: IfNotPresent tag: "0.1.0" +application: + port: 8080 + useCors: true + migrateDB: true + imagePullSecrets: [ ] + nameOverride: "" + fullnameOverride: "" serviceAccount: - # Specifies whether a service account should be created create: true - # Annotations to add to the service account annotations: { } - # The name of the service account to use. - # If not set and create is true, a name is generated using the fullname template name: "" podAnnotations: { } @@ -51,31 +49,24 @@ securityContext: service: type: ClusterIP - port: 80 + port: 8080 ingress: - enabled: false + enabled: true className: "nginx" annotations: - { } - # kubernetes.io/ingress.class: nginx - # nginx.ingress.kubernetes.io/rewrite-target: / - # nginx.ingress.kubernetes.io/ssl-redirect: "true" - # cert-manager.io/cluster-issuer: letsencrypt-production + nginx.ingress.kubernetes.io/use-regex: "true" + nginx.ingress.kubernetes.io/rewrite-target: /$2 + nginx.ingress.kubernetes.io/enable-cors: "true" hosts: - - host: terminfinder.opencode.de + - host: localhost + port: 80 paths: - - path: /api - pathType: Prefix + - path: /api(/|$)(.*) + pathType: ImplementationSpecific tls: [ ] - # - secretName: cert-terminfinder.opencode.de - # hosts: - # - terminfinder.de resources: - # We recommend to not use limits, since workload spikes can hinder the application or cause crashes - # due to OOM errors. Read more about it here: - # https://cloud.google.com/blog/products/containers-kubernetes/kubernetes-best-practices-resource-requests-and-limits?hl=en limits: cpu: 500m memory: 256Mi @@ -99,27 +90,28 @@ affinity: { } postgresql: enabled: true - serviceAccount: - create: true + auth: + enablePostgresUser: false - ## Set permissions for the data volume - ## Only needed when volume has not correct permissions - volumePermissions: - enabled: true + primary: + persistence: + enabled: true - image: - registry: docker.io # Notice, may this is not allowed - repository: bitnami/bitnami-shell - # tag: 11-debian-11-r77 - # pullPolicy: Always - # pullSecrets: [] + resources: + requests: + memory: 256Mi + cpu: 250m + limits: + memory: 256Mi + cpu: 250m initdb: - # Enabling the UUID-OSSP scripts: 99-enable-uuid.sql: | CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; ALTER EXTENSION "uuid-ossp" SET SCHEMA public; - # More variables / parameters can be found here: - # https://github.com/bitnami/charts/tree/main/bitnami/postgresql#parameters + readReplicas: + replicaCount: 0 + persistence: + enabled: false diff --git a/terminfinder-chart/charts/terminfinder-frontend/templates/NOTES.txt b/terminfinder-chart/charts/terminfinder-frontend/templates/NOTES.txt index 1ff943b..12792e7 100644 --- a/terminfinder-chart/charts/terminfinder-frontend/templates/NOTES.txt +++ b/terminfinder-chart/charts/terminfinder-frontend/templates/NOTES.txt @@ -17,7 +17,7 @@ {{- else if contains "ClusterIP" .Values.service.type }} export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "terminfinder-frontend.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") - echo "Visit http://127.0.0.1:8080 to use your application" - kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT + echo "Visit http://127.0.0.1:80 to use your application" + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 80:$CONTAINER_PORT {{- end }} 2. Don't forget to deploy the Backend! diff --git a/terminfinder-chart/charts/terminfinder-frontend/templates/deployment.yaml b/terminfinder-chart/charts/terminfinder-frontend/templates/deployment.yaml index 7ccaa11..a2adb14 100644 --- a/terminfinder-chart/charts/terminfinder-frontend/templates/deployment.yaml +++ b/terminfinder-chart/charts/terminfinder-frontend/templates/deployment.yaml @@ -35,16 +35,18 @@ spec: image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.image.pullPolicy }} env: - - name: ADDRESSING - value: {{ .Values.customerConfig.ADDRESSING }} - - name: LOCALE - value: {{ .Values.customerConfig.LOCALE }} + - name: CUSTOMER_ID + value: {{ required "no customerId set" .Values.application.customerId }} + - name: API_URL + value: {{ .Values.application.apiUrl }} - name: TITLE - value: {{ .Values.customerConfig.TITLE }} + value: {{ .Values.application.title }} + - name: LOCALE + value: {{ required "no locale set" .Values.application.locale }} + - name: ADDRESSING + value: {{ required "no addressing set" .Values.application.addressing }} - name: EMAIL - value: {{ .Values.customerConfig.EMAIL }} - - name: API_URL - value: {{ .Values.app.backend_url }} + value: {{ required "no email set" .Values.application.email }} ports: - name: http containerPort: 8080 diff --git a/terminfinder-chart/charts/terminfinder-frontend/values.yaml b/terminfinder-chart/charts/terminfinder-frontend/values.yaml index 83ca29d..cd6df5a 100644 --- a/terminfinder-chart/charts/terminfinder-frontend/values.yaml +++ b/terminfinder-chart/charts/terminfinder-frontend/values.yaml @@ -1,17 +1,12 @@ -# Default values for terminfinder-frontend. -# This is a YAML-formatted file. -# Declare variables to be passed into your templates. +application: + customerId: "80248A42-8FE2-4D4A-89DA-02E683511F76" + apiUrl: "" + title: "" + locale: "de-DE" + addressing: "du" + email: "demo@demo.demo" -customerConfig: - ADDRESSING: "du" # supported: du, sie - LOCALE: "de-DE" # supported: DE-de, EN-en - TITLE: "Terminfinder Demo" - EMAIL: "" - -app: - backend_url: https://terminfinder.opencode.de/api # Public URL to Backend - -replicaCount: 1 # Not HA for now! +replicaCount: 1 image: repository: registry.opencode.de/dataport/terminfinder/terminfinder-frontend @@ -23,12 +18,8 @@ nameOverride: "" fullnameOverride: "" serviceAccount: - # Specifies whether a service account should be created - create: true - # Annotations to add to the service account + create: false annotations: { } - # The name of the service account to use. - # If not set and create is true, a name is generated using the fullname template name: "" podAnnotations: { } @@ -41,39 +32,26 @@ podSecurityContext: securityContext: capabilities: - # add: - # - NET_BIND_SERVICE drop: - ALL readOnlyRootFilesystem: false - # runAsUser: 1000 service: type: ClusterIP - port: 80 + port: 8080 ingress: - enabled: false + enabled: true className: "nginx" - annotations: - { } - # kubernetes.io/ingress.class: nginx - # nginx.ingress.kubernetes.io/ssl-redirect: "true" - # cert-manager.io/cluster-issuer: letsencrypt-production hosts: - - host: terminfinder.opencode.de + - host: localhost + port: 80 paths: - path: / pathType: Prefix tls: [ ] - # - secretName: cert-terminfinder.opencode.de - # hosts: - # - terminfinder.de resources: - # We recommend to not use limits, since workload spikes can hinder the application or cause crashes - # due to OOM errors. Read more about it here: - # https://cloud.google.com/blog/products/containers-kubernetes/kubernetes-best-practices-resource-requests-and-limits?hl=en limits: cpu: 500m memory: 256Mi @@ -86,7 +64,6 @@ autoscaling: minReplicas: 1 maxReplicas: 20 targetCPUUtilizationPercentage: 80 - # targetMemoryUtilizationPercentage: 80 nodeSelector: { } diff --git a/terminfinder-chart/values.yaml b/terminfinder-chart/values.yaml index 2dd7bf5..a3aeff9 100644 --- a/terminfinder-chart/values.yaml +++ b/terminfinder-chart/values.yaml @@ -1,255 +1,3 @@ -terminfinder-frontend: - # Default values for terminfinder-frontend. - # This is a YAML-formatted file. - # Declare variables to be passed into your templates. - - customerConfig: - ADDRESSING: "sie" # supported: du, sie - LOCALE: "de-DE" # supported: DE-de, EN-en - TITLE: "Terminfinder MyDemo" - EMAIL: "" - - app: - backend_url: https://terminfinder.opencode.de/api # Public URL to Backend - - replicaCount: 1 # Not HA for now! - - imagePullSecrets: [ ] - nameOverride: "" - fullnameOverride: "" - - serviceAccount: - # Specifies whether a service account should be created - create: true - # Annotations to add to the service account - annotations: { } - # The name of the service account to use. - # If not set and create is true, a name is generated using the fullname template - name: "" - - podAnnotations: { } - - podSecurityContext: - runAsNonRoot: true - runAsUser: 101 - runAsGroup: 101 - fsGroup: 101 - - securityContext: - capabilities: - # add: - # - NET_BIND_SERVICE - drop: - - ALL - readOnlyRootFilesystem: false - # runAsUser: 1000 - - service: - type: ClusterIP - port: 80 - - ingress: - enabled: false - className: "nginx" - annotations: - { } - # kubernetes.io/ingress.class: nginx - # nginx.ingress.kubernetes.io/ssl-redirect: "true" - # cert-manager.io/cluster-issuer: letsencrypt-production - hosts: - - host: terminfinder.opencode.de - paths: - - path: / - pathType: Prefix - tls: [ ] - # - secretName: cert-terminfinder.opencode.de - # hosts: - # - terminfinder.de - - resources: - # We recommend to not use limits, since workload spikes can hinder the application or cause crashes - # due to OOM errors. Read more about it here: - # https://cloud.google.com/blog/products/containers-kubernetes/kubernetes-best-practices-resource-requests-and-limits?hl=en - limits: - cpu: 500m - memory: 256Mi - requests: - cpu: 500m - memory: 256Mi - - autoscaling: - enabled: false - minReplicas: 1 - maxReplicas: 20 - targetCPUUtilizationPercentage: 80 - # targetMemoryUtilizationPercentage: 80 - - nodeSelector: { } - - tolerations: [ ] - - affinity: { } - -terminfinder-backend: - # Default values for terminfinder-backend. - # This is a YAML-formatted file. - # Declare variables to be passed into your templates. - - replicaCount: 1 - - imagePullSecrets: [ ] - nameOverride: "" - fullnameOverride: "" - - serviceAccount: - # Specifies whether a service account should be created - create: true - # Annotations to add to the service account - annotations: { } - # The name of the service account to use. - # If not set and create is true, a name is generated using the fullname template - name: "" - - podAnnotations: { } - - podSecurityContext: - runAsUser: 1000 - fsGroup: 2000 - runAsGroup: 3000 - - securityContext: - capabilities: - drop: - - ALL - readOnlyRootFilesystem: false - runAsNonRoot: true - - service: - type: ClusterIP - port: 80 - - ingress: - enabled: false - className: "nginx" - annotations: - { } - # kubernetes.io/ingress.class: nginx - # nginx.ingress.kubernetes.io/rewrite-target: / - # nginx.ingress.kubernetes.io/ssl-redirect: "true" - # cert-manager.io/cluster-issuer: letsencrypt-production - hosts: - - host: terminfinder.opencode.de - paths: - - path: /api - pathType: Prefix - tls: [ ] - # - secretName: cert-terminfinder.opencode.de - # hosts: - # - terminfinder.de - - resources: - # We recommend to not use limits, since workload spikes can hinder the application or cause crashes - # due to OOM errors. Read more about it here: - # https://cloud.google.com/blog/products/containers-kubernetes/kubernetes-best-practices-resource-requests-and-limits?hl=en - limits: - cpu: 500m - memory: 256Mi - requests: - cpu: 500m - memory: 256Mi - - autoscaling: - enabled: false - minReplicas: 1 - maxReplicas: 20 - targetCPUUtilizationPercentage: 80 - targetMemoryUtilizationPercentage: 80 - - nodeSelector: { } - - tolerations: [ ] - - affinity: { } - - postgresql: - enabled: true - - #architecture: standalone - - serviceAccount: - create: true - - ## Set permissions for the data volume - ## Only needed when volume has not correct permissions - volumePermissions: - enabled: false - - image: - registry: docker.io - repository: bitnami/bitnami-shell - - resources: - requests: - memory: 64Mi - cpu: 250m - limits: - memory: 64Mi - cpu: 250m - - containerSecurityContext: - enabled: false - runAsUser: 1001 - runAsGroup: 1001 - allowPrivilegeEscalation: false - runAsNonRoot: true - capabilities: - drop: - - ALL - - primary: - ## Enable security context with non-root user - podSecurityContext: - enabled: false - runAsUser: 1001 - runAsGroup: 1001 - fsGroup: 1001 - containerSecurityContext: - enabled: false - runAsUser: 1001 - runAsGroup: 1001 - allowPrivilegeEscalation: false - runAsNonRoot: true - capabilities: - drop: - - ALL - - ## Enable persistence using Persistent Volume Claims - ## For BSI compliance, we need to use non-root user - persistence: - enabled: true - accessModes: - - ReadWriteOnce - size: 8Gi - - # Resources (minimal) - resources: - requests: - memory: 256Mi - cpu: 250m - limits: - memory: 256Mi - cpu: 250m - - initdb: - # Enabling the UUID-OSSP - scripts: - 99-enable-uuid.sql: | - CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; - ALTER EXTENSION "uuid-ossp" SET SCHEMA public; - - # More variables / parameters can be found here: - # https://github.com/bitnami/charts/tree/main/bitnami/postgresql#parameters - terminfinder-resources: grafana: enabled: false