26O05d1

QK·7일 전

네. 지금 환경이라면 GPU Cluster를 단순 “vLLM 서버가 있는 K8s”가 아니라 독립적인 AI Serving Platform으로 설계하는 것이 좋습니다.

특히 중요한 전제는 다음입니다.

  • 현재 GPU Cluster: B300 × 8, 1 node
  • 6개월 이내: 동일/유사 GPU node 1대 추가
  • 주 용도: inference
  • Compute Cluster: JupyterLab / Spark / StarRocks / Trino / Polaris 등
  • Storage Cluster: MinIO/AiStor
  • GPU Cluster: 별도 Kubernetes
  • Cilium native routing + ClusterMesh
  • 현재 inter-node/inter-cluster 통신: Ethernet TCP/IP
  • 여러 팀/사용자가 공유
  • vLLM 0.30 기반
  • Stage1~7/production profile 체계를 이미 구축

이 조건이라면 아래 구조를 1차 목표 아키텍처로 권합니다.


1. 전체 아키텍처

                       ┌───────────────────────────────┐
                       │          USERS / APPS         │
                       │                               │
                       │ Jupyter / Spark / BI / Agent  │
                       │ Discovery / Wizard / Batch    │
                       └───────────────┬───────────────┘
                                       │
                                HTTPS / OpenAI API
                                       │
┌──────────────────── COMPUTE CLUSTER ─┼─────────────────────────┐
│                                      │                         │
│ JupyterLab   Spark   StarRocks   Trino   Polaris   Applications│
│                                      │                         │
│          Namespace / Team Identity / ServiceAccount            │
└──────────────────────────┬───────────┬─────────────────────────┘
                           │           │
                     Cilium ClusterMesh
                      Native Routing
                           │
              CiliumNetworkPolicy / Identity
                           │
                           ▼
┌────────────────────── GPU CLUSTER ──────────────────────────────┐
│                                                                │
│                  ┌────────────────────┐                        │
│                  │ Inference Gateway  │                        │
│                  │ Gateway API        │                        │
│                  │ Auth / Quota       │                        │
│                  │ Rate Limit         │                        │
│                  └─────────┬──────────┘                        │
│                            │                                   │
│                  ┌─────────▼──────────┐                        │
│                  │ Inference Router   │                        │
│                  │ / EPP              │                        │
│                  │                    │                        │
│                  │ model              │                        │
│                  │ queue              │                        │
│                  │ KV/cache locality  │                        │
│                  │ endpoint load      │                        │
│                  └─────────┬──────────┘                        │
│                            │                                   │
│             ┌──────────────┼───────────────┐                   │
│             │              │               │                   │
│             ▼              ▼               ▼                   │
│       ONLINE POOL     SMALL MODEL      DOCUMENT POOL           │
│                                                                │
│     DeepSeek V4.1     Qwen3.6          PaddleOCR               │
│     GLM-5.3-Flash     gpt-oss          Docling                 │
│                                                                │
│             │              │               │                   │
│             └──────────────┼───────────────┘                   │
│                            │                                   │
│                     GPU Scheduler                              │
│                            │                                   │
│             ┌──────────────▼──────────────┐                    │
│             │        B300 NODE #1         │                    │
│             │                             │                    │
│             │ GPU0 GPU1 GPU2 GPU3         │                    │
│             │ GPU4 GPU5 GPU6 GPU7         │                    │
│             └─────────────────────────────┘                    │
│                                                                │
│       DCGM / Prometheus / vLLM metrics / Hubble / OTel         │
└───────────────────────────┬────────────────────────────────────┘
                            │
                     Cilium ClusterMesh
                            │
                            ▼
┌──────────────────── STORAGE CLUSTER ────────────────────────────┐
│                                                                │
│                       MinIO / AIStor                            │
│                                                                │
│  model checkpoints │ documents │ results │ artifacts │ KV      │
│                                                                │
└────────────────────────────────────────────────────────────────┘

Cilium ClusterMesh는 pod-to-pod connectivity, cross-cluster service discovery/load balancing, cluster-aware network policy를 지원합니다. Native routing에서는 underlying network가 PodCIDR을 실제로 route할 수 있어야 하고 각 클러스터 PodCIDR도 겹치면 안 됩니다. Cilium 문서


2. 중요한 원칙: 사용자가 vLLM Pod를 직접 호출하게 하지 않습니다

이 구조는 피하는 게 좋습니다.

Jupyter ──────────────→ vLLM pod
Spark ────────────────→ vLLM pod
Discovery ────────────→ vLLM pod
Team A ───────────────→ vLLM pod
Team B ───────────────→ vLLM pod

처음에는 간단하지만 멀티테넌트 환경에서는 곧 문제가 됩니다.

대신 모든 요청을:

Client
  ↓
Inference Gateway
  ↓
Model Router
  ↓
InferencePool
  ↓
vLLM

로 통일하는 것을 권합니다.

2026년 기준 Kubernetes Gateway API Inference Extension은 self-hosted generative model용으로 Inference Gateway → InferencePool → Endpoint Picker(EPP) 구조를 제공합니다. Endpoint selection 때 serving metrics와 prefix-cache 같은 capability도 활용할 수 있도록 설계되어 있습니다. Kubernetes 게이트웨이 API 확장


3. GPU Cluster namespace도 역할별로 분리

예를 들면:

gpu-system
 ├─ NVIDIA GPU Operator
 ├─ DCGM Exporter
 └─ node components

inference-gateway
 ├─ Gateway
 ├─ EPP / Router
 ├─ quota
 └─ admission

inference-online
 ├─ deepseek-v4.1-flash
 └─ glm-5.3-flash

inference-small
 ├─ qwen3.6-35b
 └─ gpt-oss-20b

inference-document
 ├─ paddleocr
 └─ docling

inference-batch
 └─ glm-5.3

observability
 ├─ Prometheus
 ├─ Grafana
 ├─ OpenTelemetry
 └─ alerting

validation
 └─ Stage1~7 benchmark jobs

이렇게 서비스 클래스별 namespace로 분리하는 것이 팀별 namespace보다 GPU capacity 관리가 쉽습니다.

팀 identity는 Gateway/auth/quota 계층에서 따로 관리합니다.


4. 사용자/팀 단위 capacity 관리는 Gateway에서

예를 들어:

Team Discovery
    │
    ├─ 40 RPS
    ├─ concurrency 20
    └─ Priority HIGH

Team Ontology
    │
    ├─ 5 RPS
    ├─ concurrency 4
    └─ Priority LOW/BATCH

Team Wizard
    │
    ├─ 20 RPS
    ├─ concurrency 10
    └─ Priority NORMAL

Jupyter users
    │
    ├─ 2 RPS/user
    └─ Priority LOW

처럼 관리합니다.

GPU 자원 자체를 사용자에게 나누는 것보다:

requests/sec
concurrent requests
input tokens/min
output tokens/min
context length
queue depth

를 quota 단위로 삼는 게 inference에서는 훨씬 의미가 있습니다.


5. 실제 GPU allocation

1-node 시점의 초기 qualification topology는 이런 형태가 좋습니다.

B300 NODE #1
┌────────────────────────────────────────────┐
│                                            │
│ GPU0 ─┐                                    │
│ GPU1  │                                    │
│ GPU2  ├── Online Primary                   │
│ GPU3 ─┘   DeepSeek-V4.1 / GLM-5.3-Flash   │
│            TP4 candidate                   │
│                                            │
│ GPU4 ───── Qwen3.6 TP1                     │
│                                            │
│ GPU5 ───── gpt-oss TP1                     │
│                                            │
│ GPU6 ───── Document Pipeline               │
│            PaddleOCR / Docling             │
│                                            │
│ GPU7 ───── Burst / spare / document replica│
│                                            │
└────────────────────────────────────────────┘

다만 이것은 고정 configuration이 아닙니다.

v12 Stage7 결과가:

DeepSeek
 TP2 FAIL
 TP4 PASS + 30% headroom
 TP8 PASS

