Helm values
Every value in the obleth Helm chart (deploy/k8s/obleth/values.yaml), its default, and what it sets in the rendered objects.
14 min readUpdated for v2.4.0Edit on GitHub
The chart is published at oci://ghcr.io/thediymaker/charts/obleth; chart
version and appVersion are both 2.4.0.
helm install obleth oci://ghcr.io/thediymaker/charts/obleth \
--version 2.4.0 \
--namespace obleth --create-namespace \
--set obleth.adminToken=$(openssl rand -hex 32) \
--set postgres.password=$(openssl rand -hex 16) \
--set redis.password=$(openssl rand -hex 16) \
--set clickhouse.password=$(openssl rand -hex 16) \
--set controlPlane.dashboardPassword='change-me-now' \
--set controlPlane.dashboardSessionSecret=$(openssl rand -hex 32) \
-f my-values.yaml
--set values end up in shell history and the release record. In production,
create the Secrets yourself and name them in
existingSecret. Upgrading from 1.x
changes the Secret keys; see Upgrading from v1.x.
Required values
Rendering fails with a message when one of these is missing.
| Value | Required when |
|---|---|
obleth.adminToken | Always, unless obleth.existingSecret |
postgres.password | postgres.enabled, unless obleth.existingSecret |
redis.password | redis.enabled, unless obleth.existingSecret |
clickhouse.password | clickhouse.enabled, unless obleth.existingSecret |
controlPlane.dashboardPassword | controlPlane.enabled, unless controlPlane.existingSecret |
controlPlane.dashboardSessionSecret | Same as above |
postgres.external.url | postgres.enabled: false, unless obleth.existingSecret |
redis.external.url | redis.enabled: false, unless obleth.existingSecret |
clickhouse.external.url | clickhouse.enabled: false |
obleth.upstreamBaseUrl | benchmarkBackend.enabled: false |
redis.maxmemory | redis.enabled (default 400mb) |
redis.password goes unescaped into OBLETH_REDIS_URL, so rendering also fails
if it contains @, :, /, ?, #, % or whitespace. Use hex
(openssl rand -hex 16). The dashboard enforces the lengths itself:
dashboardSessionSecret must be at least 32 characters, and a
dashboardPassword under 8 characters is not seeded.
Gateway
Values for the gateway Deployment (<release>-obleth) and the objects around
it. Fairshare limits are cluster-wide across replicas; see
Fairshare engine and
Scaling.
| Value | Default | What it sets |
|---|---|---|
obleth.replicas | 1 | Gateway pods; ignored when hpa.enabled |
obleth.globalMaxInFlight | 4096 | Ceiling across all model pools, cluster-wide |
obleth.defaultModelMaxInFlight | 32 | Pool size for a model with no max_in_flight |
obleth.fairshareSharedSlots | true | Limits held as Redis slots shared by all replicas |
obleth.fairshareReplicaAware | true | Each replica takes ceil(limit / replicas) when shared slots are off or Redis is down |
obleth.fairshareReplicaHeartbeatSecs | 5 | Replica heartbeat and slot re-assert interval |
obleth.fairshareReplicaTtlSecs | 15 | How long a heartbeat counts; raised to at least 2× the interval |
obleth.fairshareHistorySecs | 3600 | Fairshare activity history kept in memory; 0 off |
obleth.fairshareSessionAffinity.enabled | false | Favour warm agent sessions in each pool; see Session affinity |
obleth.fairshareSessionAffinity.warmSecs | 120 | How long after its last step a session counts as warm |
obleth.fairshareSessionAffinity.holdMs | 3000 | How long a looping session's slot is held for its next step; 0 holds nothing |
obleth.fairshareSessionAffinity.maxJumps | 8 | Times a queued request may be passed by later requests of its key |
obleth.fairshareSessionAffinity.maxBypassSecs | 30 | Wait after which nothing passes a request |
obleth.fairshareSessionAffinity.maxHeldPercent | 25 | Most of a pool's slots held at once |
obleth.failOpen | true | Admit a request when its Redis budget check fails; false rejects it |
obleth.adminToken | "" | Management API token (Secret); required |
obleth.encryptionKey | "" | Base64 of 32 bytes; encrypts model and MCP credentials at rest. Empty stores them in plain text |
obleth.apiKeyPepper | "" | Pepper mixed into API key hashes; changing it invalidates every secret key |
obleth.jwtIssuers | "" | JSON array of trusted identity token issuers; empty turns the path off |
obleth.existingSecret | "" | Pre-created Secret used instead of the chart's |
obleth.allowedPrivateCidrs | "" | CIDRs allowed when strict outbound-URL mode is on |
obleth.upstreamBaseUrl | "" | Default upstream; empty uses the benchmark backend |
obleth.otelEndpoint | "" | OTLP trace endpoint; empty turns tracing off |
obleth.slackWebhookUrl | "" | Slack webhook seeded into alert settings on first boot (Secret) |
obleth.slackAlertMinIntervalSecs | 300 | Minimum gap between repeats of one alert |
obleth.modelHealthEnabled | true | Background model health checks |
obleth.modelHealthIntervalSecs | 900 | Health check interval |
obleth.modelHealthTimeoutSecs | 30 | Health check timeout |
obleth.modelHealthRetentionDays | 30 | Days of health check history kept |
obleth.usageRetentionDays | 180 | Days of per-request usage rows kept in ClickHouse |
obleth.telemetryFlushIntervalMs | 5000 | How long each gateway pod buffers usage rows and spans before inserting them, 100–60000 ms. Fewer, larger inserts cost ClickHouse much less merge I/O; rows reach the dashboard up to this long after a request ends |
obleth.shutdownGraceSecs | 300 | Drain time on SIGTERM; keep below 310 (see below) |
obleth.redisRewarmSecs | 300 | Postgres-to-Redis re-push interval; 0 off |
obleth.upstreamTimeoutSecs | 300 | Wait for upstream response headers |
obleth.upstreamReadTimeoutSecs | "" | Longest upstream silence; empty is the upstream timeout, at least 120 s; 0 off |
obleth.redisResponseTimeoutMs | 250 | Redis command timeout |
obleth.redisConnectTimeoutMs | 2000 | Redis connect timeout |
obleth.admissionTimeoutSecs | 60 | Queue wait before 503 with Retry-After: 5 |
obleth.videoJobRetentionHours | 24 | How long a video job record is kept |
obleth.videoJobScope | key | Who sees a video job: key or tenant (video generation) |
obleth.resources | requests 250m / 256Mi, limits 2 / 1Gi | Gateway container resources |
obleth.capacityDiscovery.enabled | false | Pool sizes from the backend for discovered models (pool sizes) |
obleth.capacityDiscovery.intervalSecs | 15 | How often each replica re-reads capacity |
obleth.capacityDiscovery.namespaces | [] | Namespaces the kubernetes source reads; also where RBAC is rendered |
obleth.capacityDiscovery.defaultService | "" | Service name template ({upstream_model}, {model_name}) for models without capacity_service |
image.obleth | ghcr.io/thediymaker/obleth-gateway/obleth | Gateway image |
image.controlPlane | ghcr.io/thediymaker/obleth-gateway/control-plane | Dashboard image |
image.provisioner | ghcr.io/thediymaker/obleth-gateway/obleth-provisioner | Provisioner image |
image.benchmarkBackend | ghcr.io/thediymaker/obleth-gateway/benchmark-backend | Benchmark backend image |
image.tag | "" | Tag for the four images above and the compressor; empty is v2.4.0 |
image.pullPolicy | IfNotPresent | Pull policy for those images |
hpa.enabled | false | CPU HorizontalPodAutoscaler for the gateway |
hpa.minReplicas | 1 | HPA minimum |
hpa.maxReplicas | 20 | HPA maximum |
hpa.targetCPUUtilizationPercentage | 70 | HPA CPU target |
affinity.antiAffinity | soft | Spread gateway pods over nodes: soft, hard, or "" off |
podDisruptionBudget.enabled | true | PDB, rendered only when the minimum replica count is above 1 |
podDisruptionBudget.minAvailable | 1 | PDB minAvailable |
nodeResolution.hostAliases | [] | /etc/hosts entries on gateway and provisioner pods |
nodeResolution.dnsConfig | {} | Resolver for gateway and provisioner pods |
nodeResolution.dnsPolicy | "" | dnsPolicy override, such as None |
serviceMonitor.enabled | false | ServiceMonitor scraping metrics every 5 s; needs the Prometheus Operator CRDs |
shutdownGraceSecs plus the 5 s preStop delay, 20 s telemetry drain and 10 s
OTLP flush must fit in the fixed terminationGracePeriodSeconds: 345. The
minimum replica count for the PDB is hpa.minReplicas with the HPA on, else
obleth.replicas. Capacity discovery RBAC (a ServiceAccount, plus a Role and
RoleBinding per namespace granting only get, list, watch on
endpointslices) is rendered only when enabled is true and namespaces is
not empty. nodeResolution helps the pods reach
Slurm compute nodes.
Gateway environment mapping
What the gateway container gets. Any other variable takes its default from
Environment variables; to set one, add
it as a key in the obleth.existingSecret Secret, which reaches the container
through envFrom.
| Variable | Set from |
|---|---|
OBLETH_PROXY_LISTEN | Fixed 0.0.0.0:8080 |
OBLETH_ADMIN_LISTEN | Fixed 0.0.0.0:9180 |
OBLETH_METRICS_LISTEN | Fixed 0.0.0.0:9091 |
OBLETH_UPSTREAM_BASE_URL | obleth.upstreamBaseUrl, else http://<release>-benchmark-backend:8081 |
OBLETH_GLOBAL_MAX_IN_FLIGHT | obleth.globalMaxInFlight |
OBLETH_DEFAULT_MODEL_MAX_IN_FLIGHT | obleth.defaultModelMaxInFlight |
OBLETH_FAIRSHARE_HISTORY_SECS | obleth.fairshareHistorySecs |
OBLETH_FAIRSHARE_SHARED_SLOTS | obleth.fairshareSharedSlots |
OBLETH_FAIRSHARE_REPLICA_AWARE | obleth.fairshareReplicaAware |
OBLETH_FAIRSHARE_REPLICA_HEARTBEAT_SECS | obleth.fairshareReplicaHeartbeatSecs |
OBLETH_FAIRSHARE_REPLICA_TTL_SECS | obleth.fairshareReplicaTtlSecs |
OBLETH_FAIRSHARE_SESSION_AFFINITY | obleth.fairshareSessionAffinity.enabled |
OBLETH_FAIRSHARE_SESSION_AFFINITY_WARM_SECS | obleth.fairshareSessionAffinity.warmSecs |
OBLETH_FAIRSHARE_SESSION_AFFINITY_HOLD_MS | obleth.fairshareSessionAffinity.holdMs |
OBLETH_FAIRSHARE_SESSION_AFFINITY_MAX_JUMPS | obleth.fairshareSessionAffinity.maxJumps |
OBLETH_FAIRSHARE_SESSION_AFFINITY_MAX_BYPASS_SECS | obleth.fairshareSessionAffinity.maxBypassSecs |
OBLETH_FAIRSHARE_SESSION_AFFINITY_MAX_HELD_PERCENT | obleth.fairshareSessionAffinity.maxHeldPercent |
OBLETH_CAPACITY_DISCOVERY_ENABLED | obleth.capacityDiscovery.enabled |
OBLETH_CAPACITY_DISCOVERY_INTERVAL_SECS | obleth.capacityDiscovery.intervalSecs |
OBLETH_CAPACITY_DISCOVERY_NAMESPACES | obleth.capacityDiscovery.namespaces, de-duplicated, comma-joined |
OBLETH_CAPACITY_DEFAULT_SERVICE | obleth.capacityDiscovery.defaultService |
OBLETH_FAIL_OPEN | obleth.failOpen |
OBLETH_ALLOWED_PRIVATE_CIDRS | obleth.allowedPrivateCidrs |
OBLETH_MODEL_HEALTH_ENABLED | obleth.modelHealthEnabled |
OBLETH_MODEL_HEALTH_INTERVAL_SECS | obleth.modelHealthIntervalSecs |
OBLETH_MODEL_HEALTH_TIMEOUT_SECS | obleth.modelHealthTimeoutSecs |
OBLETH_MODEL_HEALTH_RETENTION_DAYS | obleth.modelHealthRetentionDays |
OBLETH_USAGE_RETENTION_DAYS | obleth.usageRetentionDays |
OBLETH_TELEMETRY_FLUSH_INTERVAL_MS | obleth.telemetryFlushIntervalMs |
OBLETH_OTEL_ENDPOINT | obleth.otelEndpoint |
OBLETH_SLACK_ALERT_MIN_INTERVAL_SECS | obleth.slackAlertMinIntervalSecs |
OBLETH_SHUTDOWN_GRACE_SECS | obleth.shutdownGraceSecs |
OBLETH_REDIS_REWARM_SECS | obleth.redisRewarmSecs |
OBLETH_UPSTREAM_TIMEOUT_SECS | obleth.upstreamTimeoutSecs |
OBLETH_UPSTREAM_READ_TIMEOUT_SECS | obleth.upstreamReadTimeoutSecs |
OBLETH_REDIS_RESPONSE_TIMEOUT_MS | obleth.redisResponseTimeoutMs |
OBLETH_REDIS_CONNECT_TIMEOUT_MS | obleth.redisConnectTimeoutMs |
OBLETH_ADMISSION_TIMEOUT_SECS | obleth.admissionTimeoutSecs |
OBLETH_VIDEO_JOB_RETENTION_HOURS | obleth.videoJobRetentionHours |
OBLETH_VIDEO_JOB_SCOPE | obleth.videoJobScope; empty renders key |
OBLETH_CLICKHOUSE_URL | http://<release>-clickhouse:8123, or clickhouse.external.url |
OBLETH_CLICKHOUSE_DB | clickhouse.db |
OBLETH_CLICKHOUSE_USER | clickhouse.user |
OBLETH_WAL_PATH | Fixed /var/lib/obleth/telemetry.wal |
OBLETH_COMPRESSOR_URL | http://<release>-compressor:8080 when compressor.enabled |
RUST_LOG | Fixed info,obleth=info |
OBLETH_ADMIN_TOKEN | Secret: obleth.adminToken |
OBLETH_DATABASE_URL | Secret: postgres://<user>:<password>@<release>-postgres:5432/<db>, or postgres.external.url |
OBLETH_REDIS_URL | Secret: redis://:<password>@<release>-redis:6379, or redis.external.url |
OBLETH_CLICKHOUSE_PASSWORD | Secret: clickhouse.password |
OBLETH_ENCRYPTION_KEY | Secret: obleth.encryptionKey |
OBLETH_API_KEY_PEPPER | Secret: obleth.apiKeyPepper |
OBLETH_SLACK_WEBHOOK_URL | Secret: obleth.slackWebhookUrl |
OBLETH_JWT_ISSUERS | Secret: obleth.jwtIssuers |
Pre-created Secrets (existingSecret)
When obleth.existingSecret names a Secret, the chart renders none of its own
and every pod reads that one. It must carry these keys:
| Key | Needed | Read by |
|---|---|---|
OBLETH_ADMIN_TOKEN | Always | Gateway, dashboard, provisioner |
OBLETH_DATABASE_URL | Always | Gateway |
OBLETH_REDIS_URL | Always; with bundled Redis, redis://:<REDIS_PASSWORD>@<release>-redis:6379 | Gateway |
OBLETH_CLICKHOUSE_PASSWORD | Always (may be empty for an external ClickHouse without one) | Gateway; bundled ClickHouse |
OBLETH_ENCRYPTION_KEY | Always (may be empty) | Gateway |
OBLETH_API_KEY_PEPPER | Always (may be empty) | Gateway |
OBLETH_SLACK_WEBHOOK_URL | Always (may be empty) | Gateway |
OBLETH_JWT_ISSUERS | Optional | Gateway |
POSTGRES_PASSWORD | postgres.enabled | Bundled Postgres |
REDIS_PASSWORD | redis.enabled | Bundled Redis |
controlPlane.existingSecret works the same way for the dashboard and must
carry DASHBOARD_PASSWORD, DASHBOARD_SESSION_SECRET, DATABASE_URL,
BETTER_AUTH_SECRET (falls back to DASHBOARD_SESSION_SECRET when absent),
BETTER_AUTH_URL, TRUSTED_ORIGINS, DASHBOARD_ADMIN_EMAIL and
OIDC_PROVIDERS.
The gateway, Redis and ClickHouse pods carry a checksum/secret annotation, so
a change to the chart's Secret rolls them. With existingSecret the checksum
never changes: restart the Deployments yourself after editing the Secret. The
gateway reads OBLETH_JWT_ISSUERS only at start. Start from
values-production.yaml.
Datastores
Each bundled datastore is a single-replica Deployment with the Recreate
strategy and a readiness probe (every 5 s, 3 s timeout). Set
persistence.enabled: false for an emptyDir that loses data on restart, or
enabled: false plus external.url to use your own. Overlays for each case are
in deploy/k8s/obleth/examples/.
| Value | Default | What it sets |
|---|---|---|
datastores.nodeSelector | {} | Node selector for the bundled Postgres, Redis and ClickHouse, e.g. nodes whose storage can attach their volumes |
datastores.tolerations | [] | Tolerations for the same three |
postgres.enabled | true | Bundled Postgres |
postgres.image | postgres:16 | Image |
postgres.user | obleth | POSTGRES_USER and the database URL user |
postgres.password | "" | POSTGRES_PASSWORD (Secret); required when bundled |
postgres.db | obleth | POSTGRES_DB |
postgres.resources | requests 250m / 512Mi, limits 500m / 1Gi | Container resources |
postgres.persistence.enabled | true | PVC; false uses emptyDir |
postgres.persistence.size | 10Gi | PVC size |
postgres.persistence.storageClass | "" | StorageClass; empty is the cluster default |
postgres.persistence.accessMode | ReadWriteOnce | PVC access mode |
postgres.external.url | "" | Database URL when enabled: false |
redis.enabled | true | Bundled Redis |
redis.image | redis:7 | Image |
redis.password | "" | --requirepass and the URL password (Secret); required when bundled |
redis.resources | requests 100m / 128Mi, limits 200m / 512Mi | Container resources |
redis.maxmemory | 400mb | --maxmemory; keep near 80% of the memory limit |
redis.persistence.enabled | true | PVC for the append-only file |
redis.persistence.size | 1Gi | PVC size |
redis.persistence.storageClass | "" | StorageClass |
redis.persistence.accessMode | ReadWriteOnce | PVC access mode |
redis.external.url | "" | redis://:PASSWORD@host:6379 when enabled: false (Secret) |
clickhouse.enabled | true | Bundled ClickHouse |
clickhouse.image | clickhouse/clickhouse-server:24.8 | Image |
clickhouse.db | obleth | CLICKHOUSE_DB and OBLETH_CLICKHOUSE_DB |
clickhouse.user | obleth | CLICKHOUSE_USER and OBLETH_CLICKHOUSE_USER |
clickhouse.password | "" | OBLETH_CLICKHOUSE_PASSWORD (Secret); required when bundled |
clickhouse.resources | requests 500m / 2Gi, limits 1 / 4Gi | Container resources |
clickhouse.systemLogRetentionDays | 7 | Days of the bundled ClickHouse's own system log tables kept (query_log, part_log, metric_log, text_log and the rest); at least 1 |
clickhouse.logLevel | information | ClickHouse server log level; text_log keeps warnings and errors only |
clickhouse.persistence.enabled | true | PVC |
clickhouse.persistence.size | 20Gi | PVC size |
clickhouse.persistence.storageClass | "" | StorageClass |
clickhouse.persistence.accessMode | ReadWriteOnce | PVC access mode |
clickhouse.external.url | "" | http://host:8123 when enabled: false |
The bundled Redis runs with the append-only file on, a password, and
--maxmemory-policy volatile-lru: only keys with a TTL are evicted. API keys,
model routes, MCP servers and committed term-budget usage have none and stay.
When nothing is left to evict, Redis refuses writes, which the gateway treats
as a Redis failure (see obleth.failOpen). An external Redis must be a single
primary; Redis Cluster is not supported. Redis is rebuilt from Postgres after
data loss. See Redis layout.
Dashboard, provisioner and sidecars
| Value | Default | What it sets |
|---|---|---|
controlPlane.enabled | true | Dashboard Deployment and Service (port 3000) |
controlPlane.replicas | 1 | Dashboard pods |
controlPlane.dashboardPassword | "" | DASHBOARD_PASSWORD: break-glass admin password, at least 8 characters |
controlPlane.dashboardSessionSecret | "" | DASHBOARD_SESSION_SECRET and BETTER_AUTH_SECRET, at least 32 characters |
controlPlane.existingSecret | "" | Pre-created dashboard Secret |
controlPlane.databaseUrl | "" | DATABASE_URL; empty is the bundled Postgres URL |
controlPlane.betterAuthUrl | "" | BETTER_AUTH_URL: the browser-facing dashboard URL, used for SSO redirects |
controlPlane.trustedOrigins | "" | TRUSTED_ORIGINS: extra sign-in origins, comma-separated |
controlPlane.dashboardAdminEmail | admin@example.com | DASHBOARD_ADMIN_EMAIL: break-glass admin email |
controlPlane.oidcProviders | "" | OIDC_PROVIDERS: JSON array of SSO providers (Dashboard SSO) |
controlPlane.resources | requests 100m / 256Mi, limits 1 / 512Mi | Container resources |
provisioner.enabled | false | Slurm provisioner Deployment |
provisioner.intervalSecs | 15 | OBLETH_PROVISIONER_INTERVAL_SECS: reconcile interval |
provisioner.restartAfterFailures | 20 | OBLETH_PROVISIONER_RESTART_AFTER_FAILURES: net failed probes before a restart; 0 off |
provisioner.logLevel | info,obleth_provisioner=debug | RUST_LOG |
provisioner.resources | requests 50m / 64Mi, limits 500m / 256Mi | Container resources |
compressor.enabled | false | Compression sidecar and OBLETH_COMPRESSOR_URL on the gateway |
compressor.replicas | 1 | Sidecar pods; ignored when autoscaling |
compressor.numThreads | 4 | COMPRESSOR_NUM_THREADS and OMP_NUM_THREADS; keep equal to the CPU limit |
compressor.image.repository | ghcr.io/thediymaker/obleth-gateway/obleth-compressor | Image |
compressor.image.tag | "" | Tag; empty follows image.tag, else v2.4.0 |
compressor.image.pullPolicy | "" | Pull policy; empty follows image.pullPolicy |
compressor.resources | requests 4 / 1536Mi, limits 4 / 2Gi | Container resources |
compressor.autoscaling.enabled | false | CPU HorizontalPodAutoscaler for the sidecar |
compressor.autoscaling.minReplicas | 1 | HPA minimum |
compressor.autoscaling.maxReplicas | 5 | HPA maximum |
compressor.autoscaling.targetCPUUtilizationPercentage | 70 | HPA CPU target |
benchmarkBackend.enabled | true | Synthetic backend; turn off in production |
benchmarkBackend.ttftMs | 20 | BENCHMARK_BACKEND_TTFT_MS |
benchmarkBackend.tokenMs | 3 | BENCHMARK_BACKEND_TOKEN_MS |
benchmarkBackend.concurrency | 256 | BENCHMARK_BACKEND_CONCURRENCY |
The dashboard and provisioner get OBLETH_ADMIN_BASE_URL
(http://<release>-obleth:9180) and read OBLETH_ADMIN_TOKEN from the gateway
Secret; the dashboard also gets OBLETH_PROXY_BASE_URL (:8080). The
provisioner only deploys the reconciler; its Slurm connection is set in the
dashboard (Slurm provisioning). The
compressor holds about 900 MB of model per pod and one inference saturates near
four cores, so scale it with replicas, not bigger pods. The gateway works
without it.
Ingress
| Value | Default | What it sets |
|---|---|---|
ingress.enabled | false | Ingress to the gateway Service |
ingress.className | "" | ingressClassName |
ingress.host | obleth.example.com | Rule host, path / |
ingress.servicePort | 8080 | Backend port; keep the data plane, never 9180 |
ingress.annotations | {} | Ingress annotations |
ingress.tls | [] | TLS blocks, such as [{ secretName: obleth-tls, hosts: [obleth.example.com] }] |
The chart does not deploy HAProxy.
Security contexts (Pod Security Standard)
| Value | Default | What it sets |
|---|---|---|
podSecurityContext | runAsNonRoot: true, seccompProfile: RuntimeDefault | Pod security context |
securityContext | allowPrivilegeEscalation: false, drop ALL, runAsNonRoot: true | Container security context; readOnlyRootFilesystem is opt-in |
networkPolicy.enabled | false | NetworkPolicies below; needs a CNI that enforces them |
Both contexts apply to the gateway, dashboard, provisioner, compressor and
benchmark backend, and meet the Kubernetes
restricted
standard. No UID is pinned (gateway runs as 10001, dashboard as 1000). The
bundled datastores are left out because their images manage their own users.
With networkPolicy.enabled, ingress is limited to:
| Target | Allowed from |
|---|---|
Bundled Postgres 5432 | Gateway; dashboard when controlPlane.enabled |
Bundled Redis 6379 | Gateway |
Bundled ClickHouse 8123, 9000 | Gateway |
Gateway 8080 (data plane) | Any source |
Gateway 9091 (metrics) | Any source |
Gateway 9180 (Management API) | Dashboard and provisioner, when enabled |
Minimal production values
obleth:
existingSecret: obleth-secrets # keys listed above
upstreamBaseUrl: "http://inference.inference.svc.cluster.local:8000/v1"
replicas: 2
postgres:
enabled: false
redis:
enabled: false
clickhouse:
enabled: false
external:
url: "http://clickhouse.example.internal:8123"
benchmarkBackend:
enabled: false
controlPlane:
existingSecret: obleth-control-plane # dashboard keys listed above
serviceMonitor:
enabled: true
ingress:
enabled: true
className: nginx
host: obleth.example.com
tls:
- secretName: obleth-tls
hosts: [obleth.example.com]
With external datastores, the Postgres and Redis URLs come from the Secret, so
postgres.external.url and redis.external.url can stay empty.
Fixed pod settings
These are set in the templates, not by values.
| Pod | Setting |
|---|---|
| Gateway | terminationGracePeriodSeconds: 345; preStop sleep 5 |
| Gateway | Startup probe GET /health on proxy, every 5 s, 30 failures (about 150 s) |
| Gateway | Readiness GET /health, delay 5 s, every 5 s; liveness delay 10 s, every 10 s |
| Gateway | emptyDir volume wal at /var/lib/obleth for spilled telemetry; survives container restarts, not pod deletion |
| Gateway | Service ports proxy 8080, admin 9180, metrics 9091 |
| Gateway | Uses the chart's ServiceAccount only when capacity discovery RBAC is rendered |
| Dashboard | Readiness GET /login, delay 5 s, every 10 s; liveness delay 15 s, every 20 s |
| Dashboard | HOSTNAME=0.0.0.0, so it listens on all interfaces and kubectl port-forward reaches it |
| Provisioner | One replica, Recreate, terminationGracePeriodSeconds: 60, no probes, no Service |
| Compressor | Readiness GET /health, delay 30 s, every 10 s; liveness delay 60 s, every 30 s |
| Postgres | Readiness pg_isready; PGDATA in a subdirectory of the volume |
| Redis | Readiness redis-cli -a "$REDIS_PASSWORD" ping |
| ClickHouse | Readiness GET /ping on 8123; CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT=1 |
| ClickHouse | ConfigMap <release>-clickhouse-config in config.d: system log tables partitioned by day, with the retention above; the pod rolls when it changes |
