Skip to content

Middleware

Deploy Middleware, the open-source DORA metrics platform, with the official image and either bundled or external PostgreSQL. The chart measures deployment frequency, lead time for changes, change failure rate, and time to restore.

PostgreSQL and the key PVC are one recovery set

Middleware encrypts integration credentials with an RSA key pair stored on the application PVC. Back up and restore PostgreSQL and that PVC together. A database restored without its matching key pair can contain credentials the application can no longer decrypt.

Key features

  • Official middlewareeng/middleware:0.3.1 image
  • HelmForge PostgreSQL subchart or an external PostgreSQL service
  • Database migrations applied before application startup
  • Persistent encryption keys at the upstream configuration path
  • Real frontend, analytics, and sync port configuration
  • Readiness checks for all three application listeners and embedded Redis
  • Tokenless ServiceAccount, seccomp, capability drop, and NetworkPolicy defaults
  • Ingress, scheduling, resource, additional volume, and extra manifest controls

Architecture

The upstream image supervises a Next.js frontend, analytics API, sync server, cron, and optional embedded datastores. This chart disables embedded PostgreSQL and enables the upstream embedded Redis process on loopback.

Process Default port Exposure
Frontend 3333 Service and optional Ingress
Analytics API 9696 Pod-internal
Sync server 9697 Pod-internal

An init container runs the migrations included in the same official image and writes the startup signal expected by the analytics process. The application Deployment remains single-replica and uses Recreate because the key volume is stateful and upstream does not define a multi-replica coordination model.

Why there is no Redis subchart

Middleware 0.3.1 does not expose a remote Redis password and forces TLS whenever the Redis host is not localhost. A normal authenticated Redis Service is therefore incompatible. The chart uses the upstream-supported loopback Redis runtime and rejects legacy redis.enabled or externalRedis.enabled overrides.

Installation

helm repo add helmforge https://repo.helmforge.dev
helm repo update
helm install middleware helmforge/middleware \
  --namespace middleware \
  --create-namespace

Using OCI:

helm install middleware oci://ghcr.io/helmforgedev/helm/middleware \
  --namespace middleware \
  --create-namespace

Deployment examples

postgresql:
  enabled: true
  auth:
    database: mhq-oss
    username: middleware

persistence:
  enabled: true
  size: 1Gi

middleware:
  timezone: America/Sao_Paulo
postgresql:
  enabled: false

externalDatabase:
  enabled: true
  host: postgres.database.svc.cluster.local
  port: 5432
  name: mhq-oss
  user: middleware
  existingSecret: middleware-database
  existingSecretPasswordKey: user-password
  sslMode: require

persistence:
  enabled: true
middleware:
  frontendPort: 4333
  analyticsPort: 10696
  syncPort: 10697

service:
  port: 8080

The Service targets the named frontend port, so its port remains independent from the process listener.

External database credentials

Create the Secret before installation or let an external secret controller create the same target:

read -r -s -p 'External PostgreSQL password: ' MIDDLEWARE_DB_PASSWORD
printf '\n'
kubectl create namespace middleware --dry-run=client -o yaml | kubectl apply -f -
kubectl create secret generic middleware-database \
  --namespace middleware \
  --from-literal=user-password="$MIDDLEWARE_DB_PASSWORD"
unset MIDDLEWARE_DB_PASSWORD

An inline externalDatabase.password is supported for development and is rendered into a Secret rather than directly into the Deployment. It can still be retained in Helm release storage, so use an existing Secret for production.

Production example

postgresql:
  enabled: true
  auth:
    database: mhq-oss
    username: middleware

persistence:
  enabled: true
  size: 5Gi

resources:
  requests:
    cpu: 500m
    memory: 2Gi
  limits:
    cpu: '4'
    memory: 8Gi

ingress:
  enabled: true
  ingressClassName: traefik
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
  hosts:
    - host: middleware.example.com
      paths:
        - path: /
          pathType: Prefix
  tls:
    - hosts:
        - middleware.example.com
      secretName: middleware-tls

Configuration reference

Application

Parameter Default Description
middleware.frontendPort 3333 Frontend process and container port.
middleware.analyticsPort 9696 Analytics process and container port.
middleware.syncPort 9697 Sync process and container port.
middleware.environment prod Backend and frontend environment.
middleware.timezone UTC IANA timezone for metric windows.
middleware.extraEnv [] Additional environment entries.

The internal database flag must remain "false", and the internal Redis flag must remain "true". The chart validates both constraints.

PostgreSQL

Parameter Default Description
postgresql.enabled true Deploy bundled PostgreSQL.
postgresql.auth.database mhq-oss Application database.
postgresql.auth.username middleware Application role.
externalDatabase.enabled false Use external PostgreSQL.
externalDatabase.host "" External hostname.
externalDatabase.port 5432 External port.
externalDatabase.existingSecret "" Password Secret.
externalDatabase.existingSecretPasswordKey user-password Password key.
externalDatabase.sslMode disable libpq SSL mode.

Exactly one database mode must be active. PostgreSQL custom names, existing Secrets, custom password keys, replication primary Services, and External Secrets target names are honored by the application wiring.

Persistence and exposure

Parameter Default Description
persistence.enabled true Persist encryption keys.
persistence.size 1Gi Key PVC capacity.
persistence.existingClaim "" Reuse a PVC.
service.port 80 Frontend Service port.
ingress.enabled false Render Ingress.
networkPolicy.enabled true Restrict inbound traffic to frontend.

Security

By default the pod receives no Kubernetes API token, uses RuntimeDefault seccomp, disallows privilege escalation, and drops all capabilities. The NetworkPolicy restricts ingress to the frontend while leaving egress open for operator-selected Git and CI providers.

The official image runs as root and writes runtime artifacts under /opt and /app; runAsNonRoot and a read-only root filesystem are therefore not safe defaults without a different upstream image.

Operations and troubleshooting

Check migrations and application logs independently:

kubectl logs -n middleware deployment/middleware-middleware -c migrate-database
kubectl logs -n middleware deployment/middleware-middleware -c middleware --tail=200
kubectl describe pod -n middleware -l app.kubernetes.io/instance=middleware

If migration waits, verify PostgreSQL DNS, credentials, SSL mode, and network access. If migrations pass but the pod is not Ready, one of the frontend, analytics, sync, or embedded Redis listeners is unavailable.

Preserve the key PVC on every upgrade. Remove legacy Redis overrides before upgrading to this contract.

More information