→ TP4

라면 GPU0~3을 배정하는 식입니다.


6. GPU7은 처음부터 꽉 채우지 않는 것을 권합니다

1-node밖에 없는 상황에서는 GPU 8개를 평상시에 100% 예약하지 않는 것이 중요합니다.

GPU7 정도는:

burst capacity
document replica
failed workload retry
model qualification
canary
temporary batch

용으로 남기는 편이 운영상 가치가 큽니다.

즉 정상 운영 목표를:

steady state
GPU reservation ≈ 75~87.5%

peak
GPU reservation = 100%

정도로 잡는 게 낫습니다.


7. 야간에는 GPU ownership 변경

Ontology는 야간이라고 했으므로 이 특성을 적극적으로 이용해야 합니다.

주간:

GPU0-3   Discovery
GPU4     Qwen
GPU5     gpt-oss
GPU6     Document
GPU7     Spare/Burst

야간에는 필요하면:

            drain / scale-down
                   ↓

GPU0 ─────────────────────┐
GPU1                      │
GPU2                      │
GPU3                      │
GPU4                      ├─ GLM-5.3 TP8
GPU5                      │
GPU6                      │
GPU7 ─────────────────────┘

                   ↓

           ontology batch

                   ↓

             scale-down

                   ↓

          daytime topology

로 전환합니다.

이건 Kubernetes CronJob 하나보다는 queue-aware scheduler/controller 형태로 발전시키는 게 좋습니다.


8. Batch가 Online을 밀어내면 안 됩니다

우선순위는 명확하게 두는 것을 권합니다.

PriorityClass

inference-critical     100000
inference-online        50000
inference-document      20000
inference-batch          5000
inference-validation     1000

하지만 GPU pod를 무조건 Kubernetes preemption으로 죽이는 구조는 권하지 않습니다.

먼저:

Gateway admission
       ↓
queue control
       ↓
scale decision
       ↓
graceful drain
       ↓
GPU reassignment

순서로 처리하고 K8s preemption은 마지막 보호수단으로 두는 편이 안전합니다.


9. vLLM capacity control

각 model server는 v12가 만든 production profile을 사용합니다.

Stage7
 ↓
TP sweep
 ↓
adaptive saturation
 ↓
SLO/headroom
 ↓
production profile
 ↓
Helm values

예를 들어:

deepseek:
  gpu: 4

  vllm:
    tensorParallelSize: 4

    maxModelLen: 131072
    maxNumSeqs: 32
    maxNumBatchedTokens: 8192

    gpuMemoryUtilization: 0.90

    prefixCaching: true
    kvCacheDtype: fp8

같은 값은 Git에 사람이 작성하는 값이 아니라 Stage7 qualification 결과에서 승격된 값으로 만드는 것이 좋습니다.


10. Model configuration GitOps 구조

추천 구조는:

ai-serving-config/
│
├── models/
│   ├── deepseek-v4.1-flash/
│   │   ├── qualification.yaml
│   │   ├── production-profile.yaml
│   │   └── values.yaml
│   │
│   ├── glm-5.3-flash/
│   ├── qwen3.6-35b/
│   └── gpt-oss-20b/
│
├── gateway/
│
├── policies/
│
├── quotas/
│
└── environments/
    ├── validation
    └── production

가 좋습니다.

변경 절차는:

new checkpoint / vLLM
          ↓
Stage7
          ↓
qualification
          ↓
production-profile.yaml
          ↓
Git PR
          ↓
review
          ↓
Helm / GitOps
          ↓
canary
          ↓
production

가 됩니다.


11. Model storage는 GPU node local NVMe + AIStor 2-tier

이 부분은 이미 Stage3a10 설계와 잘 연결됩니다.

                MinIO / AIStor
                       │
             source of truth
                       │
        ┌──────────────┴───────────────┐
        │                              │
        ▼                              ▼
model checkpoint                 documents/data
        │
        ▼
GPU node local NVMe
        │
  model cache
        │
        ▼
     vLLM

모델을 매번 AIStor에서 직접 읽어서 시작하지 말고, GPU node local NVMe에 cache를 두는 게 좋습니다.

AIStor
  ↓
model sync
  ↓
local NVMe
  ↓
checksum/revision verification
  ↓
vLLM startup

구조를 권합니다.


12. KV cache도 별도 계층

초기에는:

GPU HBM KV
   ↓
Local NVMe KV
   ↓
Remote AIStor/MemKV

순으로 생각하면 됩니다.

하지만 Stage3a10/Stage7에서 GPU KV만으로 SLO와 capacity가 충분하면 굳이 remote tier를 사용하지 않습니다.

GPU-only PASS
      ↓
     사용

GPU-only capacity 부족
      ↓
local NVMe

local도 부족 / reuse 요구
      ↓
remote

가 좋습니다.


13. Network architecture

현재 RDMA가 없으므로 inference 요청과 storage traffic을 구분해서 보는 게 중요합니다.

                  Ethernet Fabric
                       │
          ┌────────────┼─────────────┐
          │            │             │
       Service       Storage      ClusterMesh
       traffic       traffic        traffic
          │            │             │
       HTTP/S3        S3/TCP       Pod TCP/IP

가능하다면 VLAN/VRF 또는 최소한 routing/QoS 관점에서:

Management
Pod/Service
Storage

traffic을 분리하는 것을 권합니다.


14. Cilium native routing에서 특히 주의할 점

3개 cluster PodCIDR은 반드시 겹치지 않게 잡습니다.

예:

Compute
10.10.0.0/16

GPU
10.20.0.0/16

Storage
10.30.0.0/16

그리고 underlying network에서 이 PodCIDR이 실제로 route되어야 합니다.

Cilium native routing은 encapsulation 없이 Linux routing을 사용하기 때문에 물리 네트워크가 PodCIDR reachability를 제공해야 합니다. ClusterMesh에서도 모든 cluster의 PodCIDR은 unique해야 하고 native-routing CIDR은 연결된 PodCIDR들을 포괄해야 합니다. Cilium 문서


15. ClusterMesh를 “모두 허용”으로 사용하면 안 됩니다

ClusterMesh는 연결성을 제공할 뿐입니다.

보안은:

default deny
       +
explicit allow

를 권합니다.

예:

Compute
   │
   │ HTTPS
   ▼
Inference Gateway

Inference Gateway
   │
   │ HTTP
   ▼
Inference Pool

Inference Pods
   │
   │ S3
   ▼
AIStor

만 허용합니다.

Compute → vLLM Pod 직접 접근은 차단합니다.

Cilium은 cross-cluster endpoint identity를 사용한 정책을 지원하지만, 정책 자체는 각 클러스터에 배포해야 합니다. Cilium 문서


16. Network observability

여기서는 Hubble을 적극적으로 쓰는 것이 좋습니다.

Compute
   ↓
Gateway
   ↓
vLLM
   ↓
AIStor

흐름에서:

latency
drops
TCP reset
retransmission
denied flow
service dependency

를 봅니다.

Hubble Relay를 사용하면 cluster 단위뿐 아니라 ClusterMesh 환경의 multi-cluster visibility도 제공할 수 있습니다. Cilium 문서


17. GPU observability는 4단계로 봅니다

L1 — Hardware

DCGM

GPU utilization
HBM
power
temperature
XID
ECC
NVLink

L2 — vLLM

TTFT
ITL
queue
running requests
waiting requests
KV usage
prefix cache hit
preemption
tokens/sec

vLLM은 /metrics를 통해 KV usage, prefix-cache query/hit, running/waiting request 등의 production metric을 제공합니다. vLLM

L3 — Service

RPS
P50/P95/P99
429
5xx
timeout
queue depth
tokens/min

L4 — Tenant

team
user
application
model

requests
input tokens
output tokens
GPU cost
latency
errors

입니다.


18. capacity dashboard를 별도로 만드세요

운영자가 가장 먼저 봐야 하는 화면은:

