10 changed files with 264 additions and 0 deletions
@ -0,0 +1,12 @@ |
|||
##
|
|||
## Makefile for LiteLLM quadlet
|
|||
##
|
|||
|
|||
DEPENDENCIES = postgresql traefik |
|||
|
|||
# LiteLLM quadlet is mapped to the 10024 user (litellm) and 10000 group (itix-svc)
|
|||
PROJECT_UID = 10024 |
|||
PROJECT_GID = 10000 |
|||
|
|||
# Include common Makefile
|
|||
include ../../scripts/common.mk |
|||
@ -0,0 +1,92 @@ |
|||
# Podman Quadlet: LiteLLM |
|||
|
|||
## Overview |
|||
|
|||
[LiteLLM](https://docs.litellm.ai/) is an LLM gateway (proxy server) that exposes |
|||
100+ LLM providers behind a single, OpenAI-compatible API, with authentication, |
|||
budgets, rate limiting and a management UI. |
|||
|
|||
This cookbook: |
|||
|
|||
- Runs LiteLLM in **proxy mode** using the **non-root** container image |
|||
(`ghcr.io/berriai/litellm-non_root`), which runs as UID/GID `65534`. |
|||
UID/GID mapping remaps it to the dedicated `litellm` user (`10024`) and the |
|||
`itix-svc` group (`10000`) on the host. |
|||
- Reads its behaviour from a configuration file (`config.yaml`). |
|||
- Reads secrets and passwords (master key, UI credentials, database URL) from a |
|||
separate `config.env` file injected as environment variables. |
|||
- Redirects the root path (`/`) to the Admin UI (`/ui`) and serves the API docs |
|||
under `/docs`. |
|||
- Uses PostgreSQL as its backend (requires the `postgresql` cookbook) to persist |
|||
keys, models and spend logs. |
|||
- Is published through Traefik (requires the `traefik` cookbook). |
|||
|
|||
## Prerequisites |
|||
|
|||
- The `postgresql` cookbook must be installed and running. |
|||
- The `traefik` cookbook must be installed and running. |
|||
- Configuration files `/etc/quadlets/litellm/config.yaml` and |
|||
`/etc/quadlets/litellm/config.env` must exist (copied from the examples). |
|||
|
|||
## Configuration |
|||
|
|||
- `config.yaml` — proxy configuration (`model_list`, `general_settings`, ...). |
|||
See <https://docs.litellm.ai/docs/proxy/config_settings>. |
|||
- `config.env` — secrets injected as environment variables: |
|||
|
|||
| Variable | Purpose | |
|||
| -------------------- | ----------------------------------------------- | |
|||
| `LITELLM_MASTER_KEY` | Master key for the proxy (must start with `sk-`)| |
|||
| `UI_USERNAME` | Username to sign in on the Admin UI | |
|||
| `UI_PASSWORD` | Password to sign in on the Admin UI | |
|||
| `DATABASE_URL` | PostgreSQL connection string | |
|||
|
|||
The root redirect (`ROOT_REDIRECT_URL=/ui`) and docs path (`DOCS_URL=/docs`) |
|||
are set directly in the Quadlet file. |
|||
|
|||
## Ports |
|||
|
|||
- TCP `4000`: LiteLLM proxy / Admin UI (bound on `127.0.0.1`, exposed through |
|||
Traefik). |
|||
|
|||
## UID / GID |
|||
|
|||
- User `litellm`: UID `10024` |
|||
- Group `itix-svc`: GID `10000` |
|||
- Inside the container the process runs as `65534:65534` (mapped to the host |
|||
IDs above). |
|||
|
|||
## Usage |
|||
|
|||
In a separate terminal, follow the logs. |
|||
|
|||
```sh |
|||
sudo make tail-logs |
|||
``` |
|||
|
|||
Install the Podman Quadlets and start LiteLLM. |
|||
|
|||
```sh |
|||
sudo make clean install |
|||
``` |
|||
|
|||
You should see the **litellm.service** waiting for PostgreSQL to be available, |
|||
then running its database migrations and starting up. |
|||
|
|||
Verify LiteLLM is running using its liveness endpoint: |
|||
|
|||
```sh |
|||
curl -sSf http://127.0.0.1:4000/health/liveliness |
|||
``` |
|||
|
|||
Then browse to the service through Traefik (the root path redirects to `/ui`): |
|||
|
|||
```sh |
|||
curl --resolve litellm:80:127.0.0.1 -L http://litellm/ |
|||
``` |
|||
|
|||
Finally, remove the quadlets, their configuration and their data. |
|||
|
|||
```sh |
|||
sudo make uninstall clean |
|||
``` |
|||
@ -0,0 +1,24 @@ |
|||
## |
|||
## LiteLLM secrets and passwords |
|||
## https://docs.litellm.ai/docs/proxy/ui |
|||
## |
|||
## This file holds sensitive values and is installed with 0600 root:root |
|||
## permissions. Podman reads it on the host and injects the variables into the |
|||
## container environment. |
|||
## |
|||
|
|||
# Master key used to authenticate against the proxy server (must start with sk-) |
|||
LITELLM_MASTER_KEY=sk-secret1234 |
|||
|
|||
# Admin UI credentials |
|||
UI_USERNAME=admin |
|||
UI_PASSWORD=admin |
|||
|
|||
# PostgreSQL connection (provided by the postgresql cookbook on localhost) |
|||
DATABASE_URL=postgresql://litellm:litellm@localhost:5432/litellm |
|||
|
|||
# Store models and keys managed through the UI in the database |
|||
STORE_MODEL_IN_DB=True |
|||
|
|||
# Provider API keys referenced from config.yaml (os.environ/...) go here too |
|||
#OPENAI_API_KEY="sk-..." |
|||
@ -0,0 +1,24 @@ |
|||
## |
|||
## LiteLLM Proxy configuration |
|||
## https://docs.litellm.ai/docs/proxy/config_settings |
|||
## |
|||
## Secrets (master key, UI credentials, database URL) are NOT set here. |
|||
## They are injected as environment variables from config.env. |
|||
## |
|||
|
|||
model_list: |
|||
# Declare your models here, or add them through the Admin UI (they will be |
|||
# persisted in the database thanks to `store_model_in_db`). |
|||
# |
|||
# - model_name: gpt-4o |
|||
# litellm_params: |
|||
# model: openai/gpt-4o |
|||
# api_key: os.environ/OPENAI_API_KEY |
|||
|
|||
general_settings: |
|||
# Persist models and credentials added through the Admin UI in the database. |
|||
store_model_in_db: true |
|||
|
|||
litellm_settings: |
|||
# Drop parameters unsupported by the target provider instead of failing. |
|||
drop_params: true |
|||
@ -0,0 +1,62 @@ |
|||
[Unit] |
|||
Description=LiteLLM Proxy Server |
|||
Documentation=https://docs.litellm.ai/docs/proxy/deploy |
|||
After=network.target |
|||
|
|||
# Only start if LiteLLM has been configured |
|||
ConditionPathExists=/etc/quadlets/litellm/config.env |
|||
ConditionPathExists=/etc/quadlets/litellm/config.yaml |
|||
|
|||
# Start/stop this unit when the target is started/stopped |
|||
PartOf=litellm.target |
|||
|
|||
[Container] |
|||
ContainerName=litellm |
|||
Image=litellm.image |
|||
AutoUpdate=registry |
|||
|
|||
# The non-root image runs as the "nobody" user (UID/GID 65534) |
|||
User=65534 |
|||
Group=65534 |
|||
|
|||
# UID/GID mapping to map the nobody (65534) user inside the container to the |
|||
# dedicated litellm user (10024) / itix-svc group (10000) on the host |
|||
UIDMap=0:1000000:65535 |
|||
UIDMap=+65534:10024:1 |
|||
GIDMap=0:1000000:65535 |
|||
GIDMap=+65534:10000:1 |
|||
|
|||
# Network configuration |
|||
Network=host |
|||
|
|||
# Run in proxy mode with the provided configuration file |
|||
Exec=--config /app/config.yaml |
|||
|
|||
# Redirect the root path (/) to the Admin UI and expose the docs under /docs |
|||
Environment=ROOT_REDIRECT_URL=/ui |
|||
Environment=DOCS_URL=/docs |
|||
|
|||
# Secrets and passwords (master key, UI credentials, database URL) |
|||
EnvironmentFile=/etc/quadlets/litellm/config.env |
|||
|
|||
# Volume mounts |
|||
Volume=/etc/quadlets/litellm/config.yaml:/app/config.yaml:ro,z |
|||
|
|||
# Health check |
|||
HealthCmd=python3 -c 'import urllib.request; urllib.request.urlopen("http://127.0.0.1:4000/health/liveliness")' |
|||
HealthInterval=30s |
|||
HealthTimeout=10s |
|||
HealthStartPeriod=60s |
|||
HealthRetries=3 |
|||
|
|||
[Service] |
|||
Restart=always |
|||
RestartSec=10 |
|||
TimeoutStartSec=300 |
|||
TimeoutStopSec=30 |
|||
|
|||
# Wait for PostgreSQL to be ready on localhost |
|||
ExecStartPre=/bin/sh -c 'exec 2>/dev/null; for try in $(seq 0 12); do if ! /bin/true 5<> /dev/tcp/127.0.0.1/5432; then echo "Waiting for PostgreSQL to be available..."; sleep 5; else exit 0; fi; done; exit 1' |
|||
|
|||
[Install] |
|||
WantedBy=litellm.target |
|||
@ -0,0 +1,7 @@ |
|||
[Unit] |
|||
Description=podman pull ghcr.io/berriai/litellm-non_root |
|||
Documentation=https://docs.litellm.ai/docs/proxy/docker_image_security |
|||
|
|||
[Image] |
|||
# Non-root variant of the LiteLLM image (runs as UID/GID 65534) |
|||
Image=ghcr.io/berriai/litellm-non_root:main-stable |
|||
@ -0,0 +1,13 @@ |
|||
[Unit] |
|||
Description=LiteLLM Service Target |
|||
Documentation=man:systemd.target(5) |
|||
Requires=postgresql.target litellm.service |
|||
After=postgresql.target litellm.service |
|||
|
|||
# Allow isolation - can stop/start this target independently |
|||
AllowIsolate=yes |
|||
# Only start if LiteLLM has been configured |
|||
ConditionPathExists=/etc/quadlets/litellm/config.env |
|||
|
|||
[Install] |
|||
WantedBy=multi-user.target |
|||
@ -0,0 +1,5 @@ |
|||
-- Initialization script for LiteLLM database and user |
|||
CREATE USER litellm WITH PASSWORD 'litellm'; |
|||
CREATE DATABASE litellm OWNER litellm; |
|||
GRANT ALL PRIVILEGES ON DATABASE litellm TO litellm; |
|||
ALTER ROLE litellm SET client_encoding TO 'utf8'; |
|||
@ -0,0 +1,16 @@ |
|||
http: |
|||
routers: |
|||
litellm: |
|||
rule: "Host(`litellm`)" |
|||
entryPoints: |
|||
- http |
|||
#- https |
|||
middlewares: |
|||
service: "litellm" |
|||
#tls: |
|||
# certResolver: le |
|||
services: |
|||
litellm: |
|||
loadBalancer: |
|||
servers: |
|||
- url: "http://127.0.0.1:4000" |
|||
@ -0,0 +1,9 @@ |
|||
variant: fcos |
|||
version: 1.4.0 |
|||
passwd: |
|||
users: |
|||
- name: litellm |
|||
uid: 10024 |
|||
gecos: LiteLLM |
|||
home_dir: /var/lib/quadlets/litellm |
|||
primary_group: itix-svc |
|||
Loading…
Reference in new issue