mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-03 07:23:33 +00:00
Neither chart bundles Lens anymore. The Lens subchart, its lock entry, the vendored chart archive, the templates/lens resources and the bundled-Lens install smoke are gone. A connection-only lens block wires the gateway and backend to a Lens deployed from its own chart, and an enabled lensWorker value fails the render instead of being ignored. Supersedes #47869, which made the same change for helm/litellm only.
265 lines
29 KiB
Markdown
265 lines
29 KiB
Markdown
# Helm Chart for LiteLLM
|
||
|
||
> [!IMPORTANT]
|
||
> This is community maintained, Please make an issue if you run into a bug
|
||
> We recommend using [Docker or Kubernetes for production deployments](https://docs.litellm.ai/docs/proxy/prod)
|
||
|
||
## Prerequisites
|
||
|
||
- Kubernetes 1.21+
|
||
- Helm 3.8.0+
|
||
|
||
If `db.deployStandalone` is used:
|
||
|
||
- PV provisioner support in the underlying infrastructure
|
||
|
||
If `db.useStackgresOperator` is used (not yet implemented):
|
||
|
||
- The Stackgres Operator must already be installed in the Kubernetes Cluster. This chart will **not** install the operator if it is missing.
|
||
|
||
## Parameters
|
||
|
||
### LiteLLM Proxy Deployment Settings
|
||
|
||
| Name | Description | Value |
|
||
| --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------- |
|
||
| `replicaCount` | The number of LiteLLM Proxy pods to be deployed | `1` |
|
||
| `masterkeySecretName` | The name of the Kubernetes Secret that contains the Master API Key for LiteLLM. If not specified, use the generated secret name. | N/A |
|
||
| `masterkeySecretKey` | The key within the Kubernetes Secret that contains the Master API Key for LiteLLM. If not specified, use `masterkey` as the key. | N/A |
|
||
| `masterkey` | The Master API Key for LiteLLM. If not specified, a random key in the `sk-...` format is generated on first install and reused on upgrades. | N/A |
|
||
| `environmentSecrets` | An optional array of Secret object names. The keys and values in these secrets will be presented to the LiteLLM proxy pod as environment variables. See below for an example Secret object. | `[]` |
|
||
| `environmentConfigMaps` | An optional array of ConfigMap object names. The keys and values in these configmaps will be presented to the LiteLLM proxy pod as environment variables. See below for an example Secret object. | `[]` |
|
||
| `image.repository` | LiteLLM Proxy image repository | `ghcr.io/berriai/litellm` |
|
||
| `image.pullPolicy` | LiteLLM Proxy image pull policy | `IfNotPresent` |
|
||
| `image.tag` | Overrides the image tag whose default the latest version of LiteLLM at the time this chart was published. | `""` |
|
||
| `imagePullSecrets` | Registry credentials for the LiteLLM and initContainer images. | `[]` |
|
||
| `serviceAccount.create` | Whether or not to create a Kubernetes Service Account for this deployment. The default is `false` because LiteLLM has no need to access the Kubernetes API. | `false` |
|
||
| `service.type` | Kubernetes Service type (e.g. `LoadBalancer`, `ClusterIP`, etc.) | `ClusterIP` |
|
||
| `service.port` | TCP port that the Kubernetes Service will listen on. Also the TCP port within the Pod that the proxy will listen on. | `4000` |
|
||
| `livenessProbe.*` | Liveness probe settings for the LiteLLM container (`path`, `periodSeconds`, `timeoutSeconds`, thresholds, and initial delay). | See `values.yaml` |
|
||
| `readinessProbe.*` | Readiness probe settings for the LiteLLM container (`path`, `periodSeconds`, `timeoutSeconds`, thresholds, and initial delay). | See `values.yaml` |
|
||
| `startupProbe.*` | Startup probe settings for the LiteLLM container (`path`, `periodSeconds`, `timeoutSeconds`, thresholds, and initial delay). | See `values.yaml` |
|
||
| `resources.*` | CPU/memory requests and limits for the LiteLLM container. Unset by default; production deployments should set 1 CPU and 4Gi of memory per worker. | `{}` |
|
||
| `service.loadBalancerClass` | Optional LoadBalancer implementation class (only used when `service.type` is `LoadBalancer`) | `""` |
|
||
| `ingress.labels` | Additional labels for the Ingress resource | `{}` |
|
||
| `ingress.*` | See [values.yaml](./values.yaml) for example settings | N/A |
|
||
| `proxyConfigMap.create` | When `true`, render a ConfigMap from `.Values.proxy_config` and mount it. | `true` |
|
||
| `proxyConfigMap.name` | When `create=false`, name of the existing ConfigMap to mount. | `""` |
|
||
| `proxyConfigMap.key` | Key in the ConfigMap that contains the proxy config file. | `"config.yaml"` |
|
||
| `proxy_config.*` | See [values.yaml](./values.yaml) for default settings. Rendered into the ConfigMap’s `config.yaml` only when `proxyConfigMap.create=true`. See [example_config_yaml](../../../litellm/proxy/example_config_yaml/) for configuration examples. | `N/A` |
|
||
| `extraContainers[]` | An array of additional containers to be deployed as sidecars alongside the LiteLLM Proxy. |
|
||
| `pdb.enabled` | Enable a PodDisruptionBudget for the LiteLLM proxy Deployment | `false` |
|
||
| `pdb.minAvailable` | Minimum number/percentage of pods that must be available during **voluntary** disruptions (choose **one** of minAvailable/maxUnavailable) | `null` |
|
||
| `pdb.maxUnavailable` | Maximum number/percentage of pods that can be unavailable during **voluntary** disruptions (choose **one** of minAvailable/maxUnavailable) | `null` |
|
||
| `pdb.annotations` | Extra metadata annotations to add to the PDB | `{}` |
|
||
| `pdb.labels` | Extra metadata labels to add to the PDB | `{}` |
|
||
|
||
| `billingMetrics.enabled` | Enable enterprise billable-request metering. Requires an enterprise license. | `false` |
|
||
| `billingMetrics.endpoint` | Collector that the billable-request counter is pushed to. | `https://telemetry.litellm.ai` |
|
||
| `billingMetrics.secretName` | Name of an existing Secret holding the mTLS client certificate, under the keys `tls.crt` and `tls.key`. | `litellm-billing-metrics-mtls` |
|
||
| `billingMetrics.caSecretName` | Name of an existing Secret holding a CA bundle under the key `ca.crt`. Only needed for a private or test collector whose server certificate is not on the public web PKI. | `""` |
|
||
| `billingMetrics.exportIntervalMs` | How often the counter is pushed, in milliseconds. The proxy defaults to `60000` when unset. | `""` |
|
||
|
||
#### Example `proxy_config` ConfigMap from values (default):
|
||
|
||
```
|
||
proxyConfigMap:
|
||
create: true
|
||
key: "config.yaml"
|
||
|
||
proxy_config:
|
||
general_settings:
|
||
master_key: os.environ/PROXY_MASTER_KEY
|
||
model_list: []
|
||
```
|
||
|
||
The chart ships no models, so add them under `proxy_config.model_list` or from the Admin UI with `store_model_in_db: true`
|
||
|
||
```
|
||
proxy_config:
|
||
model_list:
|
||
- model_name: gpt-5.6
|
||
litellm_params:
|
||
model: openai/gpt-5.6
|
||
api_key: os.environ/OPENAI_API_KEY
|
||
```
|
||
|
||
#### Example using existing `proxyConfigMap` instead of creating it:
|
||
|
||
```
|
||
proxyConfigMap:
|
||
create: false
|
||
name: my-litellm-config
|
||
key: config.yaml
|
||
|
||
# proxy_config is ignored in this mode
|
||
```
|
||
|
||
#### Example `environmentSecrets` Secret
|
||
|
||
```
|
||
apiVersion: v1
|
||
kind: Secret
|
||
metadata:
|
||
name: litellm-envsecrets
|
||
data:
|
||
AZURE_OPENAI_API_KEY: TXlTZWN1cmVLM3k=
|
||
type: Opaque
|
||
```
|
||
|
||
#### Enterprise billable-request metering
|
||
|
||
Enterprise licenses meter billable requests by pushing a counter to LiteLLM's collector over mutual TLS. The chart does not create the client certificate; it mounts one you already hold, read-only, so the private key is never exposed through the environment. Create the Secret under the name the chart expects, then turn the block on:
|
||
|
||
```
|
||
kubectl create secret tls litellm-billing-metrics-mtls --cert=client.crt --key=client.key
|
||
```
|
||
|
||
```
|
||
billingMetrics:
|
||
enabled: true
|
||
```
|
||
|
||
Set `billingMetrics.caSecretName` only when the collector is a private or test one whose server certificate is not on the public web PKI; the production collector needs no CA override. The chart fails the render rather than deploying a proxy that silently never exports, so a missing `secretName` or an emptied `endpoint` surfaces at `helm install` time.
|
||
|
||
### Database Settings
|
||
|
||
| Name | Description | Value |
|
||
| ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
|
||
| `db.useExisting` | Use an existing Postgres database. A Kubernetes Secret object must exist that contains credentials for connecting to the database. An example secret object definition is provided below. | `false` |
|
||
| `db.endpoint` | If `db.useExisting` is `true`, this is the IP, Hostname or Service Name of the Postgres server to connect to. | `localhost` |
|
||
| `db.database` | If `db.useExisting` is `true`, the name of the existing database to connect to. | `litellm` |
|
||
| `db.url` | If `db.useExisting` is `true`, the connection url of the existing database to connect to can be overwritten with this value. | `postgresql://$(DATABASE_USERNAME):$(DATABASE_PASSWORD)@$(DATABASE_HOST)/$(DATABASE_NAME)` |
|
||
| `db.secret.name` | If `db.useExisting` is `true`, the name of the Kubernetes Secret that contains credentials. | `postgres` |
|
||
| `db.secret.usernameKey` | If `db.useExisting` is `true`, the name of the key within the Kubernetes Secret that holds the username for authenticating with the Postgres instance. | `username` |
|
||
| `db.secret.passwordKey` | If `db.useExisting` is `true`, the name of the key within the Kubernetes Secret that holds the password associates with the above user. | `password` |
|
||
| `db.username` | If `db.useExisting` is `true`, the database user as a plain value. When set, `db.secret.usernameKey` is not read. | `""` |
|
||
| `db.port` | If `db.useExisting` is `true` with token auth, the Postgres port used to build the connection URL. Password auth takes the port from `db.url`. | `5432` |
|
||
| `db.schema` | With token auth, the Postgres schema holding the LiteLLM tables, rendered as `DATABASE_SCHEMA` when the tables are not in `public`. Ignored with password auth, where the schema stays in `db.url` as `?schema=`. | `""` |
|
||
| `db.useIAMAuth` | If `db.useExisting` is `true` and `db.deployStandalone` is `false`, authenticate with an AWS RDS IAM token instead of a password. See [Token auth](#token-auth-to-an-existing-postgres-rds-iam-or-microsoft-entra-id). | `false` |
|
||
| `db.useAzureEntraAuth` | If `db.useExisting` is `true` and `db.deployStandalone` is `false`, authenticate with a Microsoft Entra ID token instead of a password. Mutually exclusive with `db.useIAMAuth`. | `false` |
|
||
| `db.useStackgresOperator` | Not yet implemented. | `false` |
|
||
| `db.deployStandalone` | Deploy a standalone, single instance deployment of Postgres, using the Bitnami postgresql chart. This is useful for getting started but doesn't provide HA or (by default) data backups. | `true` |
|
||
| `postgresql.*` | If `db.deployStandalone` is `true`, configuration passed to the Bitnami postgresql chart. See the [Bitnami Documentation](https://github.com/bitnami/charts/tree/main/bitnami/postgresql) for full configuration details. See [values.yaml](./values.yaml) for the default configuration. | See [values.yaml](./values.yaml) |
|
||
| `postgresql.auth.*` | If `db.deployStandalone` is `true`, care should be taken to ensure the default `password` and `postgres-password` values are **NOT** used. | `NoTaGrEaTpAsSwOrD` |
|
||
| `postgresql.image.*` | If `db.deployStandalone` is `true`, the image for the bundled Postgres. Pinned to a `docker.io/bitnamilegacy` build because Bitnami retired the versioned tags under `docker.io/bitnami`. | `bitnamilegacy/postgresql:16.2.0-debian-12-r6` |
|
||
| `redis.image.*` | If `redis.enabled` is `true`, the image for the bundled Redis. Pinned to a `docker.io/bitnamilegacy` build for the same reason. | `bitnamilegacy/redis:7.2.4-debian-12-r9` |
|
||
|
||
#### Bundled Postgres image
|
||
|
||
Bitnami removed the versioned tags from `docker.io/bitnami` and republished the archived builds under `docker.io/bitnamilegacy`, so the image defaults that ship inside the `postgresql` and `redis` subcharts no longer pull. The chart pins both to the `bitnamilegacy` copies of the exact builds those subchart versions were released with, which keeps the on-disk data directory layout unchanged for existing installs.
|
||
|
||
Keep `postgresql.image.tag` pinned. `docker.io/bitnami/postgresql` still publishes a floating `latest`, and pointing the bundled Postgres at a different major version starts the server against a data directory it cannot read (`database files are incompatible with server`). There is no in-place way back, so crossing a major version means dumping the database with the old image and restoring it into the new one. The chart refuses to render when the tag is empty or `latest`.
|
||
|
||
Those images no longer receive updates. For anything beyond getting started, run Postgres outside the chart and point at it with `db.useExisting`.
|
||
|
||
#### Example Postgres `db.useExisting` Secret
|
||
|
||
```yaml
|
||
apiVersion: v1
|
||
kind: Secret
|
||
metadata:
|
||
name: postgres
|
||
data:
|
||
# Password for the "postgres" user
|
||
postgres-password: <some secure password, base64 encoded>
|
||
username: litellm
|
||
password: <some secure password, base64 encoded>
|
||
type: Opaque
|
||
```
|
||
|
||
#### Token auth to an existing Postgres (RDS IAM or Microsoft Entra ID)
|
||
|
||
When the database accepts short-lived tokens instead of a password (AWS RDS or Aurora with IAM database authentication, or Azure Database for PostgreSQL with Microsoft Entra ID), there is no password to put in a Secret. Turn on `db.useIAMAuth` or `db.useAzureEntraAuth` and the chart stops referencing `db.secret.passwordKey` and `db.url`. It sets `IAM_TOKEN_DB_AUTH` (or `AZURE_POSTGRESQL_AUTH`) and emits `DATABASE_HOST`, `DATABASE_PORT`, `DATABASE_USERNAME` and `DATABASE_NAME` for the proxy, the migrations job and the collector sidecar. Each of them mints its own token at startup and builds `DATABASE_URL` from those parts, and the in-container pgbouncer (`db.connectionPool`) refreshes the token before it expires.
|
||
|
||
```yaml
|
||
db:
|
||
useExisting: true
|
||
deployStandalone: false
|
||
useIAMAuth: true
|
||
endpoint: litellm.cluster-abc123.us-west-1.rds.amazonaws.com
|
||
database: litellm
|
||
username: litellm_iam # the role granted rds_iam; no db.secret needed
|
||
```
|
||
|
||
The pod needs cloud credentials for the token: on EKS use IRSA or Pod Identity on the chart's `serviceAccount` (and `migrationJob.serviceAccountName` when the Helm hook runs before the ServiceAccount exists), on AKS use workload identity. Set `AWS_RDS_REGION` under `envVars` when the RDS hostname is not a standard regional endpoint (the token must be signed for the region the database lives in). TLS options that would otherwise go in `db.url` are set as `DATABASE_SSLMODE` and `DATABASE_SSLROOTCERT` under `envVars`. Leaving `db.username` empty reads the user from `db.secret.usernameKey` as before.
|
||
|
||
#### Examples for `environmentSecrets` and `environemntConfigMaps`
|
||
|
||
```yaml
|
||
# Use config map for not-secret configuration data
|
||
apiVersion: v1
|
||
kind: ConfigMap
|
||
metadata:
|
||
name: litellm-env-configmap
|
||
data:
|
||
SOME_KEY: someValue
|
||
ANOTHER_KEY: anotherValue
|
||
```
|
||
|
||
```yaml
|
||
# Use secrets for things which are actually secret like API keys, credentials, etc
|
||
# Base64 encode the values stored in a Kubernetes Secret: $ pbpaste | base64 | pbcopy
|
||
# The --decode flag is convenient: $ pbpaste | base64 --decode
|
||
|
||
apiVersion: v1
|
||
kind: Secret
|
||
metadata:
|
||
name: litellm-env-secret
|
||
type: Opaque
|
||
data:
|
||
SOME_PASSWORD: cDZbUGVXeU5e0ZW # base64 encoded
|
||
ANOTHER_PASSWORD: AAZbUGVXeU5e0ZB # base64 encoded
|
||
```
|
||
|
||
Source: [GitHub Gist from troyharvey](https://gist.github.com/troyharvey/4506472732157221e04c6b15e3b3f094)
|
||
|
||
### Migration Job Settings
|
||
|
||
The migration job supports both ArgoCD and Helm hooks to ensure database migrations run at the appropriate time during deployments.
|
||
|
||
| Name | Description | Value |
|
||
| -------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | ------- |
|
||
| `migrationJob.enabled` | Enable or disable the schema migration Job | `true` |
|
||
| `migrationJob.backoffLimit` | Backoff limit for Job restarts | `4` |
|
||
| `migrationJob.ttlSecondsAfterFinished` | TTL for completed migration jobs | `120` |
|
||
| `migrationJob.annotations` | Additional annotations for the migration job pod | `{}` |
|
||
| `migrationJob.extraContainers` | Additional containers to run alongside the migration job | `[]` |
|
||
| `migrationJob.hooks.argocd.enabled` | Enable ArgoCD hooks for the migration job (uses PreSync hook with BeforeHookCreation delete policy) | `true` |
|
||
| `migrationJob.hooks.helm.enabled` | Enable Helm hooks for the migration job (uses pre-install,pre-upgrade hooks with before-hook-creation delete policy) | `false` |
|
||
| `migrationJob.hooks.helm.weight` | Helm hook execution order (lower weights executed first). Optional - defaults to "1" if not specified. | N/A |
|
||
|
||
## Accessing the Admin UI
|
||
|
||
When browsing to the URL published per the settings in `ingress.*`, you will
|
||
be prompted for **Admin Configuration**. The **Proxy Endpoint** is the internal
|
||
(from the `litellm` pod's perspective) URL published by the `<RELEASE>-litellm`
|
||
Kubernetes Service. If the deployment uses the default settings for this
|
||
service, the **Proxy Endpoint** should be set to `http://<RELEASE>-litellm:4000`.
|
||
|
||
The **Proxy Key** is the value specified for `masterkey` or, if a `masterkey`
|
||
was not provided to the helm command line, the `masterkey` is a randomly
|
||
generated string in the `sk-...` format stored in the `<RELEASE>-litellm-masterkey` Kubernetes Secret.
|
||
The key is generated once on the first install; later `helm upgrade` runs reuse the
|
||
value already in that Secret, so upgrading never rotates the master key.
|
||
|
||
```bash
|
||
kubectl -n litellm get secret <RELEASE>-litellm-masterkey -o jsonpath="{.data.masterkey}"
|
||
```
|
||
|
||
## Admin UI Limitations
|
||
|
||
At the time of writing, the Admin UI is unable to add models. This is because
|
||
it would need to update the `config.yaml` file which is a exposed ConfigMap, and
|
||
therefore, read-only. This is a limitation of this helm chart, not the Admin UI
|
||
itself.
|
||
|
||
## Connect Lens
|
||
|
||
This chart does not deploy Lens. Deploy Lens from [its own chart](https://github.com/BerriAI/lens/tree/main/helm/lens), then set `lens.enabled: true`, `lens.url`, `lens.publicUrl`, `lens.gatewaySecret.name` and `lens.serviceTokenSecret.name`. The secret keys default to `gateway-secret` and `service-token`. Set `lens.service.name` when that Lens runs in this release's namespace and the chart ingress should route `/lens-ingest` to it. The old `lensWorker` values are no longer read, and enabling them fails the render
|
||
|
||
## Shutdown accounting
|
||
|
||
`GRACEFUL_SHUTDOWN_TIMEOUT` defaults to 30 seconds. Pending success callbacks share the time remaining since SIGTERM or the first `/health/drain` call. Callback flushing reserves the existing 10-second teardown headroom for cancellation, tracked accounting tasks and persistence. Exhausting this budget can discard callbacks, which is logged
|
||
|
||
Set `terminationGracePeriodSeconds` to at least `GRACEFUL_SHUTDOWN_TIMEOUT + 10`, allowing additional time for preStop hooks and database writes. This is not a hard shutdown bound or a guarantee of persistence. Database retries retain their own limits, and cancellation-resistant callbacks can remain alive. The existing preStop hook can also be followed by Uvicorn's separate connection drain, as described in `values.yaml`
|