GPU CLUSTER CAPACITY

B300 GPUs
8 total

Allocated       6
Reserved        1
Available       1

──────────────────────

DeepSeek TP4
GPU        4
RPS       22 / capacity 31
C         24 / SLO max 48
KV        67%
P99 TTFT  1.4s

Qwen
GPU        1
RPS        6 / 20

Document
GPU        1
pages/min 180 / 350

──────────────────────

Cluster headroom
GPU           25%
Online RPS    34%
KV            33%

같은 형태여야 합니다.

GPU utilization 90% 하나만 보고 capacity를 판단하면 안 됩니다.


19. 2번째 B300 node가 들어오면

여기서 지금 설계를 잘해놓은 효과가 나타납니다.

GPU CLUSTER

          Inference Gateway
                 │
         Inference Router
                 │
        ┌────────┴────────┐
        │                 │
        ▼                 ▼

 B300 NODE #1        B300 NODE #2
 8 GPU               8 GPU

 Online              Online
 Small               Batch
 Document            Spare

또는 online HA 관점에서는:

DeepSeek

Node1
GPU0-3
Replica A

Node2
GPU0-3
Replica B

       ▲
       │
InferencePool
       │
EPP

가 됩니다.

InferencePool은 label selector로 endpoint pod들을 묶고 EPP가 그 endpoint들 중 요청을 보낼 곳을 선택하는 모델입니다. Kubernetes 게이트웨이 API 확장


20. 저는 2-node가 되면 “TP8 across nodes”를 기본으로 하지 않겠습니다

RDMA가 없는 상태라면 특히 그렇습니다.

즉:

BAD DEFAULT

Node1 GPU0-3
       │
    TCP/IP
       │
Node2 GPU0-3

       TP8

보다:

PREFERRED

Node1
TP4 replica A

Node2
TP4 replica B

를 먼저 검토합니다.

모델이 한 노드에 들어가는 한 tensor parallel communication을 node 내부 NVLink/NVSwitch domain에 유지하는 편이 일반적으로 유리합니다.

두 노드가 필요한 초대형 모델은 Stage7에서 별도로 TCP distributed inference 성능을 qualification 해야 합니다.


21. 2-node 시점의 권장 목표

                        Gateway
                           │
                  Inference Router
                           │
            ┌──────────────┴──────────────┐
            │                             │
         NODE #1                       NODE #2
        8 × B300                      8 × B300
            │                             │
     ┌──────┴──────┐              ┌──────┴──────┐
     │             │              │             │
 Online A       Small          Online B       Batch
 TP4            models          TP4            GLM
     │             │              │             │
     └─────────────┴──────┬───────┴─────────────┘
                          │
                      AIStor

이렇게 하면 node 한 대가 장애 나더라도 주요 online service를 다른 node에서 유지할 수 있는 구조로 발전시킬 수 있습니다.


22. 결국 전체 운영 제어 루프

제가 이 환경에서 가장 중요하게 보는 구조는 이것입니다.

                  ┌──────────────┐
                  │ Real Traffic │
                  └──────┬───────┘
                         │
                         ▼
                Prometheus / OTel
                         │
       ┌─────────────────┼─────────────────┐
       │                 │                 │
      SLO             Capacity          Quality
       │                 │                 │
       └─────────────────┼─────────────────┘
                         ▼
                    Stage7
                         │
               TP / C / KV tuning
                         │
                         ▼
             production-profile.yaml
                         │
                         ▼
                  Helm values
                         │
                         ▼
                     GitOps
                         │
                         ▼
                 GPU Deployment
                         │
                         ▼
                Stage7D validation

즉 Stage7이 단순 benchmark 도구가 아니라 GPU Serving Platform의 capacity planner 역할을 하게 만드는 겁니다.


최종 권장 구조

현재 1-node에서는 GPU를 Kubernetes scheduler에게 완전히 자유롭게 맡기기보다 Stage7에서 검증된 “GPU allocation profile” 단위로 운영하는 것을 권합니다.

그리고 architecture를 크게 세 plane으로 분리하면 관리하기 좋습니다.

┌──────────────── CONTROL PLANE ────────────────┐
│                                               │
│ Gateway API / InferencePool / EPP             │
│ GitOps / Helm                                 │
│ Quota / Admission / Priority                  │
│ Stage7 Qualification                          │
└──────────────────────┬────────────────────────┘
                       │
┌──────────────── DATA PLANE ───────────────────┐
│                                               │
│ vLLM / PaddleOCR / Docling                    │
│ B300 GPU                                      │
│ Local NVMe model/KV cache                     │
└──────────────────────┬────────────────────────┘
                       │
┌──────────── OBSERVABILITY PLANE ──────────────┐
│                                               │
│ DCGM                                          │
│ vLLM metrics                                  │
│ Prometheus / Grafana                          │
│ OpenTelemetry                                 │
│ Cilium Hubble                                 │
│ Tenant usage / capacity / SLO                 │
└───────────────────────────────────────────────┘

이 구조라면 지금 8 GPU 한 노드에서도 과하지 않고, 6개월 뒤 16 GPU/2-node가 되었을 때 Gateway/EPP/InferencePool 아래에 replica와 capacity만 추가하면 되기 때문에 아키텍처를 다시 설계할 필요가 없습니다.

다음 단계에서는 이 아키텍처를 실제 배포 구조로 내려서 namespace 설계 + Gateway API/InferencePool + CiliumNetworkPolicy + PriorityClass/ResourceQuota + Prometheus/DCGM/Hubble + 모델별 GPU 배치 + 주간/야간 전환까지 포함한 K8s 논리/물리 아키텍처 다이어그램과 YAML 설계로 구체화하는 것이 좋습니다.


네. 그러면 이전 설계에서 Cilium ClusterMesh를 클러스터 간 연결의 전제로 둔 부분을 빼는 것이 맞습니다.

현재 네트워크를 이렇게 이해하겠습니다.

Compute Cluster ─┐
                 ├── Private Network ── Storage Cluster
Storage Cluster ─┘

AI/GPU Cluster
 B300 Node
 ├─ Private Network 없음
 └─ Public Network만 존재

이 경우 GPU Cluster를 기존 클러스터와 억지로 하나의 flat pod network로 만들기보다, GPU Cluster를 독립된 서비스 존(Service Zone) 으로 두고 L3/L7 API + Storage endpoint를 통해 연결하는 구조를 권합니다.

수정된 전체 구조

                Existing Private Network
┌─────────────────────────────────────────────────────────┐
│                                                         │
│  ┌──────────── COMPUTE CLUSTER ──────────────┐          │
│  │ JupyterLab / Spark / Trino / StarRocks    │          │
│  │ Polaris / Applications                    │          │
│  └─────────────────┬─────────────────────────┘          │
│                    │                                    │
│                    │ Private NW                         │
│                    │                                    │
│  ┌─────────────────▼─────────────────────────┐          │
│  │            STORAGE CLUSTER                │          │
│  │                                           │          │
│  │            MinIO / AIStor                 │          │
│  └─────────────────┬─────────────────────────┘          │
│                    │                                    │
└────────────────────┼────────────────────────────────────┘
                     │
              Controlled L3/L4
               TCP/IP / TLS
                     │
        ───────── Firewall ─────────
                     │
                     │ Public/Service Network
                     │
┌────────────────────▼────────────────────────────────────┐
│                  GPU / AI CLUSTER                       │
│                                                       │
│   ┌───────────────────────────────────────────────┐   │
│   │ Inference Gateway                            │   │
│   │ TLS / Auth / Quota / Rate Limit              │   │
│   └──────────────────────┬────────────────────────┘   │
│                          │                             │
│                ┌─────────▼─────────┐                   │
│                │ Inference Router  │                   │
│                │ EPP / Model Route │                   │
│                └─────────┬─────────┘                   │
│                          │                             │
│          ┌───────────────┼──────────────┐              │
│          ▼               ▼              ▼              │
│      Online Pool     Small LLM      Document           │
│      DeepSeek        Qwen           PaddleOCR          │
│      GLM Flash       gpt-oss        Docling            │
│                                                       │
│              B300 × 8 / Local NVMe                     │
│                                                       │
│  DCGM / Prometheus / OTel / Hubble                     │
└────────────────────────────────────────────────────────┘

