Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions deploy/helm/comqtt/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ description: |
comqtt — a lightweight, high-performance MQTT broker (v3.0/v3.1.1/v5.0)
supporting standalone and clustered (Raft + Gossip) deployments.
type: application
version: 0.1.0
version: 0.3.0
appVersion: "2.6.0"
kubeVersion: ">=1.23.0-0"
home: https://github.com/wind-c/comqtt
Expand All @@ -25,7 +25,9 @@ icon: https://raw.githubusercontent.com/wind-c/comqtt/main/README.md
annotations:
artifacthub.io/changes: |
- kind: added
description: Initial Helm chart with single-node and clustered deployment modes (resolves #137).
description: Gateway API support, HTTPRoute (REST API + /metrics) and TCPRoute (MQTT).
- kind: deprecated
description: ingress.* (use gateway.* instead).
artifacthub.io/license: MIT
## Bitnami sub-charts intentionally omitted: as of 2025 the public bitnami/*
## Docker images are behind authentication. Bring your own Redis/Valkey,
Expand Down
65 changes: 55 additions & 10 deletions deploy/helm/comqtt/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,13 @@ is rejected by the schema.
| `service.mqtt.{type,port,nodePort}` | — | `ClusterIP / 1883` | |
| `service.ws.{type,port,nodePort}` | — | `ClusterIP / 1882` | |
| `service.dashboard.{type,port,nodePort}` | — | `ClusterIP / 8080` | |
| `ingress.enabled` | bool | `false` | Dashboard only. |
| `ingress.enabled` | bool | `false` | **DEPRECATED.** Use `gateway.*`. HTTP listener only. |
| `gateway.enabled` | bool | `false` | Master toggle for Gateway API resources. |
| `gateway.parentRefs` | list | `[]` | Default `parentRefs` for both routes. |
| `gateway.api.enabled` | bool | `true` | Emit `HTTPRoute` for the broker's HTTP listener (REST + metrics). |
| `gateway.api.hostnames` | list | `[]` | HTTPRoute hostnames. |
| `gateway.api.matches` | list | PathPrefix `/` | HTTPRoute path matches. |
| `gateway.mqtt.enabled` | bool | `false` | Emit `TCPRoute` for raw MQTT (alpha API). |
| `tls.enabled` | bool | `false` | |
| `tls.existingSecret` | string | `""` | Pre-created Secret with tls.crt/tls.key/ca.crt. |
| `tls.certManager.enabled` | bool | `false` | |
Expand Down Expand Up @@ -143,17 +149,54 @@ and [cmd/config/node1.yml](https://github.com/wind-c/comqtt/blob/main/cmd/config
in the upstream repo. The chart's `config:` block mirrors those files
verbatim.

## Exposing MQTT externally
## Exposing the broker externally

The chart prefers [Gateway API](https://gateway-api.sigs.k8s.io/) over the
legacy `Ingress` resource. ingress-nginx is in [retirement as of
2025-11-11](https://kubernetes.io/blog/2025/11/11/ingress-nginx-retirement/)
and a Layer 7 Ingress cannot proxy raw MQTT in any case.

### Gateway API (preferred)

You bring the `Gateway` resource and a Gateway API provider. Examples:
[Envoy Gateway](https://gateway.envoyproxy.io/), Cilium, Istio, Kong.

The chart emits:

- `HTTPRoute` for the broker's HTTP listener on port 8080
(`gateway.api.enabled`, default on). This serves the existing `/api/v1/*`
REST surface and `/metrics`. Most users will not expose this externally;
flip the toggle off if you don't need it.
- `TCPRoute` for raw MQTT (`gateway.mqtt.enabled`, default off — TCPRoute is
in `gateway.networking.k8s.io/v1alpha2` and requires a TCP-aware provider)

Minimal example with Envoy Gateway in front:

```yaml
# values.yaml
gateway:
enabled: true
parentRefs:
- name: eg
namespace: envoy-gateway-system
api:
enabled: true
hostnames: ["comqtt.example.com"]
mqtt:
enabled: true
```

For TLS termination at the Gateway, configure listeners on the `Gateway`
itself; for TLS at the broker, set `tls.existingSecret` and wire
`config.mqtt.tls.{ca-cert,server-cert,server-key}`.

A standard HTTP Ingress **cannot** proxy raw MQTT TCP — it is a Layer 7
HTTP-only resource. Use one of:
### Legacy fallbacks

If Gateway API is not available in your cluster:

- `service.mqtt.type: LoadBalancer` — straightforward on cloud providers.
- An Ingress controller with TCP passthrough (e.g. NGINX `--tcp-services-configmap`).
- A NodePort plus an external load balancer or DNS round-robin.

For TLS termination at the broker, supply `tls.existingSecret` and reference
it from `config.mqtt.tls.{ca-cert,server-cert,server-key}`.
- `ingress.*` (deprecated; HTTP listener only, cannot proxy raw MQTT).

## Upgrades

Expand Down Expand Up @@ -183,8 +226,10 @@ it from `config.mqtt.tls.{ca-cert,server-cert,server-key}`.
- No bundled RESP store. The chart expects an externally-deployed Redis or
Valkey (see [ci/valkey.yaml](ci/valkey.yaml) for a starting point) — the
chart does not manage failover or HA for it.
- The dashboard Ingress proxies `/`. Mounting it under a sub-path is not
currently supported.
- The HTTP `HTTPRoute` defaults to `PathPrefix /`. Override
`gateway.api.matches` to mount under a sub-path; consumers expecting
routes at `/api/v1/...` and `/metrics` will need an HTTPRoute filter
(`URLRewrite`) to strip the prefix before forwarding.

## Contributing

Expand Down
22 changes: 19 additions & 3 deletions deploy/helm/comqtt/templates/NOTES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,23 @@ To run the chart's bundled connectivity test:

{{- if .Values.ingress.enabled }}

Dashboard Ingress is enabled. Note: raw MQTT cannot be served by a Layer 7
HTTP Ingress; for external MQTT use a LoadBalancer Service or an Ingress
controller with TCP passthrough.
WARNING: `ingress.*` is DEPRECATED. ingress-nginx is in retirement
(https://kubernetes.io/blog/2025/11/11/ingress-nginx-retirement/) and
a Layer 7 Ingress cannot proxy raw MQTT. Migrate to `gateway.*`
(Gateway API): set `gateway.enabled=true` plus `gateway.api.enabled=true`
(and `gateway.mqtt.enabled=true` for raw MQTT) and supply a Gateway via
`gateway.parentRefs`.
{{- end }}

{{- if .Values.gateway.enabled }}

Gateway API routes:
{{- if .Values.gateway.api.enabled }}
HTTPRoute {{ include "comqtt.fullname" . }}-api -> Service/{{ include "comqtt.fullname" . }}:{{ .Values.service.dashboard.port }}
(REST API + /metrics)
{{- end }}
{{- if .Values.gateway.mqtt.enabled }}
TCPRoute {{ include "comqtt.fullname" . }}-mqtt -> Service/{{ include "comqtt.fullname" . }}:{{ .Values.service.mqtt.port }}
(requires gateway.networking.k8s.io/v1alpha2)
{{- end }}
{{- end }}
34 changes: 34 additions & 0 deletions deploy/helm/comqtt/templates/httproute.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{{- if and .Values.gateway.enabled .Values.gateway.api.enabled -}}
{{- /*
HTTPRoute for the broker's HTTP listener (port 8080 by default), which
serves the /api/v1/* REST surface and /metrics. The chart's
`service.dashboard.port` value name is kept for back-compat with chart
0.1.0; it refers to the HTTP listener port regardless of what is mounted
on it.
*/ -}}
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: {{ include "comqtt.fullname" . }}-api
labels:
{{- include "comqtt.labels" . | nindent 4 }}
{{- with .Values.gateway.api.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
parentRefs:
{{- $refs := .Values.gateway.api.parentRefs }}
{{- if not $refs }}{{ $refs = .Values.gateway.parentRefs }}{{ end }}
{{- toYaml $refs | nindent 4 }}
{{- with .Values.gateway.api.hostnames }}
hostnames:
{{- toYaml . | nindent 4 }}
{{- end }}
rules:
- matches:
{{- toYaml .Values.gateway.api.matches | nindent 8 }}
backendRefs:
- name: {{ include "comqtt.fullname" . }}
port: {{ .Values.service.dashboard.port }}
{{- end }}
26 changes: 26 additions & 0 deletions deploy/helm/comqtt/templates/tcproute.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{{- if and .Values.gateway.enabled .Values.gateway.mqtt.enabled -}}
{{- /*
TCPRoute is in gateway.networking.k8s.io/v1alpha2 as of Gateway API v1.2 and
ships only with TCP-aware Gateway implementations (Envoy Gateway, Cilium,
etc.). Plain ingress-nginx does not support TCPRoute.
*/ -}}
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: TCPRoute
metadata:
name: {{ include "comqtt.fullname" . }}-mqtt
labels:
{{- include "comqtt.labels" . | nindent 4 }}
{{- with .Values.gateway.mqtt.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
parentRefs:
{{- $refs := .Values.gateway.mqtt.parentRefs }}
{{- if not $refs }}{{ $refs = .Values.gateway.parentRefs }}{{ end }}
{{- toYaml $refs | nindent 4 }}
rules:
- backendRefs:
- name: {{ include "comqtt.fullname" . }}
port: {{ .Values.service.mqtt.port }}
{{- end }}
21 changes: 21 additions & 0 deletions deploy/helm/comqtt/values.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@
},
"ingress": {
"type": "object",
"deprecated": true,
"description": "DEPRECATED. Prefer `gateway.*`.",
"properties": {
"enabled": { "type": "boolean" },
"className": { "type": "string" },
Expand All @@ -68,6 +70,15 @@
"tls": { "type": "array" }
}
},
"gateway": {
"type": "object",
"properties": {
"enabled": { "type": "boolean" },
"parentRefs": { "type": "array", "items": { "type": "object" } },
"api": { "$ref": "#/$defs/gatewayRoute" },
"mqtt": { "$ref": "#/$defs/gatewayRoute" }
}
},
"tls": {
"type": "object",
"properties": {
Expand Down Expand Up @@ -171,6 +182,16 @@
"nodePort": { "type": ["integer", "string"] },
"annotations": { "type": "object" }
}
},
"gatewayRoute": {
"type": "object",
"properties": {
"enabled": { "type": "boolean" },
"parentRefs": { "type": "array", "items": { "type": "object" } },
"hostnames": { "type": "array", "items": { "type": "string" } },
"matches": { "type": "array", "items": { "type": "object" } },
"annotations": { "type": "object" }
}
}
}
}
48 changes: 45 additions & 3 deletions deploy/helm/comqtt/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,13 @@ service:
annotations: {}

ingress:
# -- Enable Ingress for the dashboard. NOTE: a standard HTTP Ingress cannot
# proxy raw MQTT TCP. To expose MQTT externally, use a LoadBalancer
# Service or an Ingress controller with TCP/passthrough support.
# -- DEPRECATED. Prefer `gateway.*` (Gateway API). Ingress is retained for
# back-compat only; ingress-nginx is in retirement
# (https://kubernetes.io/blog/2025/11/11/ingress-nginx-retirement/) and a
# standard HTTP Ingress cannot proxy raw MQTT TCP regardless. New
# deployments should use `gateway.api` (HTTPRoute) and `gateway.mqtt`
# (TCPRoute) with a Gateway API provider such as Envoy Gateway, Cilium,
# or Istio.
enabled: false
className: ""
annotations: {}
Expand All @@ -136,6 +140,44 @@ ingress:
pathType: Prefix
tls: []

# Gateway API (preferred over `ingress:`). The chart emits an HTTPRoute for
# the broker's HTTP listener (REST API at /api/v1/* and Prometheus metrics at
# /metrics on port 8080) and a TCPRoute for raw MQTT. You bring the Gateway
# resource: install a Gateway API provider (Envoy Gateway, Cilium, Istio,
# Kong, etc.) and reference it from `parentRefs`. TCPRoute is alpha
# (gateway.networking.k8s.io/v1alpha2) and supported by a subset of providers.
gateway:
# -- Master toggle. Routes also need their per-route `enabled` flag.
enabled: false
# -- Default `parentRefs` applied to both routes when the per-route value
# is empty. Each entry is a Gateway API ParentReference object.
parentRefs: []
# - name: my-gateway
# namespace: gateway-system
# sectionName: http # for HTTPRoute
# sectionName: mqtt # for TCPRoute
api:
# -- Emit an HTTPRoute for the broker's HTTP listener (REST API +
# metrics on port 8080).
enabled: true
# -- Override `gateway.parentRefs` for this route. Empty inherits.
parentRefs: []
# -- Hostnames the route matches (HTTPRoute `spec.hostnames`).
hostnames: []
# -- HTTPRoute path matches. Defaults to PathPrefix `/`.
matches:
- path:
type: PathPrefix
value: /
annotations: {}
mqtt:
# -- Emit a TCPRoute for raw MQTT. Requires a Gateway implementation
# that supports gateway.networking.k8s.io/v1alpha2 TCPRoute.
enabled: false
# -- Override `gateway.parentRefs` for this route.
parentRefs: []
annotations: {}

tls:
# -- Enable MQTT TLS. When enabled either provide `existingSecret` or wire
# up cert-manager via `certManager.issuerRef`.
Expand Down
Loading