Skip to Content
OperationsHelm ChartsModulith Chart

Modulith Chart

The miot-modulith chart deploys the ModularIoT Quarkus backend — a modulith server that hosts fleet, driver, tracking, gateway, and integrations components. Each component can be independently enabled via values, allowing the same chart and image to serve different deployment roles.

Install

helm repo add microboxlabs https://microboxlabs.github.io/helm-charts helm repo update helm install miot-modulith microboxlabs/miot-modulith \ -f values-prod.yaml \ --namespace default

Component Activation

The modulith image contains all components. Enable only what each deployment needs:

components: fleet: enabled: true driver: enabled: true tracking: enabled: false gateway: enabled: false integrations: enabled: false

Each flag maps to MIOT_COMPONENT_*_ENABLED environment variables injected by the chart.

Deployment Topology Examples

DeploymentComponentsPurpose
prod-miot-modulithfleet + driverREST API for fleet dashboard
dev-miot-modulithfleet + driver + tracking + integrationsAll-in-one dev server
prod-miot-gatewaygatewayRequest forking/mirroring
prod-miot-integrationsintegrationsExternal API connections and credential profiles

All use the same image (ghcr.io/microboxlabs/miot-srv) and chart (miot-modulith).

Database

The chart injects both JDBC (Flyway) and reactive (Hibernate) datasource URLs:

postgresql: external: host: "pgbouncer-service" port: 6432 database: "miot" username: "miot" password: "" existingSecret: "miot-db-credentials" existingSecretUsernameKey: "db_username" existingSecretPasswordKey: "db_password"

For gateway-only deployments (no database), disable the datasource:

postgresql: external: host: "" database: "" username: "" password: "" env: - name: QUARKUS_DATASOURCE_ACTIVE value: "false" - name: QUARKUS_HIBERNATE_ORM_ACTIVE value: "false"

Authentication

Auth0 Dual JWT (HS256 + RS256)

auth: issuer: "https://auth0.example.com/" hs256Secret: "" # use existingSecret in prod jwksUrl: "https://auth0.example.com/.well-known/jwks.json" hs256Audience: "https://api.example.com/v1/asset/track" rs256Audience: "https://api.example.com/v1" existingSecret: "miot-auth-credentials" existingSecretHs256Key: "hs256-secret"

OIDC (Legacy)

oidc: authServerUrl: "https://auth0.example.com" clientId: "my-client-id" existingSecret: "miot-oidc-credentials" existingSecretKey: "client-secret"

Messaging

messaging: type: "log" # log = standalone (no broker), pulsar = Apache Pulsar pulsarUrl: "" # e.g., pulsar://pulsar-proxy:6650 trackingTopic: "" # e.g., persistent://streamhub/tracking/asset-positions

Flyway Migrations

flyway: migrateAtStart: false # true for dev, false for prod

The FlywayMigrator conditionally includes migration locations based on active components and tolerates previously applied migrations from inactive components.

Migration version ranges are reserved by component:

ComponentSchemaMigration range
Coremiot_coreV0.1.x
Fleetmiot_fleetV0.2.x
Resource Coremiot_resourceV0.3.x
Drivermiot_driverV0.4.x
Trackingmiot_trackingV0.5.x
Integrationsmiot_integrationsV0.6.x

APISIX Route

The chart can create an ApisixRoute CRD for APISIX-based ingress:

apisixRoute: enabled: true ingressClassName: apisix hosts: - host: api.modulariot.com paths: - /miot - /miot/* tls: - hosts: - api.modulariot.com secretName: api-tls plugins: - name: redirect enable: true config: http_to_https: true - name: cors enable: true

Fork Engine (Gateway)

When the gateway component is enabled, the fork engine provides body-aware request mirroring. Configure rules declaratively in values — the chart generates all environment variables and manages the filter ConfigMap automatically.

Configuration

components: gateway: enabled: true fork: enabled: true rules: - id: asset-track-canary enabled: true paths: - /v1/asset/track bodyParser: json # json or csv keyField: asset_id # field to extract as routing key filterFile: /config/fork/asset-ids.txt targets: - id: storm mirrorHost: https://storm.modulariot.com mirrorPath: /api/v1/asset/track timeout: 5000 # milliseconds # Filter files — mounted as ConfigMap at /config/fork/ filters: asset-ids.txt: | # One routing key per line. Lines starting with # are ignored. SVSX88 TRUCK-001

How It Works

Client -> APISIX -> primary backend (e.g., pulsar-publisher) | +-> proxy-mirror -> miot-gateway (ClusterIP) | +-> ForkEngine checks body for key | +-- key in filter -> forward to target(s) +-- key not in filter -> discard (200 OK)
  1. APISIX’s proxy-mirror plugin sends a copy of each request to the gateway service
  2. The gateway’s ForkEngine parses the request body, extracts the routing key
  3. If the key is in the in-memory filter, the request is forwarded to all configured targets
  4. If not, the request is silently discarded (returns 200 to APISIX)

Filter Management

Filters can be managed two ways:

Via ConfigMap (persistent, survives restarts):

Update fork.filters in values and re-deploy, or edit the ConfigMap directly:

kubectl edit configmap <release>-miot-modulith-fork-filters

Then reload via the management API:

kubectl exec <pod> -- curl -X POST http://localhost:8180/internal/fork/rules/asset-track-canary/filter/reload

Via Management API (immediate, in-memory only):

# List current filter keys kubectl exec <pod> -- curl http://localhost:8180/internal/fork/rules/asset-track-canary/filter # Add keys kubectl exec <pod> -- curl -X POST http://localhost:8180/internal/fork/rules/asset-track-canary/filter \ -H 'Content-Type: application/json' -d '["NEW-ASSET-1", "NEW-ASSET-2"]' # Remove a key kubectl exec <pod> -- curl -X DELETE http://localhost:8180/internal/fork/rules/asset-track-canary/filter/NEW-ASSET-1

APISIX Proxy Mirror Setup

Add the proxy-mirror plugin to the upstream service’s APISIX route:

# On the quarkus-http-pulsar-publisher route plugins: - name: proxy-mirror enable: true config: host: "http://<gateway-release>-miot-modulith:8180" sample_ratio: 1 # 1.0 = mirror all traffic, 0.5 = 50%

Metrics

The fork engine exposes Prometheus metrics at /q/metrics:

MetricLabelsDescription
fork_requests_totalrule, target, outcomeRequests processed (forwarded/discarded/error)
fork_forward_duration_secondsrule, targetForwarding latency histogram
fork_filter_sizeruleCurrent filter size per rule

Values Reference

KeyDefaultDescription
replicaCount1Number of pod replicas
image.repositoryghcr.io/microboxlabs/miot-srvContainer image
image.taglatestImage tag
service.port8180HTTP port
components.fleet.enabledtrueEnable fleet management
components.driver.enabledfalseEnable driver management
components.tracking.enabledfalseEnable asset tracking
components.gateway.enabledfalseEnable gateway/fork engine
components.integrations.enabledfalseEnable integrations component
postgresql.external.hostpostgresqlDatabase host
postgresql.external.port5432Database port
postgresql.external.databasemiotDatabase name
messaging.typelogMessaging backend (log/pulsar)
flyway.migrateAtStartfalseRun migrations on startup
fork.enabledfalseEnable fork engine
fork.rules[]Fork rule definitions
fork.filters{}Filter file contents (ConfigMap)
apisixRoute.enabledfalseCreate ApisixRoute CRD
Last updated on