핵심 변화는 Compute → GPU Pod 직접 연결을 없애는 것입니다.

Compute 쪽에서는 오직:

https://ai-api.company.internal/v1/...

같은 Inference Gateway endpoint 하나만 알도록 만드는 편이 좋습니다.

ClusterMesh는 어디까지 쓰나

GPU Cluster와 기존 Compute/Storage Cluster 사이에는 사용하지 않습니다.

대신 각 클러스터 내부에서는 Cilium을 계속 사용합니다.

Compute K8s
 └─ Cilium native

Storage K8s
 └─ Cilium native

GPU K8s
 └─ Cilium native

Compute ↔ Storage가 현재 ClusterMesh로 잘 연결되어 있다면 그 부분은 유지할 수 있습니다.

Compute ←── ClusterMesh/Private NW ──→ Storage

                    X
                    │
               ClusterMesh
                    │
                    X

                  GPU

GPU Cluster는 별도 security/network domain으로 봅니다.


오히려 이 구조가 멀티테넌트 inference에는 괜찮습니다

사용자가 GPU pod까지 직접 접근할 필요가 없기 때문입니다.

Jupyter ──────┐
Spark ────────┤
Discovery ────┤
Wizard ───────┼──→ AI Gateway ─→ Router ─→ vLLM
Ontology ─────┤
Team A ───────┤
Team B ───────┘

이렇게 하면 Gateway에서:

Identity
  ↓
Authentication
  ↓
Team quota
  ↓
Rate limit
  ↓
Concurrency limit
  ↓
Model authorization
  ↓
Inference routing

을 모두 통제할 수 있습니다.

즉 private network가 없는 것이 inference API 관점에서는 치명적인 문제가 아닙니다.


더 중요한 문제는 Storage입니다

Inference API는 HTTPS라 public/service network를 거쳐도 상대적으로 부담이 적지만, GPU node가 MinIO/AIStor에서 대형 checkpoint를 읽는 것은 얘기가 다릅니다.

예를 들어:

GPU Node
   │
   │ TCP/IP
   │
   ▼
Firewall/Public NW
   │
   ▼
AIStor

에서 300~700GB 모델을 pod restart 때마다 가져오면 문제가 됩니다.

그래서 GPU node의 Local NVMe cache가 더 중요해집니다.

                  AIStor
                    │
              TCP/IP + TLS
                    │
                    ▼
             GPU Local NVMe
             Model Cache
                    │
        ┌───────────┴──────────┐
        │                      │
     model A                model B
        │                      │
        ▼                      ▼
      vLLM                   vLLM

AIStor는 source of truth이고, 실제 serving은 local NVMe를 사용합니다.

모델 배포 흐름

Model Registry / AIStor
          │
          │ download once
          ▼
GPU Local NVMe

/models/
 ├─ deepseek-v4.1-flash/<revision>
 ├─ glm-5.3-flash/<revision>
 ├─ qwen3.6/<revision>
 └─ gpt-oss/<revision>

          ↓

checksum / revision validation

          ↓

vLLM

그래야 network 장애가 발생해도 이미 cache된 모델은 계속 serving할 수 있습니다.


Remote KV는 더 신중해야 합니다

이전 Stage3a10의:

GPU HBM
 ↓
Local NVMe
 ↓
Remote MinIO/MemKV

중 Remote tier의 우선순위를 더 낮추는 게 좋습니다.

현재 topology라면:

GPU
 │
 │ public/service TCP/IP
 ▼
AIStor

이므로 KV path에 network latency와 bandwidth 영향을 직접 받습니다.

따라서 초기 production은:

1순위  GPU HBM KV
         ↓
2순위  GPU node Local NVMe
         ↓
3순위  Remote KV
       (Stage3a10 PASS 시에만)

를 권합니다.

특히 online Discovery는 remote KV 없이 SLO가 나오면 그대로 두는 게 좋습니다.


Network를 두 종류로 논리적으로 분리

GPU node에 NIC가 하나뿐이어도 traffic class는 분리해서 관리할 필요가 있습니다.

                 GPU Node
                    │
        ┌───────────┼───────────┐
        │                       │
        ▼                       ▼

 Inference Traffic         Storage Traffic

 HTTPS/API                 S3/TCP
 small packets             large sequential
 latency sensitive         bandwidth sensitive
        │                       │
        ▼                       ▼
 Gateway                 AIStor/MinIO

즉 같은 물리 NIC라도 firewall/QoS/monitoring에서 별도 flow로 봐야 합니다.

가능하다면 장기적으로 GPU node에 private/storage NIC 추가를 가장 우선적인 네트워크 개선으로 권합니다.


외부에 GPU Node 자체를 노출하면 안 됩니다

"public network"가 실제 인터넷 접근 가능한 public IP 의미라면 특히 중요합니다.

구조를:

Internet/Public
     │
     ▼
Firewall / LB
     │
     ▼
Inference Gateway
     │
     X
vLLM 직접 접근 불가

로 만들어야 합니다.

다음 포트들은 외부에 직접 노출하지 않는 것을 권합니다.

vLLM :8000
Prometheus metrics
DCGM metrics
Kubernetes API
kubelet
etcd
Hubble
NodePort
MinIO credentials/API

외부에 노출되는 것은 가능하면 443/TCP → Gateway 하나로 제한합니다.


Compute → GPU 접근

Compute Cluster에서는:

Jupyter Pod
    │
    │ HTTPS
    ▼
AI Gateway VIP/FQDN
    │
    ▼
GPU Cluster

만 허용합니다.

예:

api.ai.example.internal

DNS는 private DNS에 있어도 괜찮습니다.

중요한 것은 그 FQDN이 GPU cluster의 Gateway/LB endpoint를 가리키도록 하는 것입니다.


Storage → GPU 접근은 반대로 설계

GPU가 Storage를 호출합니다.

GPU Node
    │
    │ TLS / S3
    ▼
AIStor endpoint

따라서 firewall은 최소한:

Compute → GPU
HTTPS 443

GPU → Storage
S3 HTTPS 443

GPU → DNS
DNS

GPU → NTP
NTP

GPU → Registry
HTTPS

GPU → Observability
필요 포트

정도로 좁힙니다.

Storage → GPU inbound는 기본적으로 필요 없습니다.


Observability도 Push/Pull 경계를 고려

Prometheus가 기존 Compute Cluster에 있다고 GPU Cluster의 private pod IP를 scrape하려고 하면 문제가 생깁니다.

따라서 중앙 observability가 필요하다면:

GPU Cluster

DCGM
vLLM
Cilium
K8s
 ↓
Local Prometheus
 ↓
remote_write
 ↓
Central Metrics

가 좋습니다.

즉:

BAD

Central Prometheus
      │
      └────→ 모든 GPU Pod scrape

보다:

GOOD

GPU Local Prometheus
        │
        │ remote_write TLS
        ▼
Central Metrics

를 권합니다.

로그/trace도 비슷하게:

GPU OTel Collector
       │
       ▼
Central OTel / Logging

형태로 GPU → 중앙 outbound 중심으로 만듭니다.


그러면 GPU Cluster 내부 architecture는 그대로 유지 가능

중요한 점은 외부 연결 구조가 바뀌었을 뿐, GPU cluster 내부 architecture는 거의 바뀌지 않습니다.

