diff --git a/mantisbt/index.yaml b/mantisbt/index.yaml new file mode 100644 index 0000000..960f63a --- /dev/null +++ b/mantisbt/index.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +entries: + mantisbt: + - apiVersion: v2 + appVersion: 2.27.0 + created: "2025-12-19T08:44:25.766178+01:00" + dependencies: + - condition: mariadb.enabled + name: mariadb + repository: https://charts.bitnami.com/bitnami + version: 19.*.* + description: MantisBT Bug Tracker - A Helm chart for Kubernetes + digest: 120476f60a1fb4d84ce06e50e4c57f75722e9fca06ac83fb353724ae0bb0b915 + name: mantisbt + type: application + urls: + - https://gitea.innovation-hub-niedersachsen.de/innohub/charts/raw/main/mantisbt/mantisbt-0.4.3.tgz + version: 0.4.3 +generated: "2025-12-19T08:44:25.763065+01:00" diff --git a/mantisbt/mantisbt/Chart.yaml b/mantisbt/mantisbt/Chart.yaml new file mode 100644 index 0000000..a983980 --- /dev/null +++ b/mantisbt/mantisbt/Chart.yaml @@ -0,0 +1,12 @@ +apiVersion: v2 +name: mantisbt +description: MantisBT Bug Tracker - A Helm chart for Kubernetes +type: application +version: "0.4.3" +appVersion: "2.27.0" + +dependencies: + - name: mariadb + version: "19.*.*" + repository: "https://charts.bitnami.com/bitnami" + condition: mariadb.enabled diff --git a/mantisbt/mantisbt/charts/mariadb-19.1.2.tgz b/mantisbt/mantisbt/charts/mariadb-19.1.2.tgz new file mode 100644 index 0000000..6fa352a Binary files /dev/null and b/mantisbt/mantisbt/charts/mariadb-19.1.2.tgz differ diff --git a/mantisbt/mantisbt/templates/_helpers.tpl b/mantisbt/mantisbt/templates/_helpers.tpl new file mode 100644 index 0000000..defe835 --- /dev/null +++ b/mantisbt/mantisbt/templates/_helpers.tpl @@ -0,0 +1,117 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "mantisbt.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "mantisbt.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "mantisbt.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "mantisbt.labels" -}} +helm.sh/chart: {{ include "mantisbt.chart" . }} +{{ include "mantisbt.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "mantisbt.selectorLabels" -}} +app.kubernetes.io/name: {{ include "mantisbt.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "mantisbt.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "mantisbt.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* +Create a default fully qualified database name. +*/}} +{{- define "mantisbt.databaseHost" -}} +{{- if .Values.mariadb.enabled }} +{{- printf "%s-mariadb" (include "mantisbt.fullname" .) }} +{{- else }} +{{- .Values.externalDatabase.host }} +{{- end }} +{{- end }} + +{{/* +Get database port +*/}} +{{- define "mantisbt.databasePort" -}} +{{- if .Values.mariadb.enabled }} +{{- printf "3306" }} +{{- else }} +{{- .Values.externalDatabase.port | default "3306" }} +{{- end }} +{{- end }} + +{{/* +Get database name +*/}} +{{- define "mantisbt.databaseName" -}} +{{- if .Values.mariadb.enabled }} +{{- .Values.mariadb.auth.database }} +{{- else }} +{{- .Values.externalDatabase.database }} +{{- end }} +{{- end }} + +{{/* +Get database user +*/}} +{{- define "mantisbt.databaseUser" -}} +{{- if .Values.mariadb.enabled }} +{{- .Values.mariadb.auth.username }} +{{- else }} +{{- .Values.externalDatabase.username }} +{{- end }} +{{- end }} + +{{/* +Get database password +*/}} +{{- define "mantisbt.databasePassword" -}} +{{- if .Values.mariadb.enabled }} +{{- .Values.mariadb.auth.password }} +{{- else }} +{{- .Values.externalDatabase.password }} +{{- end }} +{{- end }} diff --git a/mantisbt/mantisbt/templates/deployment.yaml b/mantisbt/mantisbt/templates/deployment.yaml new file mode 100644 index 0000000..01ed0ef --- /dev/null +++ b/mantisbt/mantisbt/templates/deployment.yaml @@ -0,0 +1,158 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "mantisbt.fullname" . }} + labels: + app: {{ template "mantisbt.name" . }} + chart: {{ template "mantisbt.chart" . }} + component: mantisbt + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + {{- if .Values.deploymentLabels }} + {{- toYaml .Values.deploymentLabels | nindent 4 }} + {{- end }} +spec: + strategy: + {{ toYaml .Values.updateStrategy | nindent 4 }} + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: {{ template "mantisbt.name" . }} + component: mantisbt + release: {{ .Release.Name }} + template: + metadata: + annotations: + checksum/secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }} + labels: + app: {{ template "mantisbt.name" . }} + component: mantisbt + release: {{ .Release.Name }} + {{- if .Values.podLabels }} + {{- toYaml .Values.podLabels | nindent 8 }} + {{- end }} + spec: + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + serviceAccountName: {{ template "mantisbt.serviceAccountName" . }} + initContainers: + - name: wait-for-db + image: busybox:1.36 + command: + - sh + - -c + - | + echo "Waiting for database at {{ include "mantisbt.databaseHost" . }}:{{ include "mantisbt.databasePort" . }}..." + until nc -z {{ include "mantisbt.databaseHost" . }} {{ include "mantisbt.databasePort" . }}; do + echo "Database not ready, waiting..." + sleep 3 + done + echo "Database is ready!" + sleep 5 + - name: fix-permissions + image: busybox:1.36 + command: + - sh + - -c + - | + echo "Fixing permissions on config and uploads directories..." + # www-data has UID 33 in Debian-based images + chown -R 33:33 /var/www/html/config + chown -R 33:33 /var/www/html/uploads + chmod -R 755 /var/www/html/config + chmod -R 755 /var/www/html/uploads + echo "Permissions fixed:" + ls -la /var/www/html/config + ls -la /var/www/html/uploads + volumeMounts: + - name: config + mountPath: /var/www/html/config + {{- if .Values.persistence.enabled }} + - name: uploads + mountPath: /var/www/html/uploads + {{- end }} + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + terminationMessagePolicy: FallbackToLogsOnError + ports: + - name: http + containerPort: 80 + env: + # xlrl/mantisbt uses MANTIS_TIMEZONE and MANTIS_ENABLE_ADMIN + - name: MANTIS_TIMEZONE + value: {{ .Values.mantisbt.timezone | default "Europe/Berlin" | quote }} + - name: MANTIS_ENABLE_ADMIN + value: {{ .Values.mantisbt.enableAdmin | default "1" | quote }} + # Master salt from secret - keeps crypto keys stable across deployments + - name: MASTER_SALT + valueFrom: + secretKeyRef: + name: {{ template "mantisbt.fullname" . }}-secret + key: master-salt + {{- range $key := .Values.env }} + {{- if .value }} + - name: {{ .name }} + value: {{ .value | quote }} + {{- end }} + {{- end }} + {{- range $key := .Values.secretEnv }} + - name: {{ .name }} + valueFrom: + secretKeyRef: + name: {{ template "mantisbt.fullname" $ }}-secret + key: {{ .name }} + {{- end }} + envFrom: + {{- with .Values.extraEnvFrom }} + {{- tpl . $ | nindent 10 }} + {{- end }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + resources: +{{ toYaml .Values.resources | indent 12 }} + volumeMounts: + # xlrl/mantisbt expects config as a volume mount - will be created on first run + - name: config + mountPath: /var/www/html/config + {{- if .Values.persistence.enabled }} + - name: uploads + mountPath: /var/www/html/uploads + {{- end }} + livenessProbe: + tcpSocket: + port: http + initialDelaySeconds: 180 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + readinessProbe: + tcpSocket: + port: http + initialDelaySeconds: 60 + periodSeconds: 5 + timeoutSeconds: 3 + failureThreshold: 10 + {{- with .Values.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} +{{- if .Values.affinity }} + affinity: +{{ toYaml .Values.affinity | indent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + volumes: + # Persistent config volume - xlrl expects this to be writable + - name: config + persistentVolumeClaim: + claimName: {{ template "mantisbt.fullname" . }}-config + {{- if .Values.persistence.enabled }} + - name: uploads + persistentVolumeClaim: + claimName: {{ template "mantisbt.fullname" . }}-uploads + {{- end }} diff --git a/mantisbt/mantisbt/templates/hpa.yaml b/mantisbt/mantisbt/templates/hpa.yaml new file mode 100644 index 0000000..5a366ee --- /dev/null +++ b/mantisbt/mantisbt/templates/hpa.yaml @@ -0,0 +1,18 @@ +{{- if .Values.autoscaling.enabled -}} +apiVersion: autoscaling/v1 +kind: HorizontalPodAutoscaler +metadata: + name: {{ template "mantisbt.fullname" . }} + labels: + app: {{ template "mantisbt.name" . }} + chart: {{ template "mantisbt.chart" . }} + component: mantisbt + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ template "mantisbt.fullname" . }} +{{ toYaml .Values.autoscaling.config | indent 2 }} +{{- end -}} diff --git a/mantisbt/mantisbt/templates/ingress.yaml b/mantisbt/mantisbt/templates/ingress.yaml new file mode 100644 index 0000000..1156fde --- /dev/null +++ b/mantisbt/mantisbt/templates/ingress.yaml @@ -0,0 +1,47 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "mantisbt.fullname" . -}} +{{- $servicePort := .Values.service.port -}} +{{- $ingressPath := .Values.ingress.path -}} +{{- $ingressPathType := .Values.ingress.pathtype -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ $fullName }} + labels: + app: {{ template "mantisbt.name" . }} + chart: {{ template "mantisbt.chart" . }} + component: mantisbt + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +{{- with .Values.ingress.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} +spec: + {{- if .Values.ingress.className }} + ingressClassName: {{ .Values.ingress.className }} + {{- end }} +{{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} +{{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ . }} + http: + paths: + - path: {{ $ingressPath }} + pathType: {{ $ingressPathType }} + backend: + service: + name: {{ $fullName }} + port: + number: {{ $servicePort }} + {{- end }} +{{- end }} diff --git a/mantisbt/mantisbt/templates/pvc.yaml b/mantisbt/mantisbt/templates/pvc.yaml new file mode 100644 index 0000000..b7c2425 --- /dev/null +++ b/mantisbt/mantisbt/templates/pvc.yaml @@ -0,0 +1,57 @@ +{{- if .Values.persistence.enabled -}} +# Config PVC - xlrl/mantisbt needs writable config directory +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ template "mantisbt.fullname" . }}-config + labels: + app: {{ template "mantisbt.name" . }} + chart: {{ template "mantisbt.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + {{- with .Values.persistence.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + accessModes: + - {{ .Values.persistence.accessMode | quote }} + {{- if .Values.persistence.storageClass }} + {{- if (eq "-" .Values.persistence.storageClass) }} + storageClassName: "" + {{- else }} + storageClassName: {{ .Values.persistence.storageClass | quote }} + {{- end }} + {{- end }} + resources: + requests: + storage: "100Mi" +--- +# Uploads PVC +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ template "mantisbt.fullname" . }}-uploads + labels: + app: {{ template "mantisbt.name" . }} + chart: {{ template "mantisbt.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + {{- with .Values.persistence.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + accessModes: + - {{ .Values.persistence.accessMode | quote }} + {{- if .Values.persistence.storageClass }} + {{- if (eq "-" .Values.persistence.storageClass) }} + storageClassName: "" + {{- else }} + storageClassName: {{ .Values.persistence.storageClass | quote }} + {{- end }} + {{- end }} + resources: + requests: + storage: {{ .Values.persistence.size | quote }} +{{- end -}} diff --git a/mantisbt/mantisbt/templates/secret.yaml b/mantisbt/mantisbt/templates/secret.yaml new file mode 100644 index 0000000..97b0d6e --- /dev/null +++ b/mantisbt/mantisbt/templates/secret.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "mantisbt.fullname" . }}-secret + labels: + app: {{ template "mantisbt.name" . }} + chart: {{ template "mantisbt.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +type: Opaque +stringData: + database-password: {{ include "mantisbt.databasePassword" . | quote }} + # Master salt - use provided value or generate random one + master-salt: {{ .Values.mantisbt.masterSalt | default (randAlphaNum 64 | b64enc) | quote }} + {{- range .Values.secretEnv }} + {{ .name }}: {{ .value | quote }} + {{- end }} diff --git a/mantisbt/mantisbt/templates/service.yaml b/mantisbt/mantisbt/templates/service.yaml new file mode 100644 index 0000000..c0b1519 --- /dev/null +++ b/mantisbt/mantisbt/templates/service.yaml @@ -0,0 +1,25 @@ +apiVersion: v1 +kind: Service +metadata: + {{- if .Values.service.annotations }} + annotations: +{{ toYaml .Values.service.annotations | indent 4 }} + {{- end }} + name: {{ template "mantisbt.fullname" . }} + labels: + app: {{ template "mantisbt.name" . }} + chart: {{ template "mantisbt.chart" . }} + component: mantisbt + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: 80 + protocol: TCP + name: http + selector: + app: {{ template "mantisbt.name" . }} + component: mantisbt + release: {{ .Release.Name }} diff --git a/mantisbt/mantisbt/templates/serviceaccount.yaml b/mantisbt/mantisbt/templates/serviceaccount.yaml new file mode 100644 index 0000000..1a3f664 --- /dev/null +++ b/mantisbt/mantisbt/templates/serviceaccount.yaml @@ -0,0 +1,13 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "mantisbt.serviceAccountName" . }} + labels: + {{- include "mantisbt.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +automountServiceAccountToken: {{ .Values.serviceAccount.automount }} +{{- end }} diff --git a/mantisbt/mantisbt/values.yaml b/mantisbt/mantisbt/values.yaml new file mode 100644 index 0000000..426d616 --- /dev/null +++ b/mantisbt/mantisbt/values.yaml @@ -0,0 +1,114 @@ +platform: kubernetes + +serviceAccount: + create: true + name: "" + annotations: {} + automount: false + +image: + # xlrl/mantisbt - well maintained, PHP 8.3, good documentation + repository: xlrl/mantisbt + tag: "latest" + pullPolicy: IfNotPresent + +replicaCount: 1 + +service: + type: ClusterIP + port: 80 + annotations: {} + +ingress: + enabled: false + className: traefik + annotations: {} + path: / + pathtype: Prefix + hosts: + - mantisbt.local + tls: [] + +resources: + requests: + memory: 128Mi + cpu: 100m + limits: + memory: 512Mi + cpu: 500m + +nodeSelector: {} +tolerations: [] +affinity: {} + +autoscaling: + enabled: false + config: + minReplicas: 1 + maxReplicas: 5 + targetCPUUtilizationPercentage: 80 + +deploymentLabels: {} +podLabels: {} + +persistence: + enabled: true + accessMode: ReadWriteOnce + size: 5Gi + storageClass: "" + annotations: {} + +updateStrategy: + type: RollingUpdate + rollingUpdate: + maxUnavailable: 1 + maxSurge: 1 + +podSecurityContext: {} +securityContext: {} + +# MantisBT specific configuration +mantisbt: + # Enable admin folder for installation (set to "0" after install!) + enableAdmin: "1" + + # Timezone (xlrl uses MANTIS_TIMEZONE) + timezone: "Europe/Berlin" + + # Master Salt for crypto - IMPORTANT: Set this to keep it stable across deployments! + # If not set, a random one will be generated (but changes on each deploy) + # Generate with: openssl rand -base64 32 + masterSalt: "" + +# Environment variables +env: [] + +secretEnv: [] + +extraEnvFrom: [] + +extraDeploy: [] + +# MariaDB subchart configuration +mariadb: + enabled: true + auth: + database: mantisbt + username: mantisbt + password: "mantisbt123" + rootPassword: "rootpassword123" + primary: + persistence: + enabled: true + size: 8Gi + storageClass: "" + +# External database (if mariadb.enabled=false) +externalDatabase: + host: "" + port: 3306 + database: mantisbt + username: mantisbt + password: "" + existingSecret: "" + existingSecretPasswordKey: ""