Helm chart for deploying the formae infrastructure-as-code agent on Kubernetes with optional PostgreSQL, OpenTelemetry, and Grafana dashboards.
| Tier | Components | Example |
|---|---|---|
| Standalone | formae agent (SQLite) | examples/formae-only.yaml |
| With database | formae + PostgreSQL | examples/formae-db.yaml |
| With auth | formae + PostgreSQL + basic auth | examples/formae-basic-auth.yaml |
| Full observability | formae + PostgreSQL + OTel + Grafana dashboards | examples/formae-db-grafana.yaml |
| Custom config | Bring your own formae.conf.pkl |
examples/formae-custom-config.yaml |
helm install formae . -f examples/formae-only.yamlWith PostgreSQL:
helm install formae . -f examples/formae-db.yaml \
--set postgresql.auth.password=changemeFull monitoring stack (requires Prometheus + Grafana already running):
helm install formae . -f examples/formae-db-grafana.yaml \
--set postgresql.auth.password=changemeSee examples/quickstart-monitoring.yaml for a step-by-step guide to deploying the monitoring stack from scratch.
| Parameter | Description | Default |
|---|---|---|
formae.datastore.type |
Backend type: postgres, sqlite, auroradataapi |
postgres |
formae.datastore.sqlite.filePath |
SQLite database path | /data/formae.db |
formae.datastore.postgres.host |
External PostgreSQL host (when postgresql.enabled=false) |
"" |
formae.datastore.auroraDataAPI.clusterARN |
Aurora cluster ARN | "" |
| Parameter | Description | Default |
|---|---|---|
postgresql.enabled |
Deploy PostgreSQL alongside formae | true |
postgresql.image.tag |
PostgreSQL image tag | 15-alpine |
postgresql.auth.username |
Database user | formae |
postgresql.auth.password |
Database password (set via --set) |
"" |
postgresql.auth.database |
Database name | formae |
postgresql.auth.existingSecret |
Use an existing Secret for the password | "" |
postgresql.persistence.enabled |
Enable persistent storage | true |
postgresql.persistence.size |
PVC size | 8Gi |
| Parameter | Description | Default |
|---|---|---|
formae.auth.enabled |
Enable basic authentication for the agent API | false |
formae.auth.basic.username |
Auth username | "" |
formae.auth.basic.password |
Auth password (bcrypt hash) | "" |
formae.auth.basic.existingSecret |
Use an existing Secret for credentials | "" |
formae.auth.basic.usernameKey |
Key in the existing Secret for username | username |
formae.auth.basic.passwordKey |
Key in the existing Secret for password | password |
Generate a bcrypt hash with:
htpasswd -bnBC 10 "" yourPassword | tr -d ':\n'Notes:
- Requires formae >= 0.84.0. Earlier images ship the legacy in-binary auth plugin, which the agent no longer loads. Set
image.tagaccordingly if the chart'sappVersionis older. - The
auth-basicplugin ships in the formae image (part of thestandardmetapackage), so no extra install is needed. The agent refuses to start if auth is configured but the plugin is missing. /api/v1/healthstays unauthenticated, so the defaulthttpGetprobes and thehelm testhook keep working.- The chart configures the agent side only. To use the
formaeCLI against an authenticated agent, addcli.auth(with the plaintext password, not the hash) to your localformae.conf.pkl.
Example with inline credentials:
helm install formae . -f examples/formae-basic-auth.yaml \
--set postgresql.auth.password=changeme \
--set-string formae.auth.basic.username=admin \
--set-string formae.auth.basic.password='$2y$10$...'Example with an existing Kubernetes Secret:
formae:
auth:
enabled: true
basic:
existingSecret: my-auth-secret
usernameKey: username
passwordKey: passwordInstead of using chart values to build formae.conf.pkl, you can provide the entire config as a string via formae.existingConfig. When set, all other formae.* values (auth, datastore, server, etc.) are ignored.
| Parameter | Description | Default |
|---|---|---|
formae.existingConfig |
Full formae.conf.pkl content as a string |
"" |
Use read("env:...") in your PKL to reference secrets, and inject them via extraEnv:
formae:
existingConfig: |
amends "formae:/Config.pkl"
agent {
server { port = 49684 }
datastore {
datastoreType = "postgres"
postgres {
host = "my-db"
password = read("env:FORMAE_DB_PASSWORD")
}
}
auth {
type = "auth-basic"
authorizedUsers = new Listing {
new Mapping {
["Username"] = read("env:FORMAE_AUTH_USERNAME")
["Password"] = read("env:FORMAE_AUTH_PASSWORD")
}
}
}
}
extraEnv:
- name: FORMAE_DB_PASSWORD
valueFrom:
secretKeyRef:
name: my-db-secret
key: password
- name: FORMAE_AUTH_USERNAME
valueFrom:
secretKeyRef:
name: my-auth-secret
key: username
- name: FORMAE_AUTH_PASSWORD
valueFrom:
secretKeyRef:
name: my-auth-secret
key: passwordSee examples/formae-custom-config.yaml for a complete example.
| Parameter | Description | Default |
|---|---|---|
initContainers |
Init containers rendered verbatim into the agent Pod | [] |
Waiting for the database removes the one crash-and-restart that otherwise happens on a fresh install, where the agent starts before PostgreSQL accepts connections:
initContainers:
- name: wait-for-postgresql
image: busybox
command: ["sh", "-c", "until nc -z formae-postgresql 5432; do sleep 2; done"]Installing extra plugins means mounting a volume over the image's plugin
directory, which hides the plugins that ship in the image (aws, azure,
gcp, k8s, auth-basic). Copy them into the volume first, or the agent loses
them — with formae.auth.enabled it then refuses to start entirely:
initContainers:
- name: install-custom-plugin
image: ghcr.io/platform-engineering-labs/formae:0.88.1
command:
- sh
- -c
## cp -R, not cp -a: preserving timestamps on the volume root fails as non-root
- cp -R /opt/pel/formae/plugins/. /plugins/ && cp -R /plugin/. /plugins/
volumeMounts:
- name: plugins
mountPath: /plugins
extraVolumes:
- name: plugins
emptyDir: {}
extraVolumeMounts:
- name: plugins
mountPath: /opt/pel/formae/pluginspodSecurityContext applies to init containers too, so their images must run as
uid 1001 and cannot be root.
| Parameter | Description | Default |
|---|---|---|
formae.otel.enabled |
Enable OpenTelemetry instrumentation | false |
formae.otel.otlp.endpoint |
OTLP receiver endpoint | localhost:4317 |
formae.otel.otlp.protocol |
OTLP protocol (grpc or http) |
grpc |
formae.otel.prometheus.enabled |
Enable Prometheus metrics export | false |
otelCollector.enabled |
Deploy OTel Collector as sidecar | false |
| Parameter | Description | Default |
|---|---|---|
grafana.dashboards.enabled |
Create dashboard ConfigMaps | true |
grafana.dashboards.label |
Label for Grafana sidecar discovery | grafana_dashboard |
grafana.dashboards.labelValue |
Label value | "1" |
grafana.dashboards.folder |
Grafana folder name | formae |
Sizing recommendations from the formae docs:
| Managed Resources | Memory | CPU |
|---|---|---|
| up to 1,000 | 512Mi | 1 |
| 1,000 - 5,000 | 1Gi | 2 |
| 5,000 - 10,000 | 1.5Gi | 2-4 |
| 10,000 - 20,000 | 2Gi | 4 |
| File | Description |
|---|---|
formae-only.yaml |
SQLite, ephemeral storage |
formae-only-persistent.yaml |
SQLite with PVC |
formae-db.yaml |
In-cluster PostgreSQL |
formae-db-grafana.yaml |
PostgreSQL + Grafana + OTel |
formae-basic-auth.yaml |
Basic authentication |
formae-custom-config.yaml |
Bring your own formae.conf.pkl |
formae-external-db.yaml |
External PostgreSQL |
formae-external-db-grafana.yaml |
External PostgreSQL + Grafana + OTel |
formae-aurora.yaml |
Aurora Data API |
quickstart-monitoring.yaml |
Full monitoring stack walkthrough |