┌──────────── GPU CLUSTER ────────────────┐
│                                        │
│           External HTTPS               │
│                 │                      │
│                 ▼                      │
│        ┌─────────────────┐             │
│        │ Gateway API     │             │
│        │ Auth / Quota    │             │
│        └────────┬────────┘             │
│                 │                      │
│        ┌────────▼────────┐             │
│        │ Inference EPP   │             │
│        └────────┬────────┘             │
│                 │                      │
│       ┌─────────┼─────────┐            │
│       │         │         │            │
│       ▼         ▼         ▼            │
│    Online     Small    Document        │
│                                        │
│  ┌─────────────────────────────────┐   │
│  │          B300 × 8               │   │
│  │                                 │   │
│  │ TP4 │ TP1 │ TP1 │ Document │   │   │
│  └─────────────────────────────────┘   │
│                 │                      │
│             Local NVMe                 │
│                                        │
│  Prometheus / DCGM / OTel / Hubble     │
│                                        │
└────────────────────────────────────────┘

6개월 뒤 Node #2 추가도 문제없습니다

두 번째 node는 같은 GPU Kubernetes cluster에 넣습니다.

                    AI Gateway
                        │
                  Inference EPP
                        │
               ┌────────┴────────┐
               │                 │
               ▼                 ▼
          B300 Node #1      B300 Node #2
             8 GPU             8 GPU

             TP4 A             TP4 B
               │                 │
               └──── replicas ───┘

두 GPU node가 같은 L2/L3 network에서 직접 통신 가능하게 구성하는 것은 매우 중요합니다.

특히 Node #2를 추가할 때는 GPU node 간 전용 private/backend network를 같이 추가하는 것을 강하게 권합니다.

장기 목표는:

GPU NODE #1                    GPU NODE #2

Public/Service NIC             Public/Service NIC
      │                              │
      └────── API traffic ───────────┘


Backend/Private NIC            Backend/Private NIC
      │                              │
      ├──── K8s / Cilium ────────────┤
      ├──── NCCL ────────────────────┤
      ├──── model distribution ──────┤
      └──── Storage ─────────────────┘

가 되어야 합니다.

RDMA까지 당장 갈 필요는 없더라도 GPU node간 backend Ethernet은 만드는 편이 좋습니다.


수정된 최종 권장 Architecture

따라서 전체 시스템을 다음처럼 잡겠습니다.

                    ┌─────────────────────┐
                    │ Users / Applications│
                    └──────────┬──────────┘
                               │
┌──────── PRIVATE ─────────────┼─────────────────────────┐
│                              │                         │
│                       Compute Cluster                  │
│                  Jupyter/Spark/Trino/...               │
│                              │                         │
│                    Private Network                    │
│                              │                         │
│                       Storage Cluster                  │
│                        MinIO/AIStor                    │
│                              │                         │
└──────────────────────────────┼─────────────────────────┘
                               │
                      Controlled TCP/TLS
                               │
                      Firewall / Routing
                               │
┌──────── GPU SERVICE ZONE ────▼─────────────────────────┐
│                                                       │
│                   AI Gateway :443                     │
│                         │                             │
│                Auth / Quota / Rate                    │
│                         │                             │
│                  Inference EPP                        │
│                         │                             │
│         ┌───────────────┼───────────────┐             │
│         │               │               │             │
│      Online          Small           Document         │
│         │               │               │             │
│         └───────────────┼───────────────┘             │
│                         │                             │
│                     B300 × 8                          │
│                         │                             │
│                    Local NVMe                         │
│                         │                             │
│              Model / KV local cache                  │
│                                                       │
│        DCGM / Prometheus / OTel / Hubble             │
│                         │                             │
│                  remote_write                        │
└─────────────────────────┼─────────────────────────────┘
                          │
                     outbound TLS
                          │
                          ▼
                Central Observability

정리하면 ClusterMesh를 포기한다고 전체 아키텍처가 약해지는 게 아닙니다. 오히려 GPU Cluster를 API 기반의 별도 security zone으로 만들고, 443 Gateway를 명확한 ingress 경계로 두는 것이 현재 물리 네트워크에는 더 자연스럽습니다.

그리고 지금 환경에서 네트워크 투자 우선순위를 하나만 고른다면 RDMA보다 먼저 GPU node에 private/backend network를 추가하는 것을 권합니다. Node #2가 들어오기 전에 해두면 GPU↔GPU, GPU↔Storage, K8s/Cilium control/data traffic의 기반이 생기고, 이후 필요하면 그 backend network를 RDMA/RoCE로 발전시킬 수 있습니다.


네. 핵심부터 말하면 “기본 Kubernetes만으로 구현”하기보다는, Kubernetes Gateway API + Gateway API Inference Extension + 이를 지원하는 Gateway 구현체를 사용하는 구조를 권합니다.

2026년 현재 Kubernetes Gateway API Inference Extension은 inference-specific routing을 위한 표준 API를 제공하며, 핵심 리소스가 InferencePool이고 실제 endpoint 선택 로직은 EPP(Endpoint Picker) 가 담당합니다.

1. 먼저 역할을 정확히 나누면

전체 request path는 이렇게 생각하면 됩니다.

Jupyter / Spark / Application / User
                 │
                 │ HTTPS
                 ▼
        ┌─────────────────────┐
        │ Gateway / Gateway API│
        │                     │
        │ TLS termination     │
        │ Auth                │
        │ Rate limit          │
        │ HTTP routing        │
        └──────────┬──────────┘
                   │
                   ▼
        ┌─────────────────────┐
        │   InferencePool     │
        │                     │
        │ "이 모델의 serving  │
        │  endpoint 집합"     │
        └──────────┬──────────┘
                   │
                   ▼
        ┌─────────────────────┐
        │ EPP                 │
        │ Endpoint Picker     │
        │                     │
        │ 어느 vLLM pod로     │
        │ 보낼 것인가 결정    │
        └──────────┬──────────┘
                   │
          ┌────────┴────────┐
          ▼                 ▼
      vLLM Pod A        vLLM Pod B
      B300 Node1        B300 Node2

여기서 흔히 말하는 Inference Router는 별도의 네 번째 필수 Kubernetes 객체라고 생각하지 않는 게 좋습니다.

실질적으로는:

Inference-aware routing
        =
Gateway + InferencePool + EPP

라고 보는 편이 정확합니다.


2. Gateway의 역할

Gateway는 외부 세계와 GPU serving platform 사이의 문입니다.

현재 환경에서는 특히 중요합니다.

Compute Cluster
 Jupyter
 Spark
 Application
     │
     │ HTTPS :443
     ▼
━━━━━━━━ Security Boundary ━━━━━━━━

 GPU Cluster

     Gateway
        │
        ▼
 inference

Gateway에서 담당할 것은 크게 다음입니다.

  • TLS termination
  • Host/path routing
  • 인증 연계
  • team/application identity
  • rate limiting
  • request size 제한
  • timeout
  • 기본적인 traffic policy
  • inference routing으로 request 전달

예를 들어 외부에는:

https://ai.company/v1/chat/completions

하나만 공개합니다.

사용자는:

{
  "model": "deepseek-v4.1-flash",
  ...
}

처럼 OpenAI-compatible API를 호출하게 합니다.

사용자가:

http://vllm-deepseek-pod-7f9xxx:8000

같은 내부 주소를 알아서는 안 됩니다.


3. Gateway API는 Kubernetes API이지 Gateway 프로그램 자체가 아닙니다

이 부분이 꽤 중요합니다.

Gateway API는 Kubernetes에 다음 같은 리소스를 추가하는 API/CRD입니다.

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute

하지만 CRD를 설치했다고 packet을 실제로 처리해주는 것은 아닙니다.

실제 구현체가 필요합니다.

구조가:

Kubernetes

GatewayClass
Gateway
HTTPRoute
InferencePool
      │
      │ desired configuration
      ▼
Gateway implementation
      │
      ▼
실제 network traffic

입니다.


4. 현재 환경에서는 Cilium Gateway API를 우선 검토할 수 있습니다

이미 GPU K8s에서 Cilium을 사용할 예정이므로 자연스러운 선택입니다.

Cilium은 Kubernetes Gateway API를 지원하고 Envoy를 이용해 L7 Gateway 기능을 제공합니다.

