Deploying with Helm
The chart at deploy/chart/ is the deploy primitive: one chart serves both
disposable per-PR previews and production. It runs the
container image; the live
per-PR preview environments are its first consumer, and
production reuses it unchanged by flipping two values.
Two modes
Section titled “Two modes”| Mode | postgres.enabled | bootstrap.enabled | Database |
|------|--------------------|---------------------|----------|
| Preview (default) | true | true | bundled, ephemeral (emptyDir) |
| Production | false | false | external, via externalDsn |
The bundled Postgres is deliberately ephemeral: its data is an emptyDir and
does not survive a pod restart, which is what you want for a throwaway preview.
Production points at a real, managed Postgres.
Install
Section titled “Install”Preview (bundled Postgres, an auto-created owner):
helm install og-pr-42 deploy/chart -n og-pr-42 --create-namespace \ --set image.tag=sha-<full-sha>Production (BYO Postgres, no auto-owner):
helm install omniglass deploy/chart -n omniglass --create-namespace \ --set postgres.enabled=false \ --set externalDsn='postgres://user:pass@db:5432/omniglass?sslmode=require' \ --set bootstrap.enabled=false \ --set image.tag=<release>How it boots
Section titled “How it boots”The server Deployment gates startup with init containers rather than Helm pre-install hooks, because a bundled Postgres in the same release is not up during the pre-install phase:
wait-for-db(only whenpostgres.enabled) blocks until Postgres answers.migrateapplies the schema (idempotent: dbmate runs each migration once).bootstrap(only whenbootstrap.enabled) creates the first owner and mints its bearer token, printed once to this container’s logs. Idempotent: a restart mints no second token.
Both migrate and bootstrap are safe to re-run on every rollout. At
server.replicas > 1 in production, run migrate as a separate one-shot Job
instead, to avoid concurrent migrators.
Values
Section titled “Values”| Key | Default | Purpose |
|-----|---------|---------|
| image.repository | ghcr.io/hyperscaleav/omniglass | image to run |
| image.tag | latest | pin to sha-<full-sha> for an exact, immutable build |
| image.pullPolicy | IfNotPresent | |
| server.replicas | 1 | server pod count |
| server.resources | small requests/limits | |
| service.port | 8080 | ClusterIP service port |
| ingress.enabled | false | create an Ingress (on for per-PR previews) |
| ingress.className | traefik | ingress controller class |
| ingress.host | empty | required when ingress.enabled; the public host |
| bootstrap.enabled | true | auto-create an owner (previews) |
| bootstrap.username | preview | owner username |
| bootstrap.email / bootstrap.displayName | empty / Preview Owner | optional owner fields |
| postgres.enabled | true | bundle an ephemeral Postgres |
| postgres.image / user / password / database | postgres:18 / omniglass x3 | bundled Postgres settings |
| postgres.resources | small requests/limits | bound the throwaway DB |
| externalDsn | empty | required when postgres.enabled is false |
| server.secureCookies | true | marks session cookies Secure (https-only); set false only for a plaintext-http deployment |
| nameOverride | empty | override the chart name in resource names |
| fullnameOverride | empty | override resource names outright; default release-named resources keep preview service DNS predictable (e.g. og-pr-42) |
Server environment
Section titled “Server environment”Anything the chart’s values do not cover reaches the server as plain environment (via
extraEnv-style values or a Secret). The full server surface renders from the declared
environment registry (make gen); behind edge TLS, set OMNIGLASS_SECURE_COOKIES=true and point
OMNIGLASS_SECRET_KEY_FILE at a mounted key:
| Variable | Default | Purpose |
|---|---|---|
OMNIGLASS_DSN | local dev DSN | Postgres connection string the Storage Gateway dials; wins over DATABASE_URL when both are set |
DATABASE_URL | (none) | conventional DSN fallback, used when OMNIGLASS_DSN is unset |
OMNIGLASS_ADDR | :8080 | HTTP listen address |
OMNIGLASS_SECURE_COOKIES | off | set true behind TLS to mark the session cookie Secure (https only) |
OMNIGLASS_NATS_ADDR | 127.0.0.1:4222 | listen address (host:port) of the embedded NATS server |
OMNIGLASS_NATS_STORE_DIR | temp dir | JetStream store directory |
OMNIGLASS_NATS_URL | nats://127.0.0.1:4222 | bus URL the node-claim exchange advertises to nodes |
OMNIGLASS_DATA_DIR | .omniglass | local non-Postgres server state (notably the fallback secret key) |
OMNIGLASS_SETTINGS_FILE | (none) | optional operator settings file (JSON or YAML), the layer between code defaults and the DB override |
OMNIGLASS_SECRET_KEY | (none) | base64 32-byte key-encryption key for secrets at rest; wins over the key file |
OMNIGLASS_SECRET_KEY_FILE | (none) | path to the key-encryption key; the intended production source (the generated fallback under the data dir is convenience, not security) |
Exposure
Section titled “Exposure”By default the chart creates no Ingress: the standing deploy is reached by port-forward (or a cloudflared route dialing the ClusterIP Service directly).
kubectl -n omniglass port-forward svc/omniglass 8080:8080kubectl -n omniglass logs deploy/omniglass -c bootstrap # the one-time tokenFor per-PR previews, set ingress.enabled=true and an ingress.host. The chart
then emits a plain-HTTP Ingress (class traefik) that the in-cluster controller
Host-routes; the shared cloudflared tunnel fronts it with one wildcard route and
terminates TLS at the edge, so the Ingress carries no tls block.
helm install og-pr-42 deploy/chart -n og-pr-42 --create-namespace \ --set image.tag=sha-<full-sha> \ --set ingress.enabled=true \ --set ingress.host=og-pr-42.preview.hyperscaleav.com \ --set fullnameOverride=omniglass