Kubernetes (Helm)
A single container is one thing to run; keeping several replicas of it healthy, routed to, and rolling through updates without downtime is a different problem, and that's what a real Kubernetes deployment buys you over just running the Docker image by hand. rapidrest generate k8s packages a project as a Helm chart to run it that way:
rapidrest generate k8s
This adds a Helm chart under helm/. Like generate docker, it's idempotent: regenerate it with --force any time your project's datastores change (see CLI → Add-ons).
Architecture
The chart deploys your server as a stateless Kubernetes Deployment, not a StatefulSet. Every replica is identical and sits behind a single Service, which is in turn exposed outside the cluster through a Gateway API Gateway/HTTPRoute rather than an Ingress. Each pod waits, via an init container, for its datastores to accept connections before starting.
------------ --------------- -----------
| Gateway | ---> | HTTPRoute | ---> | Service |
------------ --------------- -----------
|
-----------------------------------------------------------
| | |
------------ ------------ ------------
| Pod | | Pod | ... | Pod |
| (replica) | | (replica) | | (replica) |
------------ ------------ ------------
| | |
-----------------------------------------------------------
|
-----------------------------------
| |
------------ ------------
| MongoDB | | Redis |
| or | | (optional, |
| PostgreSQL | | standalone)|
| (optional, | ------------
| standalone)|
------------
What's in the chart
MongoDB, PostgreSQL, and Redis are optional dependencies, pulled in as Bitnami subcharts only if your project actually uses them, each gated behind a condition in Chart.yaml (mongodb.create / postgresql.create / redis.create) so they can be swapped out for externally-managed databases in values.yaml without touching the chart itself.
The templates are organized by the order Kubernetes resources naturally depend on each other:
helm/templates/
├── 0_config/ # ConfigMap + Secrets: becomes your app's env vars
├── 1_deployments/ # the server Deployment
├── 2_services/ # the Service exposing it inside the cluster
├── 3_gateways/ # Gateway + HTTPRoute exposing it outside the cluster
└── NOTES.txt # printed after `helm install` (see below)
Configuring values.yaml
host and environment drive most of the chart's other defaults: host sets the auth.audience/auth.issuer claims, the Gateway/HTTPRoute hostname, and the TLS certificate's domain, while environment sets NODE_ENV on the deployment (and, outside production, enables --inspect on the container for remote debugging). auth.secret, cookies.secret, and sessions.secret default to Helm's randAlphaNum 32, a fresh random value generated at install time and preserved across upgrades rather than a value you set. That's deliberate (see Save the install output below).
mongodb.create, postgresql.create, and redis.create only appear in a freshly generated project's values.yaml for the datastores that project actually uses, matching whichever of MongoDB/PostgreSQL/Redis you configured when the project was scaffolded. Set the corresponding create to false and provide a connection URL (mongodb.url/postgresql.url/redis.url) to point at an instance you already run instead of the bundled Bitnami subchart.
Just like Docker Compose, every datastore ends up as a datastores__<name>__<key> environment variable on the pod, sourced from a generated ConfigMap/Secret pair rather than typed in by hand. These are the same nconf keys from Configuration, just populated by Kubernetes instead of Compose.
Parameters
| Name | Description | Value |
|---|---|---|
host | Public hostname the Gateway, HTTPRoute, and TLS certificate are issued for | localhost |
environment | Sets NODE_ENV for the deployment | dev |
auth.audience | JWT audience claim | '{{ .Values.host }}' |
auth.issuer | JWT issuer claim | 'api.{{ .Values.host }}' |
auth.expiresIn | Access token lifetime | 1 hour |
auth.secret | JWT signing secret. Randomly generated at install time and preserved across upgrades | '{{ randAlphaNum 32 }}' |
cookies.secret | Cookie signing secret. Randomly generated at install time and preserved across upgrades | '{{ randAlphaNum 32 }}' |
sessions.secret | Session secret. Randomly generated at install time and preserved across upgrades | '{{ randAlphaNum 32 }}' |
gateway.name | Name of the Gateway the HTTPRoute attaches to. The chart only creates this Gateway itself when the name and namespace are both left at their defaults; point it at an existing Gateway to share one across releases | api-gateway |
gateway.namespace | Namespace of that Gateway | '{{ .Release.Namespace }}' |
gateway.tls | Add an HTTPS listener and request a cert-manager certificate for host. Skipped automatically when host is localhost or ends in .local | true |
gateway.hsts | Keep the Strict-Transport-Security response header. Set to false to strip it, for local or non-TLS testing | true |
redis.create | Deploy a Redis instance via the Bitnami subchart. Present only if your project uses a redis datastore | true |
redis.url | Redis connection URL. Override when redis.create is false to point at an external Redis | redis://db-redis-master |
redis.architecture | Redis architecture, passed through to the Bitnami subchart | standalone |
redis.auth.enabled | Require a password on the bundled Redis | true |
redis.fullnameOverride | Resource name prefix for the bundled Redis subchart | db-redis |
redis.master.persistence.enabled | Enable persistence on the Redis master | false |
redis.replica.persistence.enabled | Enable persistence on Redis replicas | false |
redis.networkPolicy.enabled | Create a NetworkPolicy restricting access to Redis | true |
redis.networkPolicy.allowExternal | Allow traffic from outside the cluster when networkPolicy.enabled is true | false |
mongodb.create | Deploy a MongoDB instance via the Bitnami subchart. Present only if your project uses a mongodb datastore | true |
mongodb.url | MongoDB connection URL, used only when mongodb.create is false | "" |
mongodb.architecture | MongoDB architecture, passed through to the Bitnami subchart | standalone |
mongodb.auth.enabled | Require credentials on the bundled MongoDB | true |
mongodb.fullnameOverride | Resource name prefix for the bundled MongoDB subchart | mongodb |
postgresql.create | Deploy a PostgreSQL instance via the Bitnami subchart. Present only if your project uses a postgres datastore | true |
postgresql.url | PostgreSQL connection URL, used only when postgresql.create is false | "" |
postgresql.architecture | PostgreSQL architecture, passed through to the Bitnami subchart | standalone |
postgresql.fullnameOverride | Resource name prefix for the bundled PostgreSQL subchart | postgresql |
postgresql.auth.enablePostgresUser | Require credentials on the bundled PostgreSQL | true |
postgresql.auth.database | Name of the one database the bundled subchart auto-provisions on first start | your project's name |
service.image.registry | Container image registry | ghcr.io |
service.image.repository | Container image repository | your project's name |
service.image.tag | Container image tag. Defaults to the chart's appVersion when empty | "" |
service.imagePullSecret | Name of an existing image pull secret | "" |
service.replicas | Number of replicas | 1 |
service.resources.requests.cpu | CPU request | 100m |
service.resources.requests.memory | Memory request | 256Mi |
service.resources.limits.memory | Memory limit | 512Mi |
service.mongodb.acl.name | Database name for the ACL datastore | access_control_lists |
service.mongodb.acl.host | Host override for the ACL datastore | "" |
service.mongodb.acl.url | Full connection URL override for the ACL datastore | "" |
service.mongodb.mongo.name | Database name for the application datastore | your project's name |
service.mongodb.mongo.host | Host override for the application datastore | "" |
service.mongodb.mongo.url | Full connection URL override for the application datastore | "" |
service.postgresql.acl.name | Database name for the ACL datastore | postgres |
service.postgresql.acl.host | Host override for the ACL datastore | "" |
service.postgresql.acl.url | Full connection URL override for the ACL datastore | "" |
service.postgresql.sql.name | Database name for the application datastore | your project's name |
service.postgresql.sql.host | Host override for the application datastore | "" |
service.postgresql.sql.url | Full connection URL override for the application datastore | "" |
service.config | Arbitrary key/value pairs merged into the service's environment configuration | {logs: true, metrics: true, releaseNotes: true} |
service.spec | Arbitrary key/value pairs merged into the pod spec, for settings such as nodeSelector or tolerations | {} |
Installing
helm install my-api ./helm
Before your service starts serving traffic, init containers block startup until Redis and whichever of MongoDB/PostgreSQL is bundled respond to a basic connectivity probe. The pod won't report ready before its datastores are actually reachable.
Because auth.secret, the bundled datastore's admin password, and other credentials are randomly generated at install time rather than configured up front, helm install prints them to the terminal exactly once, via NOTES.txt. There's no way to recover them from the cluster afterward except by reading the underlying Secret resources directly. Write them down (or better, pull them into your own secret manager) before you close that terminal.
Routing
The chart uses the Kubernetes Gateway API (a Gateway + HTTPRoute), not a classic Ingress. Your cluster needs a Gateway API-compatible controller installed (the chart assumes an NGINX Gateway Fabric-style gatewayClassName: nginx). TLS termination and HSTS are both configurable via gateway.tls/gateway.hsts in values.yaml.
Trying it locally
If you don't already have a cluster to deploy to, helm/scripts/k3s_install.sh sets up a single-node k3s cluster with the prerequisites this chart expects (a Gateway API controller, the Bitnami Helm repo, and so on), a reasonable way to try a full Helm deployment on a single machine before deploying to a real cluster.