즉 별도의 NGINX ingress를 또 집어넣지 않고:

Cilium
 │
 ├─ CNI
 ├─ NetworkPolicy
 ├─ Service
 ├─ Gateway API
 └─ Envoy

형태를 고려할 수 있습니다.

다만 여기서 주의할 게 있습니다.

Cilium Gateway API 지원과 Gateway API Inference Extension 지원은 같은 의미가 아닙니다.

일반:

Gateway
HTTPRoute
GRPCRoute

지원과

InferencePool
EPP

integration은 별도로 확인해야 합니다.

따라서 production 구현을 결정할 때는 사용하는 정확한 Cilium/Gateway 버전에서 Inference Extension 호환성을 검증해야 합니다.


5. InferencePool은 무엇인가

InferencePool은 일반 Kubernetes Service와 약간 다르게 생각하면 됩니다.

예를 들어:

DeepSeek service

가 있고 실제 endpoint가:

DeepSeek

Pod A
Node1 / GPU0-3
TP4

Pod B
Node2 / GPU0-3
TP4

라고 합시다.

일반 Service라면 대략:

request
   │
   ▼
Service
   │
   ├─ Pod A
   └─ Pod B

이고 endpoint 선택이 inference workload를 깊게 이해하지 않습니다.

InferencePool은:

InferencePool: deepseek-v4.1
              │
              ├─ Pod A
              │
              └─ Pod B

라는 동일 inference workload를 처리할 수 있는 endpoint pool을 정의합니다.

공식 spec에서도 InferencePool은 inference workload endpoint의 논리적 그룹이며 selector로 serving pod를 식별합니다.


6. 왜 그냥 Service round-robin으로 안 보내나

LLM은 일반 web server와 특성이 다르기 때문입니다.

예를 들어:

Pod A
running requests = 25
KV cache = 91%
queue = 18

Pod B
running requests = 7
KV cache = 42%
queue = 1

라고 합시다.

일반 round-robin이면:

A → B → A → B

할 수 있습니다.

하지만 inference router는:

A
queue 18
KV 91%

B
queue 1
KV 42%

        ↓

      Pod B

를 선택할 수 있습니다.


7. EPP가 그래서 핵심입니다

EPP = Endpoint Picker입니다.

InferencePool에 Pod가 4개 있다고 하면:

InferencePool
     │
 ┌───┼───┬───┐
 A   B   C   D

EPP가 request마다:

A/B/C/D 중 어느 endpoint가 이 요청에 가장 적절한가?

를 결정합니다.

Gateway API Inference Extension architecture에서도 EPP가 inference-specific metrics를 이용해 endpoint를 선택하고 Gateway가 그 선택에 따라 request를 전달하는 구조입니다.


8. EPP가 볼 수 있는 정보

여기가 LLM serving에서 중요합니다.

예를 들어:

Request

model = DeepSeek
prompt tokens = 24K
tenant = Discovery
priority = high

가 들어왔다고 합시다.

EPP 입장에서는 endpoint마다:

Pod A

running       18
waiting       12
KV usage      82%
prefix match  HIGH
Pod B

running        8
waiting        2
KV usage      43%
prefix match  LOW

같은 정보가 있을 수 있습니다.

단순 load 관점에서는 B인데, A가 동일한 system prompt/prefix KV를 이미 가지고 있다면 A가 더 유리할 수도 있습니다.

그래서 판단은 개념적으로:

Score(endpoint) =

    load score
  + queue score
  + cache locality score
  + model compatibility
  + request priority

같아집니다.

이것이 일반 HTTP load balancer와 inference-aware router의 가장 큰 차이입니다.


9. 지금 1-node에서는 EPP가 별 필요 없어 보일 수도 있습니다

맞습니다.

현재:

DeepSeek
    │
    ▼
TP4 Pod 1개

라면 EPP가 선택할 endpoint가 하나뿐입니다.

그래서 당장은:

Gateway
   ↓
InferencePool
   ↓
EPP
   ↓
vLLM #1

이 다소 과해 보일 수 있습니다.

그런데 6개월 뒤:

              DeepSeek Pool

        ┌──────────┴──────────┐
        │                     │
Node #1                    Node #2

TP4 replica A             TP4 replica B

가 되면 EPP가 의미를 갖기 시작합니다.

따라서 지금부터 API 구조를 만들어 두되 routing algorithm을 복잡하게 만들 필요는 없습니다.


10. 저는 1단계를 단순하게 시작하겠습니다

Phase 1 — 1 node

Cilium Gateway API
       │
       ▼
InferencePool
       │
       ▼
Default EPP
       │
       ▼
vLLM

EPP custom logic을 직접 만들지 않습니다.

이 상태에서 먼저:

Gateway
auth
quota
rate limit
metrics
model routing

을 안정화합니다.


11. 2-node가 되면 inference-aware routing 강화

6개월 후:

                    Gateway
                       │
                       ▼
                InferencePool
                       │
                       ▼
                     EPP
                       │
            ┌──────────┴──────────┐
            │                     │
         Node #1               Node #2
            │                     │
       DeepSeek A             DeepSeek B

에서 EPP가:

queue depth
KV cache state
active requests
request cost

등을 보고 선택하게 합니다.

이 단계에서 prefix-aware routing이 가치가 있는지 Stage7 workload로 검증하면 됩니다.


12. 모델 선택과 endpoint 선택은 구분해야 합니다

이게 설계상 중요합니다.

사용자가:

{
  "model": "deepseek-v4.1-flash"
}

라고 요청했을 때 먼저 하는 것은 Model Routing입니다.

request
   │
   │ model=deepseek
   ▼
DeepSeek InferencePool

그 다음이 Endpoint Routing입니다.

DeepSeek InferencePool

        │
        ▼

       EPP

    ┌───┴───┐
    ▼       ▼

Pod A     Pod B

즉:

MODEL ROUTING

deepseek
   ↓
DeepSeek Pool


ENDPOINT ROUTING

DeepSeek Pool
   ↓
EPP
   ↓
Pod B

두 단계를 분리해서 생각해야 합니다.


13. 사용자/팀 quota는 EPP에 넣지 않는 것을 권합니다

예를 들어:

Discovery Team
40 RPS
C20

Wizard Team
10 RPS
C8

이런 것은 EPP 책임이 아닙니다.

Gateway/admission 계층에서 처리합니다.

Client
   │
   ▼
┌───────────────────────┐
│ Gateway               │
│                       │
│ Auth                   │
│ Tenant                 │
│ Quota                  │
│ Rate limit             │
│ Concurrency limit      │
└───────────┬───────────┘
            │
            ▼
      Model Routing
            │
            ▼
      InferencePool
            │
            ▼
           EPP
            │
            ▼
          vLLM

이렇게 책임을 나누는 것이 좋습니다.


14. Queue management도 중요합니다

Gateway에서 모든 요청을 무한정 받아 vLLM queue에 밀어 넣으면 안 됩니다.

예를 들어 Stage7에서 DeepSeek TP4가:

SLO capacity
C = 40

production headroom 적용
recommended admission = 30

으로 결정됐다고 합시다.

그러면:

running + admitted

0 ─────────── 30 ───── 40 ─────────→

              │         │
           admission    absolute
             limit       limit

식으로 운영합니다.

31번째부터는 정책에 따라:

short queue
429
retry-after

등을 사용합니다.

GPU가 처리하지 못할 request를 Gateway에서 미리 제어하는 것이 tail latency 폭증을 막는 데 중요합니다.


15. v12 Stage7과 바로 연결됩니다

현재 만든 구조가 여기서 상당히 유용합니다.

Stage7

TP4
max SLO concurrency = 48

production peak = 30

headroom = 30%

required = 39

48 >= 39

       ↓

TP4 selected

production profile에:

capacity:
  maxSloConcurrency: 48
  productionConcurrency: 30
  headroomPercent: 30

같은 정보를 넣고,

Gateway policy에서는:

model=deepseek

