Configuration
Everything is configured through a Helm values file. Below is a working
starting point — copy it, change the marked values, and pass it with -f.
The values reference documents every setting the chart accepts. The configurator writes this file from your answers instead, together with the gitignored credentials file.
A starting values file
Section titled “A starting values file”env: production
images: # The chart's own defaults already point at the registry your role can pull # from, with a tag pinned per app. The pull secret is the one thing it # cannot supply — ECR allows no anonymous pull. Omit it only if you use a # kubelet credential provider. pullSecret: edisyl-ecr
config: appEnv: production nodeEnv: production # One line. Every public URL derives from it. Each app is served at # <app>.<domain>, so this value gives api.example.com, auth.example.com, # and the web application at edisyl.example.com. Do not include an app # label here — "edisyl.example.com" would put the web app at # edisyl.edisyl.example.com. domain: example.com
# Object storage. The provider is an enum: s3 | s3compatible. `s3` means # REAL AWS — using it for anything else produces storage that renders # cleanly, starts healthy and writes nowhere. Use `s3compatible` for MinIO, # Ceph, Cloudflare R2's S3 endpoint or any other S3 API. # # For real AWS S3: set the region, leave objectStorageUrl empty, and prefer # a pod IAM role over the two keys under secrets.managed below. For anything # else: objectStorageUrl and both keys are required — there is no # instance-role fallback outside AWS. objectStorageProvider: s3 objectStorageBucket: your-bucket objectStorageRegion: us-east-1 objectStorageUrl: ""
# The sender address. Required in every install: the api reads it at boot, # and sends mail from it once config.emailEnabled is true. emailFrom: platform@example.com
bootstrap: # No owner exists until at least one admin email is set. With none, the # freshly-seeded database has no owner and nothing owner-gated can be # created. Use an address you will actually sign in as, on one of the # domains under deploymentIdp below. adminEmails: ["admin@example.com"]
# The SAML identity provider your users sign in through. It is the only# sign-in path, so the chart refuses to render without it. Exactly one of# metadataUrl or metadataXml — see Authentication.deploymentIdp: metadataUrl: "https://idp.example.com/app/saml/metadata" domains: [example.com]
# Your own PostgreSQL 16. It must have the `vector` extension AVAILABLE: the# first migration runs CREATE EXTENSION vector, and a server without it fails# minutes into the install rather than at render.database: source: managed
# The LLM gateway. It always runs, and keeps its own database and role, never# the application's. Name a Secret carrying its connection as discrete# host/port/username/password/dbname keys. On the bundled cluster, set# source: cnpg instead.bifrost: database: source: existing-secret existingSecret: name: bifrost-db
secrets: provider: k8s-native managed: # Keep the real URL in a gitignored values file passed with a second -f, # not in the file you commit — see Secrets and signing keys. edisyl-database: data: DATABASE_URL: "postgresql://user:pass@host:5432/edisyl" # The object store's credentials, and nothing else: provider, bucket, # region and URL are config above. Blank on AWS S3 to use a pod IAM role. edisyl-object-storage: data: OBJECT_STORAGE_ACCESS_KEY_ID: "" OBJECT_STORAGE_SECRET_ACCESS_KEY: ""
# The bundled Inngest subchart does not read the install namespace. If you# install anywhere other than a namespace called "edisyl", this must match it.inngest: namespace: { create: false, name: edisyl }
edisyl: auth: # The auth service's own database. Without the bundled cluster you # provision it — a database, a role that owns it, and a Secret holding its # connection URI — and name that Secret here. See Using your own # infrastructure. database: secretName: mono-auth-db secretKey: uriThe auth signing material and the gateway key are not in this file. They go in
gitignored files passed with further -f flags — see
Secrets and signing keys.
Configuration lives in values, secrets in the store
Section titled “Configuration lives in values, secrets in the store”Since chart 0.46.0 a secrets.managed group holds credentials and nothing
else. Everything that is not a credential — the object store’s provider,
bucket, region and URL, your Redis host, port, user and TLS setting, the
sender address, the Sentry DSNs, the GitHub App id — is a value under
config.*, rendered into the edisyl-config ConfigMap. Where the chart runs a
service itself (bundled Redis, MinIO, the LLM gateway) it derives the address
and you set nothing. A configuration key left in a managed Secret’s data,
keys or remoteKeys fails the render, naming the config.* path to move it
to, so a store behind external-secrets only ever carries secrets. A blank
optional config.* key is left out of the ConfigMap rather than rendered as
"", so the apps apply their own defaults.
Deployment tenancy
Section titled “Deployment tenancy”config.deploymentTenancy defaults to dedicated: one organization’s own
install, where every organization owner can set the LLM gateway’s provider API
keys, bind its models and see deployment health. shared is Edisyl’s own
multi-organization posture, where provider administration and health stay with
the deployment owner, and the only one that serves the pack catalogue; an
install that runs several organizations sets shared or leaves it blank. A
self-hosted install keeps the default.
Nothing stateful is bundled
Section titled “Nothing stateful is bundled”PostgreSQL and object storage are both off by default. A chart that stands up a database and an object store unless told otherwise hands you a production datastore you never chose, on whatever StorageClass happens to be default, holding the only copy of your data.
So the file above names what the chart cannot guess: a Postgres, an object store, the sender address, the identity provider and a database for the LLM gateway. It refuses to render until each is coherent, and every refusal names the key to set.
Authentication is not a bundle at all. The chart always runs the platform’s own
auth service, and your users sign in through the SAML identity provider you
declare under deploymentIdp, which the chart registers for you — see
Authentication.
Bundled Redis and Inngest are still on. Neither holds durable state you would mourn, nor needs a credential you have to go and get. If you replace Redis with your own, it must have RediSearch and RedisJSON.
To use the bundled datastores instead — an evaluation install, say:
cnpg: enabled: true # Your cluster's StorageClass. Leave "" to use the cluster's default. A name # that does not exist leaves the PVCs Pending forever, so set this only if # you mean a specific class. The default provisions 348Gi across three # instances. storageClass: ""database: source: cnpgminio: enabled: trueconfig: # Blank: with MinIO the provider is derived as s3compatible, and `s3` is # refused. The URL and path-style addressing are derived too. objectStorageProvider: "" # Must be a bucket MinIO creates (minio.buckets). objectStorageBucket: edisyl-filesbifrost: database: # The bundled cluster provisions the gateway's database and role. source: cnpgcnpg.enabled and database.source are separate on purpose: the cluster
existing and the applications being pointed at it are separate decisions. The
chart refuses the combinations that disagree rather than rendering one that
half-works — including bifrost.database.source: cnpg with cnpg.enabled
false. With the bundled cluster the auth service’s database is provisioned too,
so the edisyl.auth.database block above is not needed.
What you must change
Section titled “What you must change”| Value | Why |
|---|---|
images.pullSecret |
ECR allows no anonymous pull; unless you use a kubelet credential provider |
config.domain |
Every public URL derives from it, as <app>.<domain> |
config.objectStorage* |
Nothing stateful is bundled; the provider and bucket have no default |
config.emailFrom |
Required in every install; the api reads it at boot |
bootstrap.adminEmails |
Empty means no owner exists in the database |
deploymentIdp |
SAML through it is the only sign-in path |
database.source and edisyl-database |
Name your Postgres or turn the bundled one on |
bifrost.database.* |
The gateway always runs and needs a database decision |
edisyl.auth.database |
The auth service’s database, unless the bundled cluster provisions it |
inngest.namespace.name |
Must match your install namespace |
Per-app image tags
Section titled “Per-app image tags”A release does not always build every app from the same commit, so the chart
pins a tag per app and no app inherits a global one. images.tag is a
fallback nothing currently uses, which means setting it alone changes nothing.
To pin a different build than the chart’s default, override per app:
edisyl: api: image: { tag: prd-<sha> } worker: image: { tag: prd-<sha> }The version matrix publishes the full block, every app’s tag, ready to copy for each release. The registry and the tags move together — these tags exist under the chart’s default registry and nowhere else, so overriding one without the other fails the pull.
Labels
Section titled “Labels”commonLabels puts your own Kubernetes labels on every resource the chart
renders, pod templates included — so they are what a cost report, a network
policy or an admission controller sees:
commonLabels: team: platform cost-center: "4210"Selectors never include them, so adding or changing one later is an ordinary
rolling update. The chart’s own keys (app, app.kubernetes.io/*,
helm.sh/chart, platform.edisyl.com/env) cannot be overridden; setting one
fails the render.
The bundled subcharts render their own resources and never see this value.
To label those too, repeat the map under the keys each one reads:
inngest.commonLabels for Inngest, and both minio.additionalLabels (the
workload) and minio.podLabels (its pods) for MinIO. The configurator writes
all of them for you.
The LLM gateway
Section titled “The LLM gateway”Every generation and embedding call goes through
Bifrost, an LLM gateway that holds your
provider credentials so no application does. Since chart 0.47.0 it is the only
gateway and on by default: bifrost.enabled is true, and the apps’
LLM_GATEWAY_URL is derived from it (http://edisyl-bifrost:8080/v1), not
set by you. What it needs from you is a database decision — the starting file
above makes it — and the virtual key the apps send, which goes in your
credentials file: see
Secrets and signing keys.
The configurator’s “Which gateway” question chooses between running it in this install and using one another deployment runs.
Configure its providers before the deployment serves traffic. A fresh gateway knows no provider, so every inference call fails until an owner adds one on Edisyl’s provider-settings page and proves it answers.
Things to know about it:
- One replica, always. Bifrost’s open-source build does not synchronize
budgets or rate-limit counters between processes, so the chart runs a
single-replica StatefulSet and exposes no replica count. Every upgrade has a
short window with no gateway, and with all inference routed through it that
window is an inference outage. On a Karpenter fleet, set
bifrost.podAnnotations: { karpenter.sh/do-not-disrupt: "true" }so consolidation does not add more of them. - Its own database. The gateway migrates its own schema and never shares the application’s Postgres. With the bundled cluster the chart provisions it; with your own Postgres you do — see Using your own infrastructure.
- The encryption key cannot be rotated. Every stored provider credential
is encrypted under
BIFROST_ENCRYPTION_KEY, and Bifrost cannot re-encrypt them. The chart generates it once and reads it back; back up theedisyl-bifrost-encryptionSecret. - Request logs keep no bodies. Each call logs model, tokens, cost, latency
and status for 30 days, on the gateway’s volume.
bifrost.logs.content: trueadds the prompts and answers;bifrost.logs.retentionDayssets the window. - It has its own ServiceAccount,
edisyl-bifrost, so a cloud workload identity can be bound to the gateway alone. On EKS a Pod Identity association needs nothing in values; IRSA and GKE Workload Identity go inbifrost.serviceAccount.annotations. A Bedrock provider configured with blank access keys then authenticates as the pod.
Nothing publishes the gateway by default: the chart renders a ClusterIP Service
and a headless edisyl-bifrost-headless Service (for a load balancer inside
your network that registers pod IPs), and no Ingress. The management console
is published only if you name an ingress class under bifrost.console — and
that class must be a private one, which the chart cannot check for you.
Console and inference share one port, so publishing it publishes provider
administration with it; on a public class the only thing left guarding every
vendor credential is one shared password. See the
values reference for the full
block.
Using a gateway you don’t run
Section titled “Using a gateway you don’t run”A deployment can use a gateway another deployment runs — a staging install
pointed at production’s, say — without running one of its own. Set
bifrost.external.url to that gateway’s management address and turn the
bundled one off:
bifrost: enabled: false external: url: http://bifrost.internal.example:8080Inference goes there too: LLM_GATEWAY_URL is that address plus /v1. No
gateway pods, database or encryption key render. Providers belong to the
deployment that runs the gateway, so here Edisyl’s gateway settings list its
providers and bind this deployment’s own model tiers, but refuse to save or
remove a provider credential. The two settings are exclusive — the render
refuses both at once, or a URL without an http or https scheme.
The management credential and the runtime key are the external gateway’s own, so the chart cannot generate them: see Secrets and signing keys.
Bringing your own infrastructure
Section titled “Bringing your own infrastructure”Every bundled dependency — PostgreSQL, Redis, object storage, the job runner — can be turned off and replaced with a managed service you already run. If you are installing on a cloud, read Using your own infrastructure before you install: it is easier to start there than to migrate a database out of the cluster later.
Third-party components lists what is on by default.
If you run Argo CD
Section titled “If you run Argo CD”Read this before installing. The chart generates secrets once and reuses
them by looking up the existing Secret in the cluster. Argo CD normally
renders with helm template against no cluster, so that lookup returns empty
on every sync and every generated value is regenerated — including
ENCRYPTION_KEY, which orphans any data encrypted under the previous one, and
BIFROST_ENCRYPTION_KEY, which orphans every provider credential the LLM
gateway holds.
Under Argo CD you must supply these values explicitly, through
secrets.managed.*.data or secrets.provider: external-secrets, rather than
relying on generation.
Was this page helpful?
Thanks for the feedback.
