LiteLLM 프로덕션 배포 — 내 환경에서 안전하게 게이트웨이를 올리는 법
LiteLLM 프로덕션 배포 — 내 환경에서 안전하게 게이트웨이를 올리는 법
로컬에서 한 줄로 띄운 LiteLLM 게이트웨이가 잘 도는 건 확인했는데, 이제 그걸 실제 운영 환경에 올리려고 하니 어디서부터 손대야 할지 막막할 때가 있어요. 이 가이드는 AWS, Google Cloud, Azure, 또는 어떤 Kubernetes 클러스터에서든 LiteLLM을 프로덕션으로 배포하는 방법을 안내합니다. 한 대의 머신에서 처음 올려보는 것이라면 먼저 Docker 퀵스타트를 보고 오시는 게 자연스러워요 — 이 페이지는 그 끝에서 시작합니다.
배포 경로는 두 가지 — Kubernetes 인지 아닌지로 나뉘어요
LiteLLM이 공식으로 지원하는 배포 경로는 크게 두 갈래입니다. 이 둘을 먼저 정해 두면 나머지는 그 위에 자재를 얹는 문제가 돼요.
- Kubernetes를 쓰는 경우: EKS, GKE, AKS 어디든 Helm 차트로 배포합니다. 클라우드가 달라도 설치는 동일하고, 차이가 나는 건 데이터 저장소와 인그레스 설정뿐이에요.
- Kubernetes를 안 쓰는 경우: AWS와 GCP는 공식 Terraform 모듈로 전체 스택을 한 번에 올릴 수 있어요. Azure는 Terraform 모듈이 없어서 AKS + Helm 경로가 지원되는 방식입니다.
두 가지 배포 모드 — 모놀리식과 마이크로서비스
LiteLLM은 두 가지 배포 모드를 제공해요.
- 모놀리식 (Monolithic): 하나의
litellm이미지가 LLM 트래픽, 관리 API, UI를 모두 처리합니다.litellm-helm차트가 바로 이 모드로 돌고, 운영하기에 가장 단순해요. - 마이크로서비스 (Microservices):
gateway(LLM 트래픽, 4000번 포트),backend(관리 API와 UI 백엔드, 4001번 포트),ui(3000번 포트)가 각각 독립적으로 배포·스케일됩니다. 컴포넌트 분리형litellm차트와 두 Terraform 모듈이 이 모드를 써요.
어느 모드를 쓰든 뒷받침하는 인프라는 동일합니다.
| 구성 요소 | 역할 | 비고 |
|---|---|---|
| LiteLLM 서비스 | 모놀리식 하나, 또는 gateway+backend+ui | 무상태, 로드 밸런서 뒤에 2개 이상 레플리카 |
| PostgreSQL | 키, 팀, 사용자, 지출 로그, 설정 | 프록시의 인증·추적 기능에 필수 |
| Redis | 비율 제한, 라우터 상태, 인스턴스 간 캐시 | 인스턴스가 둘 이상이면 필수 |
| 마이그레이션 잡 | Postgres 스키마 마이그레이션 적용 | 업그레이드마다 1회, 프록시는 DISABLE_SCHEMA_UPDATE=true |
핵심 환경변수들
배포할 때 이 다섯 개 값을 잡아두면 대부분의 운영 설정이 끝납니다.
DATABASE_URL="postgresql://user:password@host:5432/litellm"
LITELLM_MASTER_KEY="sk-..." # 프록시 관리자 키
LITELLM_SALT_KEY="sk-..." # DB에 저장하는 프로바이더 자격증명을 암호화. 한 번 정하면 절대 바꾸지 말 것
DISABLE_SCHEMA_UPDATE="true" # 프록시 인스턴스는 마이그레이션 안 함 — 마이그레이션 잡이 담당
STORE_MODEL_IN_DB="True" # 설정 파일 대신 관리 UI에서 모델 관리
여기서 LITELLM_SALT_KEY는 모델을 추가한 뒤에는 절대 회전할 수 없어요. 이 키가 데이터베이스에 저장된 프로바이더 자격증명을 암호화하는데, 값을 바꾸면 기존 자격증명을 읽을 수 없게 됩니다. 강력한 랜덤 값을 만들어 두 키 모두 클라우드의 비밀 관리자(secret manager)에 보관하세요.
이미지와 Helm 배포
공식 이미지는 ghcr.io/berriai에 게시되고 docker.litellm.ai/berriai에도 미러링됩니다. 모놀리식 배포에는 ghcr.io/berriai/litellm을 쓰는데, 이 이미지가 Prisma 툴체인을 포함하고 있어 Postgres를 같이 쓸 때 적합해요. 버전 태그를 고정해서 롤백이 결정적이게 만들고, latest 같은 움직이는 태그는 피하세요. 모든 이미지에는 서명이 되어 있어서, 검증 방법과 non-root 변형은 Docker 이미지 보안 가이드에서 확인할 수 있어요.
먼저 두 차트가 공통으로 쓰는 시크릿을 만듭니다.
kubectl create secret generic litellm-masterkey \
--from-literal=masterkey="sk-$(openssl rand -hex 24)"
kubectl create secret generic litellm-db \
--from-literal=username=litellm \
--from-literal=password="<database-password>"
kubectl create secret generic litellm-env \
--from-literal=LITELLM_SALT_KEY="sk-$(openssl rand -hex 24)" \
--from-literal=REDIS_PASSWORD="<redis-password>" \
--from-literal=OPENAI_API_KEY="<provider-key>"
그다음 모드를 하나 고르면 됩니다. 모놀리식(litellm-helm)의 values.yaml을 보면 재미있는 점이 보여요 — 오토스케일링(autoscaling.* 또는 keda.*), PodDisruptionBudget(pdb.*), Prometheus ServiceMonitor(serviceMonitor.*), 읽기 레플리카 라우팅(db.readReplicaUrl)까지 차트가 지원합니다.
replicaCount: 3
image:
repository: ghcr.io/berriai/litellm
tag: "v1.90.2" # 버전 고정
masterkeySecretName: litellm-masterkey
masterkeySecretKey: masterkey
db:
useExisting: true
deployStandalone: false
endpoint: "<postgres-endpoint>"
database: litellm
secret:
name: litellm-db
usernameKey: username
passwordKey: password
environmentSecrets:
- litellm-env
proxy_config:
model_list:
- model_name: gpt-4o
litellm_params:
model: openai/gpt-4o
api_key: os.environ/OPENAI_API_KEY
router_settings:
redis_host: "<redis-endpoint>"
redis_port: 6379
redis_password: os.environ/REDIS_PASSWORD
helm install litellm oci://ghcr.io/berriai/litellm-helm -f values.yaml
두 차트 모두 마이그레이션 잡을 자동으로 돌리고, 프록시 팟에는 DISABLE_SCHEMA_UPDATE=true를 유지합니다. 서비스는 클라우드 인그레스로 노출하되, /health/readiness에 헬스 체크를 걸고 DNS 레코드를 로드 밸런서에 연결하세요. 시크릿은 가능하면 Kubernetes 시크릿보다 클라우드 비밀 관리자(예: AKS의 Key Vault CSI 드라이버)를 쓰는 편이 좋아요.
오토스케일링 — 최댓값은 데이터베이스가 감당할 수 있는 수준으로
두 차트 모두 기본적으로 오토스케일링이 꺼져 있거나 보수적으로 설정되어 있어요. litellm-helm은 두 가지 상호 배타적 메커니즘을 제공합니다. autoscaling.*은 표준 HorizontalPodAutoscaler(HPA)를 만들고, keda.*는 큐 깊이나 Prometheus 쿼리 같은 걸 읽는 KEDA ScaledObject를 만듭니다. 둘 다 켜면 HPA만 렌더되니 하나만 고르세요.
autoscaling:
enabled: false
minReplicas: 1
maxReplicas: 100
targetCPUUtilizationPercentage: 80
keda:
enabled: false
minReplicas: 1
maxReplicas: 100
pollingInterval: 30 # 트리거 평가 간격(초)
cooldownPeriod: 300 # 축소 전 잠잠한 시간(초)
triggers: [] # 필수 — 트리거 없는 ScaledObject는 스케일 안 됨
컴포넌트 분리형 차트는 각 컴포넌트를 따로 스케일합니다(gateway.hpa, backend.hpa, ui.hpa). 게이트웨이가 LLM 트래픽을 보는 유일한 컴포넌트라 보통 게이트웨이의 최댓값을 올리는 것만으로 충분해요.
중요한 함정이 하나 있어요. 스케일 최댓값을 정할 때는 데이터베이스가 감당할 수 있는 수준으로 잡아야 합니다. 커넥션 풀이 워커마다 별도로 잡히기 때문에 레플리카 상한이 곧 Postgres 커넥션 상한이 됩니다. litellm-helm이 기본 maxReplicas: 100인데, 기본 풀 제한 10으로 계산하면 풀 스케일 시 약 1000개의 커넥션을 요구하게 돼요. 데이터베이스 커넥션을 어떻게 묶을지는 프로덕션 체크리스트를 참고하세요.
Terraform 경로 (AWS/GCP)
Kubernetes를 안 쓰는 환경이라면 AWS와 GCP의 공식 Terraform 모듈로 데이터 스토어와 인그레스를 포함한 전체 스택을 올릴 수 있어요. 기존 VPC·서브넷·데이터 스토어를 재사용할 수도 있는데, 이때 모듈은 create_database = false + database_url 같은 방식으로 기존 자원을 그대로 쓰게 합니다. 잠깐, 여기서 주의할 게 있어요 — 서브넷을 azs 대신 public_subnet_ids/private_subnet_ids로 넘기면 VPC·서브넷·라우트 테이블·NAT 게이트웨이 같은 걸 새로 만들지 않습니다. 또 create_*를 false로 두고 URL을 비우면 그 컴포넌트를 완전히 빼고 돌릴 수 있는데, 데이터베이스가 없으면 키 관리·지출 추적·UI 영속성이 사라지고 인증이 마스터 키 단독으로 내려갑니다. Redis가 없으면 비율 제한·예산·라우터 쿨다운이 클러스터 전체가 아니라 게이트웨이 프로세스별로 세어지니, per-key 제한이 의미 있게 하려면 게이트웨이를 단일 프로세스로 고정해야 해요. 누락되거나 모순된 입력은 apply 도중이 아니라 terraform plan 단계에서 실패를 알려주니까 그 점이 위안이 됩니다.
배포 확인
배포를 마친 뒤에는 게이트웨이가 데이터베이스에 닿는지 먼저 확인합니다.
curl -s https://llm.example.com/health/readiness
그다음 https://llm.example.com/ui에서 관리 UI에 로그인해 모델을 추가하고, 가상 키를 만들고, Playground 메시지를 보내 응답이 오는지 확인하세요. 이 흐름이 로드 밸런서·프록시·데이터베이스·프로바이더 자격증명 전체 경로를 증명해 줍니다. 이후에는 프로덕션 체크리스트로 보안을 강화하고, 이미지 서명을 Docker 이미지 보안 가이드로 검증하고, 매우 높은 처리량(1000+ RPS)이라면 Redis 트랜잭션 버퍼를 켜는 식으로 이어가면 됩니다.