global concurrency ≤ 30

를 설정합니다.

그러면 benchmark 결과가 실제 admission control로 연결됩니다.


16. 그래서 필요한 소프트웨어를 정리하면

전부 custom 개발할 필요는 없습니다.

제가 현재 구조에서 검토할 stack은 대략:

Kubernetes
│
├── Cilium
│    ├─ CNI
│    ├─ NetworkPolicy
│    ├─ Hubble
│    └─ Gateway API / Envoy
│
├── Kubernetes Gateway API
│
├── Gateway API Inference Extension
│    ├─ InferencePool CRD
│    └─ EPP
│
├── NVIDIA GPU Operator
│    └─ DCGM Exporter
│
├── vLLM
│
├── Prometheus
│
├── Grafana
│
└── OpenTelemetry

입니다.

즉 Ingress NGINX + custom Python router + custom LB부터 직접 만드는 방향은 권하지 않습니다.


17. 다만 Auth/Quota는 별도 고민이 필요합니다

Gateway API Inference Extension은 GPU quota/billing platform이 아닙니다.

따라서:

API Key
OIDC
Team identity
rate limit
token quota
billing

는 별도의 API-management/auth 계층이 필요할 수 있습니다.

구조적으로:

                  External

                     │
                     ▼
           ┌───────────────────┐
           │ API Management    │
           │                   │
           │ Auth / API Key    │
           │ Team / Quota      │
           │ Rate limit        │
           └─────────┬─────────┘
                     │
                     ▼
           ┌───────────────────┐
           │ Inference Gateway │
           │ Gateway API       │
           └─────────┬─────────┘
                     │
                     ▼
              InferencePool
                     │
                    EPP
                     │
                     ▼
                   vLLM

형태도 충분히 가능합니다.

초기에는 두 계층을 Gateway 구현체에서 최대한 같이 처리하고, 요구가 복잡해지면 API management를 분리하는 방식이 좋습니다.


18. 현재 환경에서 제가 추천하는 현실적인 구현 순서

한 번에 모든 것을 넣지 않는 것이 좋습니다.

1단계 — 지금 8×B300

Cilium
  +
Gateway API
  +
Inference Extension
  +
Default EPP
  +
vLLM

Prometheus/DCGM/Hubble

여기까지 먼저 구축합니다.

Request path:

Compute
   │
HTTPS
   ▼
GPU Gateway
   │
InferencePool
   │
EPP
   │
vLLM

그리고 Stage7 결과를 이용해:

TP
max concurrency
context
KV
GPU allocation

을 정합니다.

2단계 — Multi-tenant control

그 위에:

OIDC/API key
team
model ACL
RPS quota
token quota
concurrency admission
priority

를 붙입니다.

3단계 — B300 Node #2

그때:

InferencePool

 ├─ replica Node1
 └─ replica Node2

        ↓

load-aware EPP

를 본격 사용합니다.

4단계 — 실제 데이터가 쌓인 뒤

필요성이 확인되면:

prefix-aware routing
KV locality routing
request-cost routing
dynamic autoscaling

까지 발전시키는 게 좋습니다.


최종적으로 역할을 한 줄씩 정리하면

구성요소책임
CiliumPod networking, NetworkPolicy, Hubble, Gateway dataplane
Gateway APIGateway/HTTP routing을 Kubernetes 리소스로 선언
Gateway implementation실제 L4/L7 traffic 처리
InferencePool같은 모델을 serving할 endpoint 집합 정의
EPP그 pool에서 이번 요청을 처리할 최적 endpoint 선택
API/Auth layer사용자/팀 인증, quota, rate limit, model ACL
vLLM실제 LLM inference
Stage7/v12TP/Concurrency/KV/SLO capacity를 측정하고 production config 결정
Prometheus/DCGMGPU와 inference 성능/용량 측정
Hubblenetwork flow/latency/drop 관측

따라서 현재 환경에서 “별도 Inference Router를 하나 개발해야 하나?”에 대한 답은 일단 No입니다. Gateway API + Inference Extension의 InferencePool/EPP를 먼저 사용하고, 기본 EPP로 해결되지 않는 실제 routing 문제가 Stage7/production metric에서 확인됐을 때만 custom routing policy를 추가하는 게 가장 관리하기 좋은 방향입니다.

Gateway API Inference Extension 공식 문서
Cilium Gateway API 공식 문서


필요할 가능성이 높습니다. 다만 LiteLLM과 Gateway API Inference Extension은 경쟁 관계가 아니라 담당 계층이 다릅니다. 지금처럼 여러 팀이 여러 모델을 공유하는 환경이라면 저는 LiteLLM 계열의 LLM 관리/API Gateway 계층을 추가하는 쪽을 권합니다.

제가 추천하는 구조는 이렇습니다.

Compute Cluster / Users / Applications
 Jupyter / Spark / Discovery / Wizard
                 │
                 │ HTTPS :443
                 ▼
┌─────────────────────────────────────┐
│ LiteLLM / LLM Management Gateway    │  ← 사용자/팀 관리
│                                     │
│ Auth / Virtual Key                  │
│ Team / Model ACL                    │
│ RPM / TPM / Concurrent Request      │
│ Usage / Budget / Accounting         │
│ Model Alias                         │
│ Retry / Fallback Policy             │
└──────────────────┬──────────────────┘
                   │
                   │ OpenAI API
                   ▼
┌─────────────────────────────────────┐
│ K8s Inference Gateway               │  ← GPU endpoint 관리
│ Gateway API                         │
└──────────────────┬──────────────────┘
                   │
                   ▼
             InferencePool
                   │
                   ▼
                  EPP                 ← 어느 replica?
                   │
        ┌──────────┴──────────┐
        ▼                     ▼
   vLLM Replica A        vLLM Replica B
     Node #1               Node #2

LiteLLM은 virtual key와 팀별 model access, RPM/TPM/max-parallel-request 제한, budget/spend tracking 같은 기능을 제공합니다. 특히 virtual key와 budget 같은 관리 기능은 PostgreSQL DB가 필요합니다. LiteLLM

LiteLLM과 EPP의 가장 중요한 차이

둘 다 "routing"이라는 표현을 쓰기 때문에 헷갈리기 쉽습니다.

LiteLLM은 논리적인 모델/API routing을 담당하게 하는 게 좋습니다.

사용자 요청
model = discovery

        ↓

LiteLLM

"이 팀은 discovery 사용 가능?"
"quota가 남았나?"
"어떤 logical model인가?"

        ↓

deepseek-v4.1-flash

반면 EPP는 물리적인 inference replica 선택을 담당합니다.

deepseek-v4.1-flash
        ↓
InferencePool
        ↓
EPP

Node1 replica
 queue=12
 KV=85%

Node2 replica
 queue=2
 KV=45%

        ↓
Node2 선택

InferencePool은 동일 모델 서버의 Pod들을 논리적인 pool로 묶고, EPP가 KV-cache utilization, pending queue 같은 inference 상태를 추적하여 적절한 replica를 선택하도록 설계되어 있습니다. Kubernetes 게이트웨이 API 확장

그래서 LiteLLM에서 GPU replica의 KV-cache 상태까지 보고 직접 LB하게 만들지는 않는 것을 권합니다.


그러면 Gateway가 하나 더 생기는 것 아닌가?

맞습니다.

논리적으로는 두 gateway 계층입니다.

        North-South / Management

Client
  ↓
LiteLLM
  ↓
────────────────────────────
        GPU Serving
────────────────────────────
  ↓
Inference Gateway
  ↓
InferencePool / EPP
  ↓
vLLM

하지만 역할이 확실히 다릅니다.

계층주 질문
LiteLLM누가 어떤 모델을 얼마나 사용할 수 있나?
Gateway API어느 InferencePool로 traffic을 보낼까?
InferencePool이 모델을 제공하는 endpoint는 무엇인가?
EPP그중 지금 가장 적합한 replica는 무엇인가?
vLLM실제로 inference를 어떻게 실행할까?
Stage7몇 GPU/TP/C가 필요한가?

