From 639d507317ff29e92ecbb99818380edc0574db43 Mon Sep 17 00:00:00 2001 From: Joshua Clayton Date: Mon, 14 Jul 2025 15:55:05 -0600 Subject: [PATCH 1/4] Hawkbit: update to latest hawkbit version 0.9.0 Fix mountPaths according to hawkbit docker compose Fix whitespace from yaml lint Update hawkbit to 0.9.0 --- charts/hawkbit/Chart.yaml | 2 +- charts/hawkbit/templates/deployment.yaml | 14 +++++++------- charts/hawkbit/templates/pvc.yaml | 10 +++++----- charts/hawkbit/values.yaml | 19 +++---------------- 4 files changed, 16 insertions(+), 29 deletions(-) diff --git a/charts/hawkbit/Chart.yaml b/charts/hawkbit/Chart.yaml index f2bfa03f..406e6f9f 100644 --- a/charts/hawkbit/Chart.yaml +++ b/charts/hawkbit/Chart.yaml @@ -11,7 +11,7 @@ --- apiVersion: v2 version: 1.7.0 -appVersion: "0.5.0-mysql" +appVersion: "0.9.0" description: | Eclipse hawkBit™ is a domain independent back-end framework for rolling out software updates to constrained edge devices as well as more powerful controllers and gateways connected to diff --git a/charts/hawkbit/templates/deployment.yaml b/charts/hawkbit/templates/deployment.yaml index 614581af..0f71c6ef 100644 --- a/charts/hawkbit/templates/deployment.yaml +++ b/charts/hawkbit/templates/deployment.yaml @@ -34,7 +34,7 @@ spec: image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" imagePullPolicy: {{ .Values.image.pullPolicy }} env: - - name: SPRING_PROFILES_ACTIVE + - name: PROFILES value: "{{ .Values.spring.profiles }}" - name: "SPRING_DATASOURCE_URL" {{- if .Values.env.springDatasourceUrl }} @@ -113,13 +113,13 @@ spec: {{- end }} {{- end }} volumes: - - name: configmap - configMap: - name: {{ include "hawkbit.fullname" . }} + - name: configmap + configMap: + name: {{ include "hawkbit.fullname" . }} {{- if .Values.fileStorage.enabled }} - - name: storage - persistentVolumeClaim: - claimName: {{ include "hawkbit.fullname" . }}-data + - name: storage + persistentVolumeClaim: + claimName: {{ include "hawkbit.fullname" . }}-data {{- end}} {{- if .Values.extraVolumes }} {{ toYaml .Values.extraVolumes | nindent 6 }} diff --git a/charts/hawkbit/templates/pvc.yaml b/charts/hawkbit/templates/pvc.yaml index 4be6f9ef..0ce880b9 100644 --- a/charts/hawkbit/templates/pvc.yaml +++ b/charts/hawkbit/templates/pvc.yaml @@ -11,9 +11,9 @@ metadata: {{- toYaml . | nindent 4 }} {{- end }} spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: {{ .Values.fileStorage.pvcSize }} + accessModes: + - ReadWriteOnce + resources: + requests: + storage: {{ .Values.fileStorage.pvcSize }} {{- end }} diff --git a/charts/hawkbit/values.yaml b/charts/hawkbit/values.yaml index 44a4c17b..eb4b60ce 100644 --- a/charts/hawkbit/values.yaml +++ b/charts/hawkbit/values.yaml @@ -15,7 +15,7 @@ image: repository: "hawkbit/hawkbit-update-server" - tag: 0.5.0-mysql + tag: '0.9.0' pullPolicy: IfNotPresent replicaCount: 1 @@ -78,7 +78,7 @@ routes: fileStorage: enabled: true pvcSize: "1Gi" - mountPath: "/var/lib/hawkbit-storage" + mountPath: "/artifactrepo" # env vars for configuration env: @@ -119,7 +119,7 @@ extraVolumes: [] extraVolumeMounts: [] configMap: - mountPath: "/opt/hawkbit/config" + mountPath: "/config" spring: profiles: "mysql" @@ -129,19 +129,6 @@ config: server: useForwardHeaders: true hawkbit: - ## Configuration for the device management federation - ## ref: https://www.eclipse.org/hawkbit/apis/dmf_api/ - ## These configuration will become available once https://github.com/eclipse/hawkbit/pull/890 is merged - # dmf: - # hono: - # enabled: false - # tenant-list-uri: "http://[DEVICE_REGISTRY_HOST]:8080/admin/tenants" - # device-list-uri: "http://[DEVICE_REGISTRY_HOST]:8080/admin/$$tenantId/devices" - # credentials-list-uri: "http://[DEVICE_REGISTRY_HOST]:8080/v1/credentials/$$tenantId/$$deviceId" - # authentication-method: "oidc" - # username: "[KEYCLOAK_HAWKBIT_USERNAME]" - # oidc-token-uri: "http://[KEYCLOAK_HOST]:8080/auth/realms/master/protocol/openid-connect/token" - # oidc-client-id: "[KEYCLOAK_DEVICE_REGISTRY_CLIENT_ID]" spring: cloud: stream: From ce2d0b6c5f294c83582e9bbe772757d4b6aab395 Mon Sep 17 00:00:00 2001 From: Joshua Clayton Date: Thu, 26 Jun 2025 15:03:09 -0600 Subject: [PATCH 2/4] Hawkbit: hawbit 0.10.0 and lots more Make the chart compatible with k8s secrets Include an initContainer to intialize the database Update to hawkbit version 0.10.0 Support external database Make rabbitmq optional Support dynamic secrets Add extravolumemounts --- charts/hawkbit/.helmignore | 2 + charts/hawkbit/Chart.yaml | 2 +- charts/hawkbit/templates/_helpers.tpl | 75 ++++++++++++++++++ charts/hawkbit/templates/configmap.yaml | 20 ++++- charts/hawkbit/templates/deployment.yaml | 79 +++++++++++++++---- charts/hawkbit/templates/secrets.yaml | 23 +++--- .../templates/tests/test-connection.yaml | 2 +- charts/hawkbit/values.yaml | 72 +++++++---------- 8 files changed, 200 insertions(+), 75 deletions(-) diff --git a/charts/hawkbit/.helmignore b/charts/hawkbit/.helmignore index 50af0317..7aff2ccb 100644 --- a/charts/hawkbit/.helmignore +++ b/charts/hawkbit/.helmignore @@ -20,3 +20,5 @@ .idea/ *.tmproj .vscode/ +# Packaged chart tarballs +*.tgz diff --git a/charts/hawkbit/Chart.yaml b/charts/hawkbit/Chart.yaml index 406e6f9f..436acc55 100644 --- a/charts/hawkbit/Chart.yaml +++ b/charts/hawkbit/Chart.yaml @@ -11,7 +11,7 @@ --- apiVersion: v2 version: 1.7.0 -appVersion: "0.9.0" +appVersion: "0.10.0" description: | Eclipse hawkBit™ is a domain independent back-end framework for rolling out software updates to constrained edge devices as well as more powerful controllers and gateways connected to diff --git a/charts/hawkbit/templates/_helpers.tpl b/charts/hawkbit/templates/_helpers.tpl index a097f0e4..c03c9819 100644 --- a/charts/hawkbit/templates/_helpers.tpl +++ b/charts/hawkbit/templates/_helpers.tpl @@ -54,3 +54,78 @@ Return the appropriate apiVersion for ingress. {{- print "networking.k8s.io/v1beta1" -}} {{- end -}} {{- end -}} + +{{/* +Return the secret with the Hawkbit credentials. +*/}} +{{- define "hawkbit.secretName" -}} + {{- if .Values.auth.existingSecret -}} + {{ print (tpl .Values.auth.existingSecret $) -}} + {{- else -}} + {{ printf "%s" (include "hawkbit.fullname" .) -}} + {{- end -}} +{{- end -}} + +{{/* +Database helpers — switch between externalDatabase and the bundled mysql subchart. +*/}} + +{{- define "hawkbit.database.url" -}} + {{- if .Values.externalDatabase.url -}} + {{- .Values.externalDatabase.url -}} + {{- else if and .Values.externalDatabase.host (eq (.Values.externalDatabase.type | default "mysql") "postgresql") -}} + {{- printf "jdbc:postgresql://%s:%v/%s" .Values.externalDatabase.host (.Values.externalDatabase.port | default 5432) (.Values.externalDatabase.database | default "hawkbit") -}} + {{- else if .Values.externalDatabase.host -}} + {{- printf "jdbc:mariadb://%s:%v/%s" .Values.externalDatabase.host (.Values.externalDatabase.port | default 3306) (.Values.externalDatabase.database | default "hawkbit") -}} + {{- else if .Values.mysql.enabled -}} + {{- printf "jdbc:mariadb://%s-mysql:3306/%s" (include "hawkbit.fullname" .) .Values.mysql.auth.database -}} + {{- else -}} + {{- fail "Either externalDatabase.host or mysql.enabled must be set" -}} + {{- end -}} +{{- end -}} + +{{- define "hawkbit.database.user" -}} + {{- if .Values.externalDatabase.user -}} + {{- .Values.externalDatabase.user -}} + {{- else if .Values.mysql.enabled -}} + {{- "root" -}} + {{- else -}} + {{- fail "externalDatabase.user is required when mysql.enabled=false" -}} + {{- end -}} +{{- end -}} + +{{- define "hawkbit.database.secretName" -}} + {{- if .Values.externalDatabase.existingSecret -}} + {{- .Values.externalDatabase.existingSecret -}} + {{- else if .Values.mysql.enabled -}} + {{- include "mysql.secretName" .Subcharts.mysql -}} + {{- else -}} + {{- printf "%s-external-db" (include "hawkbit.fullname" .) -}} + {{- end -}} +{{- end -}} + +{{- define "hawkbit.database.secretPasswordKey" -}} + {{- if .Values.externalDatabase.existingSecretPasswordKey -}} + {{- .Values.externalDatabase.existingSecretPasswordKey -}} + {{- else if .Values.mysql.enabled -}} + {{- "mysql-root-password" -}} + {{- else -}} + {{- "password" -}} + {{- end -}} +{{- end -}} + +{{- define "hawkbit.database.secretUsernameKey" -}} + {{- if .Values.externalDatabase.existingSecretUsernameKey -}} + {{- .Values.externalDatabase.existingSecretUsernameKey -}} + {{- end -}} +{{- end -}} + +{{- define "hawkbit.spring.profiles" -}} + {{- if .Values.spring.profiles -}} + {{- .Values.spring.profiles -}} + {{- else if eq (.Values.externalDatabase.type | default "mysql") "postgresql" -}} + {{- "postgresql" -}} + {{- else -}} + {{- "mysql" -}} + {{- end -}} +{{- end -}} diff --git a/charts/hawkbit/templates/configmap.yaml b/charts/hawkbit/templates/configmap.yaml index de11d2a2..f1350ccd 100644 --- a/charts/hawkbit/templates/configmap.yaml +++ b/charts/hawkbit/templates/configmap.yaml @@ -6,4 +6,22 @@ metadata: {{ include "hawkbit.labels" . | indent 4 }} data: application.yaml: |- -{{ toYaml .Values.config.application | indent 4}} + {{- $rabbitmqConfig := dict -}} + {{- if .Values.rabbitmq.enabled -}} + {{- $rabbitmqConfig = dict "spring" (dict + "rabbitmq" (dict + "host" (printf "%s-rabbitmq" .Release.Name) + "username" .Values.rabbitmq.auth.username + ) + "cloud" (dict "stream" (dict "bindings" (dict + "default" (dict "group" "hawkbit") + "device-created" (dict "destination" "device-registry.device-created") + "device-updated" (dict "destination" "device-registry.device-updated") + "device-deleted" (dict "destination" "device-registry.device-deleted") + ))) + ) -}} + {{- else -}} + {{- $rabbitmqConfig = dict "spring" (dict "autoconfigure" (dict "exclude" "org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration")) -}} + {{- end -}} + {{- $authConfig := dict "hawkbit" (dict "security" (dict "user" (dict (.Values.auth.username) (dict "tenant" "DEFAULT" "roles" (list "TENANT_ADMIN"))))) -}} + {{- mergeOverwrite (deepCopy .Values.config.application) $rabbitmqConfig $authConfig | toYaml | nindent 4 }} diff --git a/charts/hawkbit/templates/deployment.yaml b/charts/hawkbit/templates/deployment.yaml index 0f71c6ef..f29a5993 100644 --- a/charts/hawkbit/templates/deployment.yaml +++ b/charts/hawkbit/templates/deployment.yaml @@ -25,6 +25,35 @@ spec: {{- toYaml . | nindent 8 }} {{- end }} spec: + initContainers: + - name: hawkbit-init + image: "{{ .Values.image.initContainer }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + env: + - name: HAWKBIT_DB_MODE + value: "migrate" + - name: "SPRING_DATASOURCE_URL" + value: {{ include "hawkbit.database.url" . | quote }} + - name: SPRING_DATASOURCE_USERNAME + {{- if include "hawkbit.database.secretUsernameKey" . }} + valueFrom: + secretKeyRef: + name: {{ include "hawkbit.database.secretName" . }} + key: {{ include "hawkbit.database.secretUsernameKey" . }} + {{- else }} + value: {{ include "hawkbit.database.user" . | quote }} + {{- end }} + - name: SPRING_DATASOURCE_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "hawkbit.database.secretName" . }} + key: {{ include "hawkbit.database.secretPasswordKey" . }} + - name: AND_THEN + value: "true" + {{- if .Values.extraVolumeMounts }} + volumeMounts: + {{- toYaml .Values.extraVolumeMounts | nindent 12 }} + {{- end }} {{- with .Values.image.pullSecrets }} imagePullSecrets: {{- toYaml . | nindent 8 }} @@ -35,35 +64,53 @@ spec: imagePullPolicy: {{ .Values.image.pullPolicy }} env: - name: PROFILES - value: "{{ .Values.spring.profiles }}" - - name: "SPRING_DATASOURCE_URL" - {{- if .Values.env.springDatasourceUrl }} - value: "{{ .Values.env.springDatasourceUrl }}" + value: {{ include "hawkbit.spring.profiles" . | quote }} + - name: SPRING_FLYWAY_ENABLED + value: "false" + - name: SPRING_DATASOURCE_USERNAME + {{- if include "hawkbit.database.secretUsernameKey" . }} + valueFrom: + secretKeyRef: + name: {{ include "hawkbit.database.secretName" . }} + key: {{ include "hawkbit.database.secretUsernameKey" . }} {{- else }} - value: "jdbc:mariadb://{{ if .Values.mysql.enabled }}{{ .Release.Name }}-mysql{{ else }}{{ .Values.env.springDatasourceHost }}{{ end }}:3306/{{ .Values.env.springDatasourceDb }}" + value: {{ include "hawkbit.database.user" . | quote }} {{- end }} - - name: "SPRING_APPLICATION_JSON" + - name: SPRING_DATASOURCE_PASSWORD valueFrom: secretKeyRef: - name: {{ include "hawkbit.fullname" . }} - key: "SPRING_APPLICATION_JSON" - - name: "SPRING_RABBITMQ_HOST" - value: "{{ if .Values.rabbitmq.enabled }}{{ .Release.Name }}-rabbitmq{{ else }}{{ .Values.env.springRabbitmqHost }}{{ end }}" - - name: "SPRING_RABBITMQ_USERNAME" - value: "{{ .Values.env.springRabbitmqUsername }}" + name: {{ include "hawkbit.database.secretName" . }} + key: {{ include "hawkbit.database.secretPasswordKey" . }} + - name: "SPRING_DATASOURCE_URL" + value: {{ include "hawkbit.database.url" . | quote }} + {{- if .Values.rabbitmq.enabled }} - name: "SPRING_RABBITMQ_PASSWORD" valueFrom: secretKeyRef: - name: "{{ template "hawkbit.fullname" . }}-rabbitmq-pass" - key: "rabbitmq-pass" + name: {{ include "rabbitmq.secretPasswordName" .Subcharts.rabbitmq }} + key: rabbitmq-password + {{- end }} + - name: {{ printf "HAWKBIT_SECURITY_USER_%s_PASSWORD" (.Values.auth.username | upper) }} + valueFrom: + secretKeyRef: + name: {{ include "hawkbit.secretName" . }} + key: hawkbit-password {{- if .Values.fileStorage.enabled }} - name: "org.eclipse.hawkbit.repository.file.path" value: {{ .Values.fileStorage.mountPath }} {{- end }} + {{- if .Values.extraEnv }} + {{- if kindIs "slice" .Values.extraEnv }} + {{- toYaml .Values.extraEnv | nindent 12 }} + {{- else if kindIs "map" .Values.extraEnv }} {{- range $key, $value := .Values.extraEnv }} - name: "{{ $key }}" value: "{{ $value }}" {{- end }} + {{- else }} + # .Values.extraEnv of type {{kindOf .Values.extraEnv}} is ignored + {{- end }} + {{- end }} ports: - name: http containerPort: 8080 @@ -88,7 +135,7 @@ spec: mountPath: {{ .Values.fileStorage.mountPath }} {{- end }} {{- if .Values.extraVolumeMounts }} - {{ toYaml .Values.extraVolumeMounts | nindent 12 }} + {{- toYaml .Values.extraVolumeMounts | nindent 12 }} {{- end }} resources: {{ toYaml .Values.resources | indent 12 }} @@ -122,5 +169,5 @@ spec: claimName: {{ include "hawkbit.fullname" . }}-data {{- end}} {{- if .Values.extraVolumes }} - {{ toYaml .Values.extraVolumes | nindent 6 }} + {{- toYaml .Values.extraVolumes | nindent 8 }} {{- end }} diff --git a/charts/hawkbit/templates/secrets.yaml b/charts/hawkbit/templates/secrets.yaml index 2def1c4a..9533fe60 100644 --- a/charts/hawkbit/templates/secrets.yaml +++ b/charts/hawkbit/templates/secrets.yaml @@ -1,3 +1,4 @@ +{{- if not .Values.auth.existingSecret }} apiVersion: v1 kind: Secret metadata: @@ -6,17 +7,11 @@ metadata: {{ include "hawkbit.labels" . | indent 4 }} type: Opaque data: - SPRING_APPLICATION_JSON: {{ .Values.config.secrets | toJson | b64enc }} ---- -apiVersion: v1 -kind: Secret -metadata: - name: {{ template "hawkbit.fullname" . }}-rabbitmq-pass - labels: - app.kubernetes.io/name: {{ include "hawkbit.name" . }} - helm.sh/chart: {{ include "hawkbit.chart" . }} - app.kubernetes.io/instance: {{ .Release.Name }} - app.kubernetes.io/managed-by: {{ .Release.Service }} -type: Opaque -data: - rabbitmq-pass: {{ .Values.env.springRabbitmqPassword | b64enc | quote }} +{{- if .Values.config.secrets }} + hawkbit-dmf-password: {{ .Values.config.secrets.hawkbit.dmf.hono.password | b64enc | quote }} + hawkbit-password: {{ .Values.config.secrets.spring.securinty.user.password | b64enc | quote }} +{{- else }} + hawkbit-dmf-password: {{ .Values.auth.dmfPassword | b64enc | quote }} + hawkbit-password: {{ .Values.auth.password | b64enc | quote }} +{{- end }} +{{- end }} diff --git a/charts/hawkbit/templates/tests/test-connection.yaml b/charts/hawkbit/templates/tests/test-connection.yaml index 1cc847ab..aa38fa89 100644 --- a/charts/hawkbit/templates/tests/test-connection.yaml +++ b/charts/hawkbit/templates/tests/test-connection.yaml @@ -16,7 +16,7 @@ spec: command: ['curl'] args: [ "-X", "GET", - "-u", "{{ .Values.config.application.spring.security.user.name }}:{{ trimPrefix "{noop}" .Values.config.secrets.spring.security.user.password }}", + "-u", "{{ .Values.auth.username }}:{{ trimPrefix "{noop}" .Values.auth.password }}", "http://{{ include "hawkbit.fullname" . }}:{{ .Values.service.port }}/rest/v1/userinfo" ] restartPolicy: Never diff --git a/charts/hawkbit/values.yaml b/charts/hawkbit/values.yaml index eb4b60ce..4b8a75ee 100644 --- a/charts/hawkbit/values.yaml +++ b/charts/hawkbit/values.yaml @@ -15,8 +15,17 @@ image: repository: "hawkbit/hawkbit-update-server" - tag: '0.9.0' + tag: '0.10.0' pullPolicy: IfNotPresent + initContainer: "hawkbit/hawkbit-repository-jpa-init" + +# auth configuration +auth: + # if set, the secret will be used to set the hawkbit user password + existingSecret: "" + username: "admin" + password: "{noop}admin" + dmfPassword: "[KEYCLOAK_HAWKBIT_USER_PASSWORD]" replicaCount: 1 @@ -80,19 +89,10 @@ fileStorage: pvcSize: "1Gi" mountPath: "/artifactrepo" -# env vars for configuration -env: - springDatasourceHost: "hawkbit-mysql" - springDatasourceDb: "hawkbit" - # if springDatasourceUrl is set override default mysql db url - springDatasourceUrl: "" - springRabbitmqHost: "hawkbit-rabbitmq" - springRabbitmqUsername: "hawkbit" - springRabbitmqPassword: "hawkbit" - # optional env vars -extraEnv: {} - # JAVA_TOOL_OPTIONS: "-Xms1024m -Xmx1024m" +extraEnv: [] +# - name: JAVA_TOOL_OPTIONS: +# value: "-Xms1024m -Xmx1024m" resources: {} # We usually recommend not to specify default resources and to leave this as a conscious @@ -129,37 +129,21 @@ config: server: useForwardHeaders: true hawkbit: - spring: - cloud: - stream: - bindings: - default: - group: "hawkbit" - device-created: - destination: "device-registry.device-created" - device-updated: - destination: "device-registry.device-updated" - device-deleted: - destination: "device-registry.device-deleted" - security: - user: - name: admin - secrets: - hawkbit: - dmf: - hono: - password: "[KEYCLOAK_HAWKBIT_USER_PASSWORD]" - spring: - security: - user: - # the "{noop}" prefix is needed! - password: "{noop}admin" - datasource: - username: hawkbit - password: hawkbit - ## dependency charts config +## External database configuration (used when mysql.enabled=false). +## type: mysql (default) or postgresql +externalDatabase: + type: mysql + host: "" + port: "" + database: hawkbit + user: "" + url: "" # optional: override the full JDBC URL + existingSecret: "" + existingSecretPasswordKey: "" + existingSecretUsernameKey: "" + ## ref: https://github.com/bitnami/charts/blob/master/bitnami/mysql/values.yaml mysql: enabled: true @@ -170,6 +154,8 @@ mysql: enabled: true architecture: standalone auth: + # The secret has to contain the keys mysql-root-password, mysql-replication-password and mysql-password + existingSecret: "" username: hawkbit password: hawkbit database: hawkbit @@ -184,6 +170,8 @@ rabbitmq: volumePermissions: enabled: true auth: + existingPasswordSecret: "" + existingSecretPasswordKey: rabbitmq-password username: hawkbit password: hawkbit metrics: From a817841de3761d0351f7dc220eced3ad4b4843b5 Mon Sep 17 00:00:00 2001 From: Joshua Clayton Date: Sat, 25 Apr 2026 22:57:40 -0600 Subject: [PATCH 3/4] refactor: get usernames and passwords out of env and values Put most of them into secrets, with fallbacks fix default config path --- charts/hawkbit/templates/_helpers.tpl | 24 ++++++++ charts/hawkbit/templates/configmap.yaml | 12 +++- charts/hawkbit/templates/deployment.yaml | 76 ++++++++++-------------- charts/hawkbit/templates/secrets.yaml | 54 ++++++++++++++--- charts/hawkbit/values.yaml | 58 ++++++++++++++++-- 5 files changed, 163 insertions(+), 61 deletions(-) diff --git a/charts/hawkbit/templates/_helpers.tpl b/charts/hawkbit/templates/_helpers.tpl index c03c9819..08ecb0be 100644 --- a/charts/hawkbit/templates/_helpers.tpl +++ b/charts/hawkbit/templates/_helpers.tpl @@ -66,6 +66,30 @@ Return the secret with the Hawkbit credentials. {{- end -}} {{- end -}} +{{- define "hawkbit.userCredentialsSecretName" -}} + {{- if .Values.auth.existingSecret -}} + {{- .Values.auth.existingSecret -}} + {{- else -}} + {{- printf "%s-user" (include "hawkbit.fullname" .) -}} + {{- end -}} +{{- end -}} + +{{- define "hawkbit.dbCredentialsSecretName" -}} + {{- if .Values.externalDatabase.existingSecret -}} + {{- .Values.externalDatabase.existingSecret -}} + {{- else -}} + {{- printf "%s-db" (include "hawkbit.fullname" .) -}} + {{- end -}} +{{- end -}} + +{{- define "hawkbit.rabbitmqCredentialsSecretName" -}} + {{- if .Values.rabbitmq.credentialsSecret -}} + {{- .Values.rabbitmq.credentialsSecret -}} + {{- else -}} + {{- printf "%s-rabbitmq" (include "hawkbit.fullname" .) -}} + {{- end -}} +{{- end -}} + {{/* Database helpers — switch between externalDatabase and the bundled mysql subchart. */}} diff --git a/charts/hawkbit/templates/configmap.yaml b/charts/hawkbit/templates/configmap.yaml index f1350ccd..0ceb8be2 100644 --- a/charts/hawkbit/templates/configmap.yaml +++ b/charts/hawkbit/templates/configmap.yaml @@ -11,7 +11,6 @@ data: {{- $rabbitmqConfig = dict "spring" (dict "rabbitmq" (dict "host" (printf "%s-rabbitmq" .Release.Name) - "username" .Values.rabbitmq.auth.username ) "cloud" (dict "stream" (dict "bindings" (dict "default" (dict "group" "hawkbit") @@ -24,4 +23,13 @@ data: {{- $rabbitmqConfig = dict "spring" (dict "autoconfigure" (dict "exclude" "org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration")) -}} {{- end -}} {{- $authConfig := dict "hawkbit" (dict "security" (dict "user" (dict (.Values.auth.username) (dict "tenant" "DEFAULT" "roles" (list "TENANT_ADMIN"))))) -}} - {{- mergeOverwrite (deepCopy .Values.config.application) $rabbitmqConfig $authConfig | toYaml | nindent 4 }} + {{- $importConfig := dict "spring" (dict "config" (dict "import" (list "optional:file:/secret-config/application-user-credentials.yaml"))) -}} + {{- mergeOverwrite (deepCopy .Values.config.application) $rabbitmqConfig $authConfig $importConfig | toYaml | nindent 4 }} + application-mysql.yaml: |- + spring: + datasource: + url: {{ include "hawkbit.database.url" . | quote }} + application-postgresql.yaml: |- + spring: + datasource: + url: {{ include "hawkbit.database.url" . | quote }} diff --git a/charts/hawkbit/templates/deployment.yaml b/charts/hawkbit/templates/deployment.yaml index f29a5993..e3199f14 100644 --- a/charts/hawkbit/templates/deployment.yaml +++ b/charts/hawkbit/templates/deployment.yaml @@ -32,28 +32,22 @@ spec: env: - name: HAWKBIT_DB_MODE value: "migrate" - - name: "SPRING_DATASOURCE_URL" - value: {{ include "hawkbit.database.url" . | quote }} - - name: SPRING_DATASOURCE_USERNAME - {{- if include "hawkbit.database.secretUsernameKey" . }} - valueFrom: - secretKeyRef: - name: {{ include "hawkbit.database.secretName" . }} - key: {{ include "hawkbit.database.secretUsernameKey" . }} - {{- else }} - value: {{ include "hawkbit.database.user" . | quote }} - {{- end }} - - name: SPRING_DATASOURCE_PASSWORD - valueFrom: - secretKeyRef: - name: {{ include "hawkbit.database.secretName" . }} - key: {{ include "hawkbit.database.secretPasswordKey" . }} + - name: PROFILES + value: {{ include "hawkbit.spring.profiles" . | quote }} - name: AND_THEN value: "true" - {{- if .Values.extraVolumeMounts }} + envFrom: + - secretRef: + name: {{ include "hawkbit.dbCredentialsSecretName" . }} volumeMounts: + - name: configmap + mountPath: {{ .Values.configMap.mountPath }} + - name: secret-config + mountPath: /secret-config + readOnly: true + {{- if .Values.extraVolumeMounts }} {{- toYaml .Values.extraVolumeMounts | nindent 12 }} - {{- end }} + {{- end }} {{- with .Values.image.pullSecrets }} imagePullSecrets: {{- toYaml . | nindent 8 }} @@ -67,34 +61,6 @@ spec: value: {{ include "hawkbit.spring.profiles" . | quote }} - name: SPRING_FLYWAY_ENABLED value: "false" - - name: SPRING_DATASOURCE_USERNAME - {{- if include "hawkbit.database.secretUsernameKey" . }} - valueFrom: - secretKeyRef: - name: {{ include "hawkbit.database.secretName" . }} - key: {{ include "hawkbit.database.secretUsernameKey" . }} - {{- else }} - value: {{ include "hawkbit.database.user" . | quote }} - {{- end }} - - name: SPRING_DATASOURCE_PASSWORD - valueFrom: - secretKeyRef: - name: {{ include "hawkbit.database.secretName" . }} - key: {{ include "hawkbit.database.secretPasswordKey" . }} - - name: "SPRING_DATASOURCE_URL" - value: {{ include "hawkbit.database.url" . | quote }} - {{- if .Values.rabbitmq.enabled }} - - name: "SPRING_RABBITMQ_PASSWORD" - valueFrom: - secretKeyRef: - name: {{ include "rabbitmq.secretPasswordName" .Subcharts.rabbitmq }} - key: rabbitmq-password - {{- end }} - - name: {{ printf "HAWKBIT_SECURITY_USER_%s_PASSWORD" (.Values.auth.username | upper) }} - valueFrom: - secretKeyRef: - name: {{ include "hawkbit.secretName" . }} - key: hawkbit-password {{- if .Values.fileStorage.enabled }} - name: "org.eclipse.hawkbit.repository.file.path" value: {{ .Values.fileStorage.mountPath }} @@ -111,6 +77,13 @@ spec: # .Values.extraEnv of type {{kindOf .Values.extraEnv}} is ignored {{- end }} {{- end }} + envFrom: + - secretRef: + name: {{ include "hawkbit.dbCredentialsSecretName" . }} + {{- if .Values.rabbitmq.enabled }} + - secretRef: + name: {{ include "hawkbit.rabbitmqCredentialsSecretName" . }} + {{- end }} ports: - name: http containerPort: 8080 @@ -130,6 +103,9 @@ spec: volumeMounts: - name: configmap mountPath: {{ .Values.configMap.mountPath }} + - name: secret-config + mountPath: /secret-config + readOnly: true {{- if .Values.fileStorage.enabled }} - name: storage mountPath: {{ .Values.fileStorage.mountPath }} @@ -163,6 +139,14 @@ spec: - name: configmap configMap: name: {{ include "hawkbit.fullname" . }} + - name: secret-config + projected: + sources: + - secret: + name: {{ include "hawkbit.userCredentialsSecretName" . }} + items: + - key: application-user-credentials.yaml + path: application-user-credentials.yaml {{- if .Values.fileStorage.enabled }} - name: storage persistentVolumeClaim: diff --git a/charts/hawkbit/templates/secrets.yaml b/charts/hawkbit/templates/secrets.yaml index 9533fe60..0a695592 100644 --- a/charts/hawkbit/templates/secrets.yaml +++ b/charts/hawkbit/templates/secrets.yaml @@ -2,16 +2,54 @@ apiVersion: v1 kind: Secret metadata: - name: {{ template "hawkbit.fullname" . }} + name: {{ template "hawkbit.fullname" . }}-user labels: {{ include "hawkbit.labels" . | indent 4 }} type: Opaque -data: -{{- if .Values.config.secrets }} - hawkbit-dmf-password: {{ .Values.config.secrets.hawkbit.dmf.hono.password | b64enc | quote }} - hawkbit-password: {{ .Values.config.secrets.spring.securinty.user.password | b64enc | quote }} -{{- else }} - hawkbit-dmf-password: {{ .Values.auth.dmfPassword | b64enc | quote }} - hawkbit-password: {{ .Values.auth.password | b64enc | quote }} +stringData: + application-user-credentials.yaml: |- + hawkbit: + security: + user: + {{ .Values.auth.username }}: + password: {{ .Values.auth.password | quote }} +--- {{- end }} +{{- if and (not .Values.externalDatabase.existingSecret) (not .Values.mysql.enabled) .Values.externalDatabase.host }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "hawkbit.fullname" . }}-db + labels: +{{ include "hawkbit.labels" . | indent 4 }} +type: Opaque +stringData: + SPRING_DATASOURCE_USERNAME: {{ include "hawkbit.database.user" . | quote }} + SPRING_DATASOURCE_PASSWORD: {{ .Values.externalDatabase.password | quote }} +--- +{{- end }} +{{- if and (not .Values.externalDatabase.existingSecret) .Values.mysql.enabled }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "hawkbit.fullname" . }}-db + labels: +{{ include "hawkbit.labels" . | indent 4 }} +type: Opaque +stringData: + SPRING_DATASOURCE_USERNAME: "root" + SPRING_DATASOURCE_PASSWORD: {{ .Values.mysql.auth.rootPassword | default "" | quote }} +--- +{{- end }} +{{- if and .Values.rabbitmq.enabled (not .Values.rabbitmq.credentialsSecret) }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "hawkbit.fullname" . }}-rabbitmq + labels: +{{ include "hawkbit.labels" . | indent 4 }} +type: Opaque +stringData: + SPRING_RABBITMQ_USERNAME: {{ .Values.rabbitmq.auth.username | quote }} + SPRING_RABBITMQ_PASSWORD: {{ .Values.rabbitmq.auth.password | quote }} {{- end }} diff --git a/charts/hawkbit/values.yaml b/charts/hawkbit/values.yaml index 4b8a75ee..aa6bee02 100644 --- a/charts/hawkbit/values.yaml +++ b/charts/hawkbit/values.yaml @@ -21,7 +21,7 @@ image: # auth configuration auth: - # if set, the secret will be used to set the hawkbit user password + # if set, must contain key: application-user-credentials.yaml existingSecret: "" username: "admin" password: "{noop}admin" @@ -119,7 +119,7 @@ extraVolumes: [] extraVolumeMounts: [] configMap: - mountPath: "/config" + mountPath: "/app/config" spring: profiles: "mysql" @@ -139,10 +139,9 @@ externalDatabase: port: "" database: hawkbit user: "" + password: "" # used when existingSecret is not set url: "" # optional: override the full JDBC URL - existingSecret: "" - existingSecretPasswordKey: "" - existingSecretUsernameKey: "" + existingSecret: "" # must contain keys: SPRING_DATASOURCE_USERNAME, SPRING_DATASOURCE_PASSWORD ## ref: https://github.com/bitnami/charts/blob/master/bitnami/mysql/values.yaml mysql: @@ -164,6 +163,11 @@ mysql: ## ref: https://github.com/bitnami/charts/blob/master/bitnami/rabbitmq/values.yaml rabbitmq: + # hawkbit chart: if set, must contain keys SPRING_RABBITMQ_USERNAME and SPRING_RABBITMQ_PASSWORD; + # generated from rabbitmq.auth.username and rabbitmq.auth.password if not set + credentialsSecret: "" + # external RabbitMQ hostname (used when rabbitmq.enabled=false and microservices.enabled=true) + host: "" enabled: true persistence: enabled: true @@ -176,3 +180,47 @@ rabbitmq: password: hawkbit metrics: enabled: true + +## Microservices mode — deploy mgmt, ddi, dmf as separate pods instead of the monolith +microservices: + enabled: false + mgmt: + image: + repository: "hawkbit/hawkbit-mgmt-server" + tag: "0.10.0" + pullPolicy: IfNotPresent + replicaCount: 1 + resources: {} + ddi: + image: + repository: "hawkbit/hawkbit-ddi-server" + tag: "0.10.0" + pullPolicy: IfNotPresent + replicaCount: 1 + resources: {} + # Ingress paths routed to the DDI server (e.g., ["/DEFAULT/controller"]) + ingressPaths: [] + dmf: + image: + repository: "hawkbit/hawkbit-dmf-server" + tag: "0.10.0" + pullPolicy: IfNotPresent + replicaCount: 1 + resources: {} + +## hawkbitgui — optional Next.js management UI +gui: + enabled: false + image: + repository: "ghcr.io/joshua-clayton/hawkbitgui" + tag: "0.1.0" + pullPolicy: IfNotPresent + replicaCount: 1 + service: + port: 3000 + nextauth: + # NEXTAUTH_URL: full public URL of the GUI (e.g., https://hawkbit.example.com) + url: "http://localhost:3000" + # existingSecret must contain key: NEXTAUTH_SECRET + existingSecret: "" + resources: {} From 76ae05300227e3f9b5e28641aad11f46ca5cdde0 Mon Sep 17 00:00:00 2001 From: Joshua Clayton Date: Mon, 27 Apr 2026 13:29:15 -0600 Subject: [PATCH 4/4] feat: microservices and gui Split the images, and add a new optional hawkbitgui by the maintainer of swupdate Migrate away from bitnami charts and images to open alternatives due to bitnami pulling existing images as their business model changes, --- charts/hawkbit/Chart.yaml | 12 +- charts/hawkbit/templates/_helpers.tpl | 26 +-- charts/hawkbit/templates/configmap.yaml | 16 +- charts/hawkbit/templates/deployment.yaml | 4 +- charts/hawkbit/templates/gui-deployment.yaml | 73 ++++++++ charts/hawkbit/templates/gui-service.yaml | 20 +++ charts/hawkbit/templates/ingress.yaml | 58 ++++++- .../microservices/ddi-deployment.yaml | 139 ++++++++++++++++ .../templates/microservices/ddi-service.yaml | 20 +++ .../microservices/dmf-deployment.yaml | 110 ++++++++++++ .../microservices/mgmt-deployment.yaml | 156 ++++++++++++++++++ .../templates/microservices/mgmt-service.yaml | 20 +++ charts/hawkbit/templates/secrets.yaml | 8 +- charts/hawkbit/templates/service.yaml | 2 + charts/hawkbit/values.yaml | 33 ++-- 15 files changed, 647 insertions(+), 50 deletions(-) create mode 100644 charts/hawkbit/templates/gui-deployment.yaml create mode 100644 charts/hawkbit/templates/gui-service.yaml create mode 100644 charts/hawkbit/templates/microservices/ddi-deployment.yaml create mode 100644 charts/hawkbit/templates/microservices/ddi-service.yaml create mode 100644 charts/hawkbit/templates/microservices/dmf-deployment.yaml create mode 100644 charts/hawkbit/templates/microservices/mgmt-deployment.yaml create mode 100644 charts/hawkbit/templates/microservices/mgmt-service.yaml diff --git a/charts/hawkbit/Chart.yaml b/charts/hawkbit/Chart.yaml index 436acc55..b7608b86 100644 --- a/charts/hawkbit/Chart.yaml +++ b/charts/hawkbit/Chart.yaml @@ -32,11 +32,11 @@ maintainers: - name: ctron email: ctron@dentrassi.de dependencies: -- name: mysql - version: ^9.x - repository: "oci://registry-1.docker.io/bitnamicharts" - condition: mysql.enabled +- name: mariadb + version: ^0.x + repository: "oci://registry-1.docker.io/cloudpirates" + condition: mariadb.enabled - name: rabbitmq - version: ^10.x - repository: "oci://registry-1.docker.io/bitnamicharts" + version: ^0.x + repository: "oci://registry-1.docker.io/cloudpirates" condition: rabbitmq.enabled diff --git a/charts/hawkbit/templates/_helpers.tpl b/charts/hawkbit/templates/_helpers.tpl index 08ecb0be..ad69e41c 100644 --- a/charts/hawkbit/templates/_helpers.tpl +++ b/charts/hawkbit/templates/_helpers.tpl @@ -86,43 +86,43 @@ Return the secret with the Hawkbit credentials. {{- if .Values.rabbitmq.credentialsSecret -}} {{- .Values.rabbitmq.credentialsSecret -}} {{- else -}} - {{- printf "%s-rabbitmq" (include "hawkbit.fullname" .) -}} + {{- printf "%s-rabbitmq-creds" (include "hawkbit.fullname" .) -}} {{- end -}} {{- end -}} {{/* -Database helpers — switch between externalDatabase and the bundled mysql subchart. +Database helpers — switch between externalDatabase and the bundled mariadb subchart. */}} {{- define "hawkbit.database.url" -}} {{- if .Values.externalDatabase.url -}} {{- .Values.externalDatabase.url -}} - {{- else if and .Values.externalDatabase.host (eq (.Values.externalDatabase.type | default "mysql") "postgresql") -}} + {{- else if and .Values.externalDatabase.host (eq (.Values.externalDatabase.type | default "mariadb") "postgresql") -}} {{- printf "jdbc:postgresql://%s:%v/%s" .Values.externalDatabase.host (.Values.externalDatabase.port | default 5432) (.Values.externalDatabase.database | default "hawkbit") -}} {{- else if .Values.externalDatabase.host -}} {{- printf "jdbc:mariadb://%s:%v/%s" .Values.externalDatabase.host (.Values.externalDatabase.port | default 3306) (.Values.externalDatabase.database | default "hawkbit") -}} - {{- else if .Values.mysql.enabled -}} - {{- printf "jdbc:mariadb://%s-mysql:3306/%s" (include "hawkbit.fullname" .) .Values.mysql.auth.database -}} + {{- else if .Values.mariadb.enabled -}} + {{- printf "jdbc:mariadb://%s-mariadb:3306/%s" (include "hawkbit.fullname" .) .Values.mariadb.auth.database -}} {{- else -}} - {{- fail "Either externalDatabase.host or mysql.enabled must be set" -}} + {{- fail "Either externalDatabase.host or mariadb.enabled must be set" -}} {{- end -}} {{- end -}} {{- define "hawkbit.database.user" -}} {{- if .Values.externalDatabase.user -}} {{- .Values.externalDatabase.user -}} - {{- else if .Values.mysql.enabled -}} + {{- else if .Values.mariadb.enabled -}} {{- "root" -}} {{- else -}} - {{- fail "externalDatabase.user is required when mysql.enabled=false" -}} + {{- fail "externalDatabase.user is required when mariadb.enabled=false" -}} {{- end -}} {{- end -}} {{- define "hawkbit.database.secretName" -}} {{- if .Values.externalDatabase.existingSecret -}} {{- .Values.externalDatabase.existingSecret -}} - {{- else if .Values.mysql.enabled -}} - {{- include "mysql.secretName" .Subcharts.mysql -}} + {{- else if .Values.mariadb.enabled -}} + {{- include "mariadb.secretName" .Subcharts.mariadb -}} {{- else -}} {{- printf "%s-external-db" (include "hawkbit.fullname" .) -}} {{- end -}} @@ -131,8 +131,8 @@ Database helpers — switch between externalDatabase and the bundled mysql subch {{- define "hawkbit.database.secretPasswordKey" -}} {{- if .Values.externalDatabase.existingSecretPasswordKey -}} {{- .Values.externalDatabase.existingSecretPasswordKey -}} - {{- else if .Values.mysql.enabled -}} - {{- "mysql-root-password" -}} + {{- else if .Values.mariadb.enabled -}} + {{- "mariadb-root-password" -}} {{- else -}} {{- "password" -}} {{- end -}} @@ -147,7 +147,7 @@ Database helpers — switch between externalDatabase and the bundled mysql subch {{- define "hawkbit.spring.profiles" -}} {{- if .Values.spring.profiles -}} {{- .Values.spring.profiles -}} - {{- else if eq (.Values.externalDatabase.type | default "mysql") "postgresql" -}} + {{- else if eq (.Values.externalDatabase.type | default "mariadb") "postgresql" -}} {{- "postgresql" -}} {{- else -}} {{- "mysql" -}} diff --git a/charts/hawkbit/templates/configmap.yaml b/charts/hawkbit/templates/configmap.yaml index 0ceb8be2..e1f488f4 100644 --- a/charts/hawkbit/templates/configmap.yaml +++ b/charts/hawkbit/templates/configmap.yaml @@ -11,6 +11,7 @@ data: {{- $rabbitmqConfig = dict "spring" (dict "rabbitmq" (dict "host" (printf "%s-rabbitmq" .Release.Name) + "listener" (dict "simple" (dict "missing-queues-fatal" false)) ) "cloud" (dict "stream" (dict "bindings" (dict "default" (dict "group" "hawkbit") @@ -19,7 +20,20 @@ data: "device-deleted" (dict "destination" "device-registry.device-deleted") ))) ) -}} - {{- else -}} + {{- else if .Values.rabbitmq.host -}} + {{- $rabbitmqConfig = dict "spring" (dict + "rabbitmq" (dict + "host" .Values.rabbitmq.host + "listener" (dict "simple" (dict "missing-queues-fatal" false)) + ) + "cloud" (dict "stream" (dict "bindings" (dict + "default" (dict "group" "hawkbit") + "device-created" (dict "destination" "device-registry.device-created") + "device-updated" (dict "destination" "device-registry.device-updated") + "device-deleted" (dict "destination" "device-registry.device-deleted") + ))) + ) -}} + {{- else if not .Values.microservices.enabled -}} {{- $rabbitmqConfig = dict "spring" (dict "autoconfigure" (dict "exclude" "org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration")) -}} {{- end -}} {{- $authConfig := dict "hawkbit" (dict "security" (dict "user" (dict (.Values.auth.username) (dict "tenant" "DEFAULT" "roles" (list "TENANT_ADMIN"))))) -}} diff --git a/charts/hawkbit/templates/deployment.yaml b/charts/hawkbit/templates/deployment.yaml index e3199f14..1200387c 100644 --- a/charts/hawkbit/templates/deployment.yaml +++ b/charts/hawkbit/templates/deployment.yaml @@ -1,3 +1,4 @@ +{{- if not .Values.microservices.enabled }} apiVersion: apps/v1 kind: Deployment metadata: @@ -62,7 +63,7 @@ spec: - name: SPRING_FLYWAY_ENABLED value: "false" {{- if .Values.fileStorage.enabled }} - - name: "org.eclipse.hawkbit.repository.file.path" + - name: ORG_ECLIPSE_HAWKBIT_ARTIFACT_FS_PATH value: {{ .Values.fileStorage.mountPath }} {{- end }} {{- if .Values.extraEnv }} @@ -155,3 +156,4 @@ spec: {{- if .Values.extraVolumes }} {{- toYaml .Values.extraVolumes | nindent 8 }} {{- end }} +{{- end }} diff --git a/charts/hawkbit/templates/gui-deployment.yaml b/charts/hawkbit/templates/gui-deployment.yaml new file mode 100644 index 00000000..06b3b9ff --- /dev/null +++ b/charts/hawkbit/templates/gui-deployment.yaml @@ -0,0 +1,73 @@ +{{- if .Values.gui.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "hawkbit.fullname" . }}-gui + labels: +{{ include "hawkbit.labels" . | indent 4 }} + app.kubernetes.io/component: gui +spec: + replicas: {{ .Values.gui.replicaCount }} + selector: + matchLabels: + app.kubernetes.io/name: {{ include "hawkbit.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: gui + template: + metadata: + labels: + app.kubernetes.io/name: {{ include "hawkbit.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: gui + {{- with .Values.podTemplate.annotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.image.pullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: hawkbitgui + image: "{{ .Values.gui.image.repository }}:{{ .Values.gui.image.tag }}" + imagePullPolicy: {{ .Values.gui.image.pullPolicy }} + env: + - name: NEXTAUTH_URL + value: {{ .Values.gui.nextauth.url | quote }} + - name: NEXTAUTH_SECRET + valueFrom: + secretKeyRef: + name: {{ .Values.gui.nextauth.existingSecret }} + key: NEXTAUTH_SECRET + ports: + - name: http + containerPort: 3000 + protocol: TCP + livenessProbe: + httpGet: + path: / + port: http + initialDelaySeconds: 30 + timeoutSeconds: 5 + readinessProbe: + httpGet: + path: / + port: http + initialDelaySeconds: 10 + timeoutSeconds: 5 + resources: +{{ toYaml .Values.gui.resources | indent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} +{{- end }} diff --git a/charts/hawkbit/templates/gui-service.yaml b/charts/hawkbit/templates/gui-service.yaml new file mode 100644 index 00000000..fd0c9c2a --- /dev/null +++ b/charts/hawkbit/templates/gui-service.yaml @@ -0,0 +1,20 @@ +{{- if .Values.gui.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "hawkbit.fullname" . }}-gui + labels: +{{ include "hawkbit.labels" . | indent 4 }} + app.kubernetes.io/component: gui +spec: + type: ClusterIP + ports: + - port: {{ .Values.gui.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + app.kubernetes.io/name: {{ include "hawkbit.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: gui +{{- end }} diff --git a/charts/hawkbit/templates/ingress.yaml b/charts/hawkbit/templates/ingress.yaml index d024cc1c..a0af8f76 100644 --- a/charts/hawkbit/templates/ingress.yaml +++ b/charts/hawkbit/templates/ingress.yaml @@ -23,27 +23,69 @@ spec: {{- end }} {{- end }} {{- if eq $apiVersion "networking.k8s.io/v1" }} - ingressClassName: {{ .Values.ingress.ingressClassName }} + ingressClassName: {{ .Values.ingress.ingressClassName }} {{- end }} rules: {{- range .Values.ingress.hosts }} - host: {{ .host | quote }} http: paths: - {{- range .paths }} + {{- if $.Values.microservices.enabled }} + - path: /rest + pathType: Prefix + backend: + service: + name: {{ $fullName }}-mgmt + port: + name: http + {{- range $.Values.microservices.ddi.ingressPaths }} + - path: {{ . }} + pathType: Prefix + backend: + service: + name: {{ $fullName }}-ddi + port: + name: http + {{- end }} + {{- else }} + {{- if $.Values.gui.enabled }} + {{- /* monolith + gui: explicitly route api paths to monolith */}} + - path: /rest + pathType: Prefix + backend: + service: + name: {{ $fullName }} + port: + name: http + {{- range $.Values.microservices.ddi.ingressPaths }} + - path: {{ . }} + pathType: Prefix + backend: + service: + name: {{ $fullName }} + port: + name: http + {{- end }} + {{- else }} + {{- range .paths }} - path: {{ . }} - {{- if eq $apiVersion "networking.k8s.io/v1" }} pathType: Prefix backend: service: name: {{ $fullName }} port: name: http - {{- else }} + {{- end }} + {{- end }} + {{- end }} + {{- if $.Values.gui.enabled }} + - path: / + pathType: Prefix backend: - serviceName: {{ $fullName }} - servicePort: http - {{- end }} - {{- end }} + service: + name: {{ $fullName }}-gui + port: + name: http + {{- end }} {{- end }} {{- end }} diff --git a/charts/hawkbit/templates/microservices/ddi-deployment.yaml b/charts/hawkbit/templates/microservices/ddi-deployment.yaml new file mode 100644 index 00000000..3f4c58e9 --- /dev/null +++ b/charts/hawkbit/templates/microservices/ddi-deployment.yaml @@ -0,0 +1,139 @@ +{{- if .Values.microservices.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "hawkbit.fullname" . }}-ddi + labels: +{{ include "hawkbit.labels" . | indent 4 }} + app.kubernetes.io/component: ddi +spec: + replicas: {{ .Values.microservices.ddi.replicaCount }} + strategy: + type: Recreate + selector: + matchLabels: + app.kubernetes.io/name: {{ include "hawkbit.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: ddi + template: + metadata: + labels: + app.kubernetes.io/name: {{ include "hawkbit.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: ddi + annotations: + checksum/config: {{ include (print .Template.BasePath "/secrets.yaml") . | sha256sum }} + {{- with .Values.podTemplate.annotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + initContainers: + - name: hawkbit-init + image: "{{ .Values.image.initContainer }}:{{ .Values.microservices.ddi.image.tag }}" + imagePullPolicy: {{ .Values.microservices.ddi.image.pullPolicy }} + env: + - name: HAWKBIT_DB_MODE + value: "migrate" + - name: PROFILES + value: {{ include "hawkbit.spring.profiles" . | quote }} + - name: AND_THEN + value: "true" + envFrom: + - secretRef: + name: {{ include "hawkbit.dbCredentialsSecretName" . }} + volumeMounts: + - name: configmap + mountPath: {{ .Values.configMap.mountPath }} + - name: secret-config + mountPath: /secret-config + readOnly: true + containers: + - name: hawkbit-ddi + image: "{{ .Values.microservices.ddi.image.repository }}:{{ .Values.microservices.ddi.image.tag }}" + imagePullPolicy: {{ .Values.microservices.ddi.image.pullPolicy }} + env: + - name: PROFILES + value: {{ include "hawkbit.spring.profiles" . | quote }} + - name: SPRING_FLYWAY_ENABLED + value: "false" + {{- if .Values.fileStorage.enabled }} + - name: ORG_ECLIPSE_HAWKBIT_ARTIFACT_FS_PATH + value: {{ .Values.fileStorage.mountPath }} + {{- end }} + envFrom: + - secretRef: + name: {{ include "hawkbit.dbCredentialsSecretName" . }} + - secretRef: + name: {{ include "hawkbit.rabbitmqCredentialsSecretName" . }} + ports: + - name: http + containerPort: 8081 + protocol: TCP + livenessProbe: + httpGet: + path: /actuator/health + port: http + initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }} + timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }} + readinessProbe: + httpGet: + path: /actuator/health + port: http + initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} + timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} + volumeMounts: + - name: configmap + mountPath: {{ .Values.configMap.mountPath }} + {{- if .Values.fileStorage.enabled }} + - name: storage + mountPath: {{ .Values.fileStorage.mountPath }} + {{- end }} + - name: secret-config + mountPath: /secret-config + readOnly: true + {{- if .Values.extraVolumeMounts }} + {{- toYaml .Values.extraVolumeMounts | nindent 12 }} + {{- end }} + resources: +{{ toYaml .Values.microservices.ddi.resources | indent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if .Values.securityContext.enabled }} + securityContext: + fsGroup: {{ .Values.securityContext.fsGroup }} + runAsUser: {{ .Values.securityContext.runAsUser }} + {{- if .Values.securityContext.extra }} + {{- toYaml .Values.securityContext.extra | nindent 8 }} + {{- end }} + {{- end }} + volumes: + - name: configmap + configMap: + name: {{ include "hawkbit.fullname" . }} + {{- if .Values.fileStorage.enabled }} + - name: storage + persistentVolumeClaim: + claimName: {{ include "hawkbit.fullname" . }}-data + {{- end }} + - name: secret-config + projected: + sources: + - secret: + name: {{ include "hawkbit.userCredentialsSecretName" . }} + items: + - key: application-user-credentials.yaml + path: application-user-credentials.yaml + {{- if .Values.extraVolumes }} + {{- toYaml .Values.extraVolumes | nindent 8 }} + {{- end }} +{{- end }} diff --git a/charts/hawkbit/templates/microservices/ddi-service.yaml b/charts/hawkbit/templates/microservices/ddi-service.yaml new file mode 100644 index 00000000..eb234938 --- /dev/null +++ b/charts/hawkbit/templates/microservices/ddi-service.yaml @@ -0,0 +1,20 @@ +{{- if .Values.microservices.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "hawkbit.fullname" . }}-ddi + labels: +{{ include "hawkbit.labels" . | indent 4 }} + app.kubernetes.io/component: ddi +spec: + type: ClusterIP + ports: + - port: 8081 + targetPort: http + protocol: TCP + name: http + selector: + app.kubernetes.io/name: {{ include "hawkbit.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: ddi +{{- end }} diff --git a/charts/hawkbit/templates/microservices/dmf-deployment.yaml b/charts/hawkbit/templates/microservices/dmf-deployment.yaml new file mode 100644 index 00000000..b53df7f3 --- /dev/null +++ b/charts/hawkbit/templates/microservices/dmf-deployment.yaml @@ -0,0 +1,110 @@ +{{- if .Values.microservices.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "hawkbit.fullname" . }}-dmf + labels: +{{ include "hawkbit.labels" . | indent 4 }} + app.kubernetes.io/component: dmf +spec: + replicas: {{ .Values.microservices.dmf.replicaCount }} + strategy: + type: Recreate + selector: + matchLabels: + app.kubernetes.io/name: {{ include "hawkbit.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: dmf + template: + metadata: + labels: + app.kubernetes.io/name: {{ include "hawkbit.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: dmf + annotations: + checksum/config: {{ include (print .Template.BasePath "/secrets.yaml") . | sha256sum }} + {{- with .Values.podTemplate.annotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + initContainers: + - name: hawkbit-init + image: "{{ .Values.image.initContainer }}:{{ .Values.microservices.dmf.image.tag }}" + imagePullPolicy: {{ .Values.microservices.dmf.image.pullPolicy }} + env: + - name: HAWKBIT_DB_MODE + value: "migrate" + - name: PROFILES + value: {{ include "hawkbit.spring.profiles" . | quote }} + - name: AND_THEN + value: "true" + envFrom: + - secretRef: + name: {{ include "hawkbit.dbCredentialsSecretName" . }} + volumeMounts: + - name: configmap + mountPath: {{ .Values.configMap.mountPath }} + - name: secret-config + mountPath: /secret-config + readOnly: true + containers: + - name: hawkbit-dmf + image: "{{ .Values.microservices.dmf.image.repository }}:{{ .Values.microservices.dmf.image.tag }}" + imagePullPolicy: {{ .Values.microservices.dmf.image.pullPolicy }} + env: + - name: PROFILES + value: {{ include "hawkbit.spring.profiles" . | quote }} + - name: SPRING_FLYWAY_ENABLED + value: "false" + envFrom: + - secretRef: + name: {{ include "hawkbit.dbCredentialsSecretName" . }} + - secretRef: + name: {{ include "hawkbit.rabbitmqCredentialsSecretName" . }} + volumeMounts: + - name: configmap + mountPath: {{ .Values.configMap.mountPath }} + - name: secret-config + mountPath: /secret-config + readOnly: true + {{- if .Values.extraVolumeMounts }} + {{- toYaml .Values.extraVolumeMounts | nindent 12 }} + {{- end }} + resources: +{{ toYaml .Values.microservices.dmf.resources | indent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if .Values.securityContext.enabled }} + securityContext: + fsGroup: {{ .Values.securityContext.fsGroup }} + runAsUser: {{ .Values.securityContext.runAsUser }} + {{- if .Values.securityContext.extra }} + {{- toYaml .Values.securityContext.extra | nindent 8 }} + {{- end }} + {{- end }} + volumes: + - name: configmap + configMap: + name: {{ include "hawkbit.fullname" . }} + - name: secret-config + projected: + sources: + - secret: + name: {{ include "hawkbit.userCredentialsSecretName" . }} + items: + - key: application-user-credentials.yaml + path: application-user-credentials.yaml + {{- if .Values.extraVolumes }} + {{- toYaml .Values.extraVolumes | nindent 8 }} + {{- end }} +{{- end }} diff --git a/charts/hawkbit/templates/microservices/mgmt-deployment.yaml b/charts/hawkbit/templates/microservices/mgmt-deployment.yaml new file mode 100644 index 00000000..501d39d2 --- /dev/null +++ b/charts/hawkbit/templates/microservices/mgmt-deployment.yaml @@ -0,0 +1,156 @@ +{{- if .Values.microservices.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "hawkbit.fullname" . }}-mgmt + labels: +{{ include "hawkbit.labels" . | indent 4 }} + app.kubernetes.io/component: mgmt +spec: + replicas: {{ .Values.microservices.mgmt.replicaCount }} + strategy: + type: Recreate + selector: + matchLabels: + app.kubernetes.io/name: {{ include "hawkbit.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: mgmt + template: + metadata: + labels: + app.kubernetes.io/name: {{ include "hawkbit.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: mgmt + annotations: + checksum/config: {{ include (print .Template.BasePath "/secrets.yaml") . | sha256sum }} + {{- with .Values.podTemplate.annotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + initContainers: + - name: hawkbit-init + image: "{{ .Values.image.initContainer }}:{{ .Values.microservices.mgmt.image.tag }}" + imagePullPolicy: {{ .Values.microservices.mgmt.image.pullPolicy }} + env: + - name: HAWKBIT_DB_MODE + value: "migrate" + - name: PROFILES + value: {{ include "hawkbit.spring.profiles" . | quote }} + - name: AND_THEN + value: "true" + envFrom: + - secretRef: + name: {{ include "hawkbit.dbCredentialsSecretName" . }} + volumeMounts: + - name: configmap + mountPath: {{ .Values.configMap.mountPath }} + - name: secret-config + mountPath: /secret-config + readOnly: true + {{- if .Values.extraVolumeMounts }} + {{- toYaml .Values.extraVolumeMounts | nindent 12 }} + {{- end }} + {{- with .Values.microservices.mgmt.image.pullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: hawkbit-mgmt + image: "{{ .Values.microservices.mgmt.image.repository }}:{{ .Values.microservices.mgmt.image.tag }}" + imagePullPolicy: {{ .Values.microservices.mgmt.image.pullPolicy }} + env: + - name: PROFILES + value: {{ include "hawkbit.spring.profiles" . | quote }} + - name: SPRING_FLYWAY_ENABLED + value: "false" + {{- if .Values.fileStorage.enabled }} + - name: ORG_ECLIPSE_HAWKBIT_ARTIFACT_FS_PATH + value: {{ .Values.fileStorage.mountPath }} + {{- end }} + {{- if .Values.extraEnv }} + {{- if kindIs "slice" .Values.extraEnv }} + {{- toYaml .Values.extraEnv | nindent 12 }} + {{- else if kindIs "map" .Values.extraEnv }} + {{- range $key, $value := .Values.extraEnv }} + - name: "{{ $key }}" + value: "{{ $value }}" + {{- end }} + {{- end }} + {{- end }} + envFrom: + - secretRef: + name: {{ include "hawkbit.dbCredentialsSecretName" . }} + - secretRef: + name: {{ include "hawkbit.rabbitmqCredentialsSecretName" . }} + ports: + - name: http + containerPort: 8080 + protocol: TCP + livenessProbe: + httpGet: + path: /actuator/health + port: http + initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }} + timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }} + readinessProbe: + httpGet: + path: /actuator/health + port: http + initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} + timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} + volumeMounts: + - name: configmap + mountPath: {{ .Values.configMap.mountPath }} + - name: secret-config + mountPath: /secret-config + readOnly: true + {{- if .Values.fileStorage.enabled }} + - name: storage + mountPath: {{ .Values.fileStorage.mountPath }} + {{- end }} + {{- if .Values.extraVolumeMounts }} + {{- toYaml .Values.extraVolumeMounts | nindent 12 }} + {{- end }} + resources: +{{ toYaml .Values.microservices.mgmt.resources | indent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if .Values.securityContext.enabled }} + securityContext: + fsGroup: {{ .Values.securityContext.fsGroup }} + runAsUser: {{ .Values.securityContext.runAsUser }} + {{- if .Values.securityContext.extra }} + {{- toYaml .Values.securityContext.extra | nindent 8 }} + {{- end }} + {{- end }} + volumes: + - name: configmap + configMap: + name: {{ include "hawkbit.fullname" . }} + - name: secret-config + projected: + sources: + - secret: + name: {{ include "hawkbit.userCredentialsSecretName" . }} + items: + - key: application-user-credentials.yaml + path: application-user-credentials.yaml + {{- if .Values.fileStorage.enabled }} + - name: storage + persistentVolumeClaim: + claimName: {{ include "hawkbit.fullname" . }}-data + {{- end }} + {{- if .Values.extraVolumes }} + {{- toYaml .Values.extraVolumes | nindent 8 }} + {{- end }} +{{- end }} diff --git a/charts/hawkbit/templates/microservices/mgmt-service.yaml b/charts/hawkbit/templates/microservices/mgmt-service.yaml new file mode 100644 index 00000000..a801b569 --- /dev/null +++ b/charts/hawkbit/templates/microservices/mgmt-service.yaml @@ -0,0 +1,20 @@ +{{- if .Values.microservices.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "hawkbit.fullname" . }}-mgmt + labels: +{{ include "hawkbit.labels" . | indent 4 }} + app.kubernetes.io/component: mgmt +spec: + type: ClusterIP + ports: + - port: 8080 + targetPort: http + protocol: TCP + name: http + selector: + app.kubernetes.io/name: {{ include "hawkbit.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: mgmt +{{- end }} diff --git a/charts/hawkbit/templates/secrets.yaml b/charts/hawkbit/templates/secrets.yaml index 0a695592..ae58671e 100644 --- a/charts/hawkbit/templates/secrets.yaml +++ b/charts/hawkbit/templates/secrets.yaml @@ -15,7 +15,7 @@ stringData: password: {{ .Values.auth.password | quote }} --- {{- end }} -{{- if and (not .Values.externalDatabase.existingSecret) (not .Values.mysql.enabled) .Values.externalDatabase.host }} +{{- if and (not .Values.externalDatabase.existingSecret) (not .Values.mariadb.enabled) .Values.externalDatabase.host }} apiVersion: v1 kind: Secret metadata: @@ -28,7 +28,7 @@ stringData: SPRING_DATASOURCE_PASSWORD: {{ .Values.externalDatabase.password | quote }} --- {{- end }} -{{- if and (not .Values.externalDatabase.existingSecret) .Values.mysql.enabled }} +{{- if and (not .Values.externalDatabase.existingSecret) .Values.mariadb.enabled }} apiVersion: v1 kind: Secret metadata: @@ -38,14 +38,14 @@ metadata: type: Opaque stringData: SPRING_DATASOURCE_USERNAME: "root" - SPRING_DATASOURCE_PASSWORD: {{ .Values.mysql.auth.rootPassword | default "" | quote }} + SPRING_DATASOURCE_PASSWORD: {{ .Values.mariadb.auth.rootPassword | default "" | quote }} --- {{- end }} {{- if and .Values.rabbitmq.enabled (not .Values.rabbitmq.credentialsSecret) }} apiVersion: v1 kind: Secret metadata: - name: {{ template "hawkbit.fullname" . }}-rabbitmq + name: {{ template "hawkbit.fullname" . }}-rabbitmq-creds labels: {{ include "hawkbit.labels" . | indent 4 }} type: Opaque diff --git a/charts/hawkbit/templates/service.yaml b/charts/hawkbit/templates/service.yaml index db234663..919987ca 100644 --- a/charts/hawkbit/templates/service.yaml +++ b/charts/hawkbit/templates/service.yaml @@ -1,3 +1,4 @@ +{{- if not .Values.microservices.enabled }} apiVersion: v1 kind: Service metadata: @@ -18,3 +19,4 @@ spec: selector: app.kubernetes.io/name: {{ include "hawkbit.name" . }} app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} diff --git a/charts/hawkbit/values.yaml b/charts/hawkbit/values.yaml index aa6bee02..7e05ca60 100644 --- a/charts/hawkbit/values.yaml +++ b/charts/hawkbit/values.yaml @@ -131,10 +131,10 @@ config: hawkbit: ## dependency charts config -## External database configuration (used when mysql.enabled=false). -## type: mysql (default) or postgresql +## External database configuration (used when mariadb.enabled=false). +## type: mariadb (default) or postgresql externalDatabase: - type: mysql + type: mariadb host: "" port: "" database: hawkbit @@ -143,25 +143,24 @@ externalDatabase: url: "" # optional: override the full JDBC URL existingSecret: "" # must contain keys: SPRING_DATASOURCE_USERNAME, SPRING_DATASOURCE_PASSWORD -## ref: https://github.com/bitnami/charts/blob/master/bitnami/mysql/values.yaml -mysql: +## ref: https://github.com/CloudPirates-io/helm-charts/tree/main/charts/mariadb +mariadb: enabled: true - primary: - persistence: - enabled: true - volumePermissions: + persistence: enabled: true - architecture: standalone auth: - # The secret has to contain the keys mysql-root-password, mysql-replication-password and mysql-password existingSecret: "" + rootPassword: "" + database: hawkbit username: hawkbit password: hawkbit - database: hawkbit + secretKeys: + rootPasswordKey: mariadb-root-password + userPasswordKey: mariadb-password metrics: enabled: true -## ref: https://github.com/bitnami/charts/blob/master/bitnami/rabbitmq/values.yaml +## ref: https://github.com/CloudPirates-io/helm-charts/tree/main/charts/rabbitmq rabbitmq: # hawkbit chart: if set, must contain keys SPRING_RABBITMQ_USERNAME and SPRING_RABBITMQ_PASSWORD; # generated from rabbitmq.auth.username and rabbitmq.auth.password if not set @@ -171,13 +170,13 @@ rabbitmq: enabled: true persistence: enabled: true - volumePermissions: - enabled: true auth: - existingPasswordSecret: "" - existingSecretPasswordKey: rabbitmq-password + existingSecret: "" + existingPasswordKey: "rabbitmq-password" + existingErlangCookieKey: "rabbitmq-erlang-cookie" username: hawkbit password: hawkbit + erlangCookie: "" metrics: enabled: true