LiteLLM 프로덕션 배포 — 내 환경에서 안전하게 게이트웨이를 올리는 법

LiteLLM 프로덕션 배포 — 내 환경에서 안전하게 게이트웨이를 올리는 법

로컬에서 한 줄로 띄운 LiteLLM 게이트웨이가 잘 도는 건 확인했는데, 이제 그걸 실제 운영 환경에 올리려고 하니 어디서부터 손대야 할지 막막할 때가 있어요. 이 가이드는 AWS, Google Cloud, Azure, 또는 어떤 Kubernetes 클러스터에서든 LiteLLM을 프로덕션으로 배포하는 방법을 안내합니다. 한 대의 머신에서 처음 올려보는 것이라면 먼저 Docker 퀵스타트를 보고 오시는 게 자연스러워요 — 이 페이지는 그 끝에서 시작합니다.

출처: 공식문서 — Production Deployment

배포 경로는 두 가지 — 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 트랜잭션 버퍼를 켜는 식으로 이어가면 됩니다.

더 알아보기