이렇게 책임을 나누면 깔끔합니다.


특히 지금 환경에서는 LiteLLM의 가치가 큽니다

사용자가 여러 팀이라고 했기 때문입니다.

예를 들어:

                 LiteLLM

        ┌──────────┼──────────┐
        │          │          │
    Discovery    Wizard    Ontology
        │          │          │
     key/team    key/team    key/team
        │          │          │
    100k TPM     50k TPM    500k TPM
     C=20         C=8        C=4
        │          │          │
 DeepSeek/GLM   Qwen/OCR     GLM-5.3

처럼 중앙에서 관리할 수 있습니다.

LiteLLM은 현재 team/key/user 수준의 TPM/RPM, max parallel requests 및 model-specific limits를 지원합니다. LiteLLM

그리고:

Team Discovery

Allowed:
 ✓ deepseek-v4.1-flash
 ✓ glm-5.3-flash

Denied:
 ✗ glm-5.3-nightly

같은 model access control도 virtual key 계층에서 관리할 수 있습니다. LiteLLM


Model alias도 상당히 유용합니다

Application에 실제 checkpoint 이름을 박지 않는 게 좋습니다.

나쁜 구조:

Jupyter application

model =
deepseek-ai/Deepseek-V4.1-Flash

좋은 구조:

model = discovery

그리고 LiteLLM에서:

discovery
    ↓
deepseek-v4.1-flash

로 mapping합니다.

나중에 Stage7 결과에서 GLM Flash가 더 적합하면:

discovery
    ↓
glm-5.3-flash

로 변경할 수 있습니다.

Application 코드는 그대로입니다.

LiteLLM 자체도 여러 모델/provider를 하나의 OpenAI-compatible API 뒤에 두는 AI Gateway를 지향하고 있습니다. LiteLLM


fallback도 LiteLLM 계층에서 하는 것이 자연스럽습니다

예를 들어:

Discovery

Primary
DeepSeek-V4.1-Flash
       │
       │ unavailable
       ▼
Fallback
GLM-5.3-Flash

같은 정책입니다.

LiteLLM은 key/team 수준에서도 routing strategy, fallback, timeout, retry 같은 router 설정을 지원합니다. LiteLLM

다만 모델 간 fallback은 quality가 동등하다는 Stage7 검증 후에만 활성화하는 것을 권합니다.


한 가지 중요한 부분: LiteLLM quota와 GPU capacity를 연결

이건 지금 만든 v12와 굉장히 잘 맞습니다.

예를 들어 Stage7 결과가:

DeepSeek TP4

SLO max concurrency = 48
Production peak     = 30
Required headroom   = 30%

production admission
≈ 30 concurrent requests

라고 나오면 LiteLLM에:

DeepSeek total
max parallel ≈ 30

이라는 상한을 만들 수 있습니다.

그리고 그 30을 팀별로:

                 DeepSeek
                capacity 30

         ┌─────────┼─────────┐
         │         │         │
    Discovery   Jupyter    Wizard
       C=20       C=4        C=6

처럼 나눌 수 있습니다.

즉 우리가 지금까지 만든:

Stage7
 ↓
TP candidate sweep
 ↓
saturation
 ↓
SLO
 ↓
headroom
 ↓
production capacity

결과가 LiteLLM의 tenant quota/admission 설정으로 이어질 수 있습니다.

이건 다음 v13에서 자동 생성 대상으로 넣어도 꽤 좋습니다.


단, LiteLLM을 EPP 대신 쓰지는 않겠습니다

이 구조는 피하는 게 좋습니다.

LiteLLM
 ├─ vLLM Pod A
 ├─ vLLM Pod B
 ├─ vLLM Pod C
 └─ vLLM Pod D

그리고 LiteLLM이 직접 replica load balancing까지 전부 담당하는 형태입니다.

LiteLLM 자체에도 load balancing/routing 기능은 있지만, Kubernetes GPU serving을 장기적으로 운영할 거라면:

LiteLLM
    │
logical model
    ▼
InferencePool
    │
    EPP
    │
physical endpoint
    ▼
vLLM

으로 책임을 분리하는 쪽을 권합니다.

EPP는 애초에 inference endpoint의 queue/KV 상태 등을 이용한 endpoint 선택을 위해 설계된 계층입니다. Kubernetes 게이트웨이 API 확장


현재 1-node에서는 조금 단순화할 수도 있습니다

처음부터 모든 계층을 production complexity로 만들 필요는 없습니다.

현재

Compute
   │
   ▼
LiteLLM
   │
   ▼
Cilium Gateway
   │
   ▼
InferencePool
   │
   ▼
EPP
   │
   ▼
vLLM

EPP 뒤에 replica가 하나라 사실상 pass-through입니다.

하지만 이렇게 만들어 놓으면 6개월 후:

                  LiteLLM
                     │
                     ▼
             Inference Gateway
                     │
                     ▼
               InferencePool
                     │
                     EPP
                ┌────┴────┐
                ▼         ▼
             Node1       Node2
             TP4 A       TP4 B

로 자연스럽게 확장됩니다.


DB도 고려해야 합니다

LiteLLM을 단순 OpenAI proxy로만 쓰면 DB 없이도 가능하지만, 우리가 원하는 것은 그 수준이 아닙니다.

우리가 원하는 기능이:

Virtual Key
Team
Quota
Budget
Usage
Model ACL

이므로 PostgreSQL을 같이 두는 구조로 보는 것이 맞습니다. LiteLLM 공식 문서도 virtual keys와 budget 기능에 DB가 필요하다고 명시하고 있습니다. LiteLLM

그래서:

GPU Cluster

┌──────────────────────┐
│ LiteLLM replicas     │
└──────────┬───────────┘
           │
           ├──────── PostgreSQL
           │
           └──────── Redis (필요 시)

정도로 생각하면 됩니다.

PostgreSQL을 GPU node에 꼭 같이 둘 필요는 없습니다. 기존 DB infrastructure가 있다면 그쪽을 사용하는 편이 운영상 더 좋을 수 있습니다.


제가 지금 환경에 추천하는 최종 계층

                USERS / APPLICATIONS
                         │
                    HTTPS :443
                         │
                         ▼
┌────────────────────────────────────────────┐
│             LiteLLM Gateway               │
│                                            │
│ Authentication / Virtual Key              │
│ Team / Model ACL                          │
│ RPM / TPM / Concurrency                   │
│ Usage / Accounting                        │
│ Model Alias                               │
│ Model Fallback                            │
└─────────────────────┬──────────────────────┘
                      │
               logical model
                      │
                      ▼
┌────────────────────────────────────────────┐
│       Kubernetes Inference Gateway         │
│       Gateway API                          │
└─────────────────────┬──────────────────────┘
                      │
                      ▼
┌────────────────────────────────────────────┐
│              InferencePool                 │
│       DeepSeek / GLM / Qwen / ...          │
└─────────────────────┬──────────────────────┘
                      │
                     EPP
                      │
           load / queue / KV locality
                      │
             ┌────────┴────────┐
             ▼                 ▼
        vLLM Replica A    vLLM Replica B
        B300 Node #1      B300 Node #2
             │                 │
             └────────┬────────┘
                      │
               GPU / Local NVMe

그래서 제 추천은 LiteLLM을 넣습니다. 다만 LiteLLM = inference router로 설계하는 게 아니라 “AI API Management / Multi-tenant Management Plane”으로 두고, GPU replica의 실제 inference-aware endpoint 선택은 InferencePool + EPP에 맡깁니다.

이렇게 하면 우리가 만든 v12의 Stage7 capacity 결과 → LiteLLM team/model quota + production profile → Helm → InferencePool까지 하나의 운영 체계로 연결할 수 있습니다. LiteLLM

LiteLLM AI Gateway 공식 문서
Gateway API Inference Extension 공식 문서


profile
engineer

0개의 댓글