Add optional bundled Mosquitto pod to Helm chart

Mirrors the Postgres pattern: mosquitto.enabled deploys a bundled
Mosquitto pod with service, PVC, and configmap. When disabled,
mosquitto.external.host points to an external broker (e.g., Amazon MQ)
with TLS and credentials. When neither is set, MQTT is disabled
entirely and announcements fall back to REST polling.

Bundled mode: eclipse-mosquitto:2, ports 1883 (MQTT) + 9001 (WS),
anonymous access, 256Mi persistence, minimal resources (25m/32Mi).

External mode: configurable TLS, port, wsUrl, username/password
injected via K8s Secret.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-07 16:43:54 -07:00
parent c6af22a1e5
commit 901f4eb328
8 changed files with 171 additions and 22 deletions

View File

@@ -45,6 +45,10 @@ busybox:1.37
{{ include "osa-suite.fullname" . }}-postgres
{{- end -}}
{{- define "osa-suite.mosquittoName" -}}
{{ include "osa-suite.fullname" . }}-mosquitto
{{- end -}}
{{/*
Construct the DATABASE_URL.
Password is injected at runtime via $(DATABASE_PASSWORD) env var substitution.

View File

@@ -21,14 +21,20 @@ data:
{{- if .Values.sessionCookieDomain }}
SESSION_COOKIE_DOMAIN: {{ .Values.sessionCookieDomain | quote }}
{{- end }}
{{- if .Values.mqtt.host }}
MQTT_HOST: {{ .Values.mqtt.host | quote }}
MQTT_PORT: {{ .Values.mqtt.port | default 1883 | quote }}
MQTT_WS_PORT: {{ .Values.mqtt.wsPort | default 9001 | quote }}
MQTT_USE_TLS: {{ .Values.mqtt.useTls | default false | quote }}
MQTT_TOPIC: {{ .Values.mqtt.topic | default "mgmt/announcements" | quote }}
{{- if .Values.mqtt.wsUrl }}
MQTT_WS_URL: {{ .Values.mqtt.wsUrl | quote }}
{{- if .Values.mosquitto.enabled }}
MQTT_HOST: {{ include "osa-suite.mosquittoName" . | quote }}
MQTT_PORT: "1883"
MQTT_WS_PORT: "9001"
MQTT_USE_TLS: "false"
MQTT_TOPIC: {{ .Values.mosquitto.topic | default "mgmt/announcements" | quote }}
{{- else if .Values.mosquitto.external.host }}
MQTT_HOST: {{ .Values.mosquitto.external.host | quote }}
MQTT_PORT: {{ .Values.mosquitto.external.port | default 8883 | quote }}
MQTT_WS_PORT: {{ .Values.mosquitto.external.wsPort | default 443 | quote }}
MQTT_USE_TLS: {{ .Values.mosquitto.external.useTls | default true | quote }}
MQTT_TOPIC: {{ .Values.mosquitto.topic | default "mgmt/announcements" | quote }}
{{- if .Values.mosquitto.external.wsUrl }}
MQTT_WS_URL: {{ .Values.mosquitto.external.wsUrl | quote }}
{{- end }}
{{- end }}
{{- if .Values.smtp.host }}

View File

@@ -0,0 +1,20 @@
{{- if .Values.mosquitto.enabled }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "osa-suite.mosquittoName" . }}-config
labels:
app.kubernetes.io/component: mosquitto
{{- include "osa-suite.labels" . | nindent 4 }}
data:
mosquitto.conf: |
listener 1883 0.0.0.0
listener 9001 0.0.0.0
protocol websockets
allow_anonymous true
persistence true
persistence_location /mosquitto/data/
log_dest stdout
{{- end }}

View File

@@ -0,0 +1,63 @@
{{- if .Values.mosquitto.enabled }}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "osa-suite.mosquittoName" . }}
labels:
app.kubernetes.io/component: mosquitto
{{- include "osa-suite.labels" . | nindent 4 }}
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app.kubernetes.io/component: mosquitto
app.kubernetes.io/instance: {{ .Release.Name }}
template:
metadata:
labels:
app.kubernetes.io/component: mosquitto
app.kubernetes.io/instance: {{ .Release.Name }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
- name: mosquitto
image: {{ .Values.mosquitto.image }}
ports:
- name: mqtt
containerPort: 1883
protocol: TCP
- name: websocket
containerPort: 9001
protocol: TCP
volumeMounts:
- name: config
mountPath: /mosquitto/config/mosquitto.conf
subPath: mosquitto.conf
readOnly: true
- name: data
mountPath: /mosquitto/data
livenessProbe:
tcpSocket:
port: mqtt
initialDelaySeconds: 5
periodSeconds: 30
readinessProbe:
tcpSocket:
port: mqtt
initialDelaySeconds: 3
periodSeconds: 10
resources:
{{- toYaml .Values.mosquitto.resources | nindent 12 }}
volumes:
- name: config
configMap:
name: {{ include "osa-suite.mosquittoName" . }}-config
- name: data
persistentVolumeClaim:
claimName: {{ include "osa-suite.mosquittoName" . }}-data
{{- end }}

View File

@@ -0,0 +1,18 @@
{{- if .Values.mosquitto.enabled }}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ include "osa-suite.mosquittoName" . }}-data
labels:
app.kubernetes.io/component: mosquitto
{{- include "osa-suite.labels" . | nindent 4 }}
spec:
accessModes:
- {{ .Values.mosquitto.persistence.accessMode | default "ReadWriteOnce" }}
{{- if .Values.mosquitto.persistence.storageClass }}
storageClassName: {{ .Values.mosquitto.persistence.storageClass | quote }}
{{- end }}
resources:
requests:
storage: {{ .Values.mosquitto.persistence.size }}
{{- end }}

View File

@@ -0,0 +1,22 @@
{{- if .Values.mosquitto.enabled }}
apiVersion: v1
kind: Service
metadata:
name: {{ include "osa-suite.mosquittoName" . }}
labels:
app.kubernetes.io/component: mosquitto
{{- include "osa-suite.labels" . | nindent 4 }}
spec:
selector:
app.kubernetes.io/component: mosquitto
app.kubernetes.io/instance: {{ .Release.Name }}
ports:
- name: mqtt
port: 1883
targetPort: 1883
protocol: TCP
- name: websocket
port: 9001
targetPort: 9001
protocol: TCP
{{- end }}

View File

@@ -24,11 +24,11 @@ stringData:
{{- if .Values.smtp.password }}
SMTP_PASSWORD: {{ .Values.smtp.password | quote }}
{{- end }}
{{- if .Values.mqtt.username }}
MQTT_USERNAME: {{ .Values.mqtt.username | quote }}
{{- if .Values.mosquitto.external.username }}
MQTT_USERNAME: {{ .Values.mosquitto.external.username | quote }}
{{- end }}
{{- if .Values.mqtt.password }}
MQTT_PASSWORD: {{ .Values.mqtt.password | quote }}
{{- if .Values.mosquitto.external.password }}
MQTT_PASSWORD: {{ .Values.mosquitto.external.password | quote }}
{{- end }}
{{- if .Values.postgresql.enabled }}
DATABASE_PASSWORD: {{ required "postgresql.password is required when postgresql is enabled" .Values.postgresql.password | quote }}

View File

@@ -105,16 +105,32 @@ smtp:
useTls: true
fromAddress: "mgmt@example.com"
mqtt:
# MQTT broker for real-time announcements
# When host is set, MQTT announcements are enabled
host: "" # e.g., "mosquitto.namespace.svc.cluster.local"
port: 1883 # MQTT TCP port (backend publishes here)
wsPort: 9001 # WebSocket port (frontend connects here)
wsUrl: "" # Browser-reachable WebSocket URL (e.g., "wss://mqtt.example.com/mqtt")
useTls: false
username: ""
password: "" # Goes into K8s Secret as MQTT_PASSWORD
# ── MQTT ───────────────────────────────────────────────────
# When mosquitto.enabled is true, a bundled Mosquitto pod is deployed.
# When false and external.host is set, connects to an external broker (e.g., Amazon MQ, EMQX Cloud).
# When neither is set, MQTT is disabled and announcements fall back to REST polling.
mosquitto:
enabled: false
image: eclipse-mosquitto:2
resources:
requests:
cpu: 25m
memory: 32Mi
limits:
cpu: 100m
memory: 64Mi
persistence:
size: 256Mi
storageClass: ""
accessMode: ReadWriteOnce
external:
host: "" # e.g., "mqtt.example.com" or "a1b2c3.iot.us-east-1.amazonaws.com"
port: 8883 # External brokers typically use 8883 (TLS)
wsPort: 443 # WebSocket port for browser clients
wsUrl: "" # Full browser-reachable WebSocket URL (e.g., "wss://mqtt.example.com/mqtt")
useTls: true
username: ""
password: "" # Goes into K8s Secret as MQTT_PASSWORD
topic: "mgmt/announcements"
caCert: