Split the monolithic LiteLLM proxy into independently scalable Kubernetes components to allow separate horizontal scaling of the LLM data plane and management API surfaces - Add DatabaseURLSettings pydantic-settings model that assembles DATABASE_URL (and optional DATABASE_URL_READ_REPLICA) from discrete DATABASE_* env vars before Prisma initializes, supporting both IAM token auth (minting short-lived RDS tokens) and password auth; replaces the CLI-only path that componentized entrypoints bypass - Add gateway component (port 4000) that trims the proxy route table to the LLM data-plane surface (chat, embeddings, completions, audio, realtime, provider passthroughs, health/metrics) via an allowlist applied inside the lifespan context so plugin-registered routes are captured - Add backend component (port 4001) that exposes the management/admin surface (keys, users, teams, orgs, spend analytics, model management, SSO, audit logs) with a complementary allowlist - Add ui component — Next.js static export served by nginx (port 3000) with RSC payload routing, asset prefix aliasing, and SPA fallback for dashboard routes - Add migrations component with dedicated Dockerfile that runs prisma migrate deploy via a Helm pre-install/pre-upgrade Job, eliminating per-pod schema contention on the Prisma advisory lock - Add Helm chart (helm/litellm) with separate Deployments, Services, HPAs, and ConfigMap for each component; shared _helpers.tpl emits DATABASE_*, IAM_TOKEN_DB_AUTH, REDIS_*, and DISABLE_SCHEMA_UPDATE env vars from chart values; ingress template routes traffic to the correct component by path prefix - Add comprehensive tests for DatabaseURLSettings covering IAM auth, password auth, read replica fallbacks, operator-pinned URL preservation, and percent-encoding; add coverage test asserting gateway + backend allowlist union equals the full proxy route set - Add pydantic-settings>=2.14.1 as a proxy extra dependency and update liccheck allowlist Co-authored-by: Yassin Kortam <yassinkortam@g.ucla.edu>
68 lines
2.7 KiB
Python
68 lines
2.7 KiB
Python
"""Entrypoint for the migrations Job container.
|
|
|
|
Runs `prisma migrate deploy` against the LiteLLM writer database using the
|
|
recovery logic in `litellm_proxy_extras.ProxyExtrasDBManager.setup_database`
|
|
(P3005 baseline + P3009/P3018 idempotent-error handling, retries, etc.).
|
|
|
|
Env vars:
|
|
DATABASE_URL required unless it can be assembled at
|
|
startup from the discrete DATABASE_* vars
|
|
(password auth) or minted from an IAM token
|
|
(`IAM_TOKEN_DB_AUTH=true`)
|
|
DIRECT_URL optional — used by `migrate diff` when the
|
|
primary URL is a pooler (e.g. Neon -pooler)
|
|
USE_V2_MIGRATION_RESOLVER "false" → fall back to the v1 resolver
|
|
(legacy diff-and-force recovery). Defaults
|
|
to "true": the v2 resolver avoids the schema
|
|
thrashing seen during rolling deploys when
|
|
two LiteLLM versions contend for the same DB.
|
|
USE_PRISMA_DB_PUSH "true" → use `prisma db push` instead of
|
|
`migrate deploy`. Default false.
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
|
|
from litellm.proxy.db.db_url_settings import DatabaseURLSettings
|
|
from litellm_proxy_extras._logging import logger
|
|
from litellm_proxy_extras.utils import ProxyExtrasDBManager, str_to_bool
|
|
|
|
|
|
def main() -> int:
|
|
# Assemble DATABASE_URL from the discrete DATABASE_* env vars, matching
|
|
# the gateway/backend startup path (IAM mint or password auth). Leaves an
|
|
# operator-pinned DATABASE_URL untouched.
|
|
DatabaseURLSettings.from_env().apply_to_env()
|
|
|
|
if not os.getenv("DATABASE_URL"):
|
|
logger.error(
|
|
"DATABASE_URL is not set and could not be assembled from the "
|
|
"DATABASE_* env vars — cannot run migrations."
|
|
)
|
|
return 1
|
|
|
|
# v2 is the safer default for componentized deploys: it skips the
|
|
# diff-and-force recovery from v1 that caused schema thrashing during
|
|
# rolling deploys. Set USE_V2_MIGRATION_RESOLVER=false to opt back into v1.
|
|
use_v2 = str_to_bool(os.getenv("USE_V2_MIGRATION_RESOLVER", "true"))
|
|
use_db_push = str_to_bool(os.getenv("USE_PRISMA_DB_PUSH"))
|
|
|
|
logger.info(
|
|
"Starting prisma migration job (use_migrate=%s, use_v2_resolver=%s)",
|
|
not use_db_push,
|
|
use_v2,
|
|
)
|
|
ok = ProxyExtrasDBManager.setup_database(
|
|
use_migrate=not use_db_push,
|
|
use_v2_resolver=use_v2,
|
|
)
|
|
if not ok:
|
|
logger.error("Migration job failed after retries.")
|
|
return 1
|
|
logger.info("Migration job completed successfully.")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|