김성환 | #ML Engineer | #Infrastructure #Kubernetes #Azure
들어가며
저희는 자체 LLM Spotwrite를 활용한 AI 엔터테인먼트 서비스 제타(zeta)를 운영하고 있습니다. 제타는 한국, 일본 AI 서비스 중 사용자가 가장 많은 압도적인 1위 서비스로 유저 한 명이 매달 40시간 이상을 사용할 정도로 체류시간이 긴 서비스인데요, 현재 WAU 150만을 달성하여 채팅 모델에만 초당 3~4천 RPS에 육박하는 LLM 트래픽을 처리하고 있습니다. 자체 LLM을 활용하여 학습부터 서빙까지 Full-Stack으로 직접 해내는 팀인 만큼, 매주 수십 개의 LLM 실험이 진행되고, 이에 따라 수백 개의 모델이 동시에 서빙되는 환경입니다.
이 규모의 서비스를 운영하려면 안정적인 인프라가 필수적입니다. 이번 글에서는 저희가 LLM Inference 인프라를 지속적으로 개선해온 여정을 공유하려고 합니다. 어떤 문제들을 겪었고, 이를 어떻게 풀어왔는지 천천히 이야기해보겠습니다.
LLM 서빙 인프라의 요구사항 in Scatter Lab
먼저 저희 서빙 인프라의 핵심 특성을 간략히 소개하겠습니다.
- Fully Operated on Cloud. 모든 머신은 클라우드 위에서 On-demand, Spot, 또는 Reserved Instance로 구성되어 있습니다.
- Containerized. LLM은 각 GPU에 맞게 최적화된 서빙 엔진에 의해 배포됩니다. vLLM, SGLang, TensorRT-LLM 등 오픈소스 Inference 엔진들은 바로 Production 환경에 배포할 수 있도록 컨테이너화된 환경을 제공합니다.
- Scalable. 엔터테인먼트 서비스인 만큼 밤/낮 트래픽 격차가 크기 때문에 유저 트래픽에 맞춰 그때그때 적절한 수의 GPU를 배포할 수 있어야 합니다.
클라우드 위에서 동작하고, 컨테이너화되어 있으며, 트래픽에 따라 유연하게 스케일링해야 하는 환경. 이 세 가지 조건을 만족시키기 위해 저희는 자연스럽게 Kubernetes Native한 환경을 주 서빙 플랫폼으로 채택하게 되었습니다. 현재 Kubernetes 위에 모든 인프라가 올라가 있고, 이를 중심으로 서빙 파이프라인 전체가 구성되어 있습니다.
기존 인프라의 한계
저희는 GPU 서빙을 위해 국내외 몇몇 클라우드사와 해외 Neo Cloud를 사용했었습니다. 특히 Neo Cloud들 중에는 Kubernetes를 지원하지 않는 경우가 많았는데요, 이를 해결하기 위해 자체 개발한 Proxy 서버를 활용해 Neo Cloud를 저희 환경과 연동시켰습니다.

일주일에 12시간을 사용할 정도로 유저의 체류시간이 길고, MAU 150만이라는 규모까지 더해지면서 LLM Infra에 여러 문제가 보이기 시작했습니다.
- GPU Capacity 확보의 어려움
이전에는 A40이나 RTX 6000 같은 서빙용 GPU는 비교적 쉽게 구할 수 있었습니다. 그런데 KV Cache 관련 기술이 발전하면서 VRAM이 넉넉한 A100, H100 같은 GPU도 Inference에 활용하게 되었고, 이런 고사양 GPU의 충분한 Capacity를 Neo Cloud에서 확보하기가 어려웠습니다.
- 인프라 안정성 이슈
아무래도 Neo Cloud이다 보니 온도 이슈, GPU 에러 등 인프라 안정성이 떨어지는 문제가 있었습니다. 이를 핸들링하기 위해 GPU 온도를 실시간으로 감지해서 Pod을 죽이는 Health Check Probe까지 직접 작성했을 정도입니다.
- 스토리지 관리의 복잡성
수십에서 수백 기가바이트에 달하는 모델 Checkpoint를 불러와야 하는데, 일반 클라우드와 Neo Cloud를 혼합 활용하는 구조에서는 마땅한 공유 스토리지가 없었습니다. 설령 각 클라우드에 별도의 스토리지가 있다 하더라도, 클라우드별·리전별로 동일한 Checkpoint의 Replication을 관리하는 것은 보통 일이 아니었습니다.
- 운영 오버헤드와 Failover의 어려움
직접 모델을 학습하는 회사인 만큼 수백 개의 모델을 동시에 서빙해야 합니다. 매번 A 클라우드, B 클라우드에 리소스를 올리고, 싱크하고, 관리하는 모든 과정이 번거롭고 비용이었습니다. 심지어 특정 클라우드에 Capacity가 부족하거나 장애가 발생하면, 통합된 Control Plane이 없어 Failover와 복구가 힘들었습니다.
정리하자면
위 문제들을 정리하면 세 가지 핵심 니즈로 귀결됩니다.
A. 안정적인 GPU의 안정적인 Capacity 확보. 장애가 발생하더라도 재빠르게 복구할 수 있는 환경이 필요합니다.
B. 여러 리전에 흩어져 있어도 빠르고 넉넉한 용량의 Storage. 수백 기가의 Checkpoint를 빠르게 가져오고, 리전 간 동기화가 쉬워야 합니다.
C. 하나의 Control Plane. 전체 인프라를 모니터링하여 안정적이고 비용 효율적으로 스케줄링 및 스케일링을 할 수 있어야 합니다.
이런 상황에서 저희는 안정적인 인프라를 찾아 여러 선택지를 검토했고, Major Cloud중 하나인 Azure 안에서 위 문제들을 차근차근 안정화해나가기 시작했습니다. 그 과정을 하나씩 풀어보겠습니다.
LLM Inference Infra의 문제를 해결한 방법
Multi-Region Cluster: GPU Capacity 확보 전략
LLM Inference에 필요한 GPU, 특히 H100급 고사양 GPU는 수요가 매우 높아서 단일 Region에서 충분한 Capacity를 확보하기가 쉽지 않습니다. 저희처럼 트래픽에 따라 수백 대의 GPU를 탄력적으로 Scaling해야 하는 환경에서는 더더욱 그렇습니다. 하나의 Region에 Capacity가 부족하면 서비스 Scaling이 막히고, 장애 시 Failover할 여유도 없어지죠.
결국 안정적인 GPU Capacity를 확보하기 위해, 저희는 8개가 넘는 Region에 각각 AKS Cluster를 띄워 운영하는 전략을 취하게 되었습니다. Region을 분산함으로써 특정 Region의 Capacity 부족이나 장애가 전체 서비스에 미치는 영향을 최소화할 수 있었습니다.
하지만 Multi-Region, Multi-Cluster 운영은 그 자체로 새로운 문제들을 가져왔습니다.

문제 1. 클러스터 추가마다 반복되는 인프라 구성 - Azure Terraform Provider
새로운 Region에 클러스터를 추가할 때마다 Resource Group, Blob Storage, Container Registry, Networking, RBAC 등 수많은 인프라를 매번 수동으로 구성해야 합니다. 8개가 넘는 Region을 운영하다 보면 이 반복 작업 자체가 상당한 운영 부담이 되고, 사람이 하는 일인 만큼 실수의 여지도 커집니다. 특히 GPU Capacity가 부족한 상황에서 새로운 Region을 긴급하게 추가해야 할 때, 이 셋업 시간이 서비스 안정성에 직접적인 영향을 주기도 했습니다.

이를 해결하기 위해 Azure에서 잘 제공하고 있는 Terraform Provider를 활용하여 Terraform 기반 IaC(Infrastructure as Code)를 적극 도입했습니다. AKS Cluster, Resource Group, Networking, Storage 등 Region 하나를 띄우는 데 필요한 모든 인프라를 Terraform 모듈로 템플릿화하여, 새로운 Region에 클러스터를 배포하는 것이 이제 변수 몇 개만 바꾸고
terraform apply 한 번이면 끝나는 수준이 되었습니다. 덕분에 Capacity 확보가 급한 상황에서도 빠르게 새로운 Region을 올릴 수 있게 되었습니다.문제 2. Multi-Cluster Service Discovery와 부하분산 - Istio Multicuster
메인 백엔드 입장에서 8개 이상의 클러스터에 흩어져 있는 LLM 서비스들에 대한 Service Discovery가 가능해야 하고, 각 서비스의 Pod들로 적절하게 부하분산을 할 수 있어야 합니다. 단순히 각 클러스터의 Endpoint를 하드코딩하는 방식은 클러스터가 늘어날수록 관리가 불가능해지고, Pod이 Scaling되거나 장애로 사라질 때 실시간 반영이 되지 않아 요청 실패로 이어지기도 합니다.

이를 위해 Service Mesh 오픈소스인 Istio를 적극 활용하고 있습니다. Istio의 Multi-cluster 기능을 통해 N개의 Cluster를 동일 Mesh에 엮으면, 서로 다른 클러스터에 떠 있는 서비스라도 마치 하나의 클러스터 안에 있는 것처럼 접근할 수 있습니다. 단순히 접근 뿐만이 아니라, 각각의 서버에 동일한 이름으로 띄운 서비스들은 하나의 서비스처럼 동작하여 각 클러스터에 위치한 Pod에 균일하게 부하분산이 가능합니다. 저희는 여러 클러스터가 각자의 Control Plane을 가지면서도 하나의 Mesh로 동작하는 Multi-primary 모델을 채택했는데, 이 구조 덕분에 특정 클러스터에 장애가 발생하더라도 나머지 클러스터의 Control Plane이 독립적으로 동작하여 Mesh 전체가 영향받지 않습니다.
문제 3. 멀티 리전 k8s 클러스터를 운영할 단일 Control Plane
수많은 k8s 클러스터를 동시에 운영하면서, 원하는 Workload를 적재적소에 배치하는 것은 정말 까다로운 일입니다. 전체 트래픽과 각 클러스터의 Capacity 상황을 종합적으로 보고 적절한 위치에 Pod을 Replicate해야 하는데, 클러스터마다
kubectl 컨텍스트를 전환하며 수동으로 관리하는 것은 사실상 불가능합니다. 특히 저희처럼 수백 개의 모델을 동시에 서빙하는 환경에서는, "어떤 모델을 어떤 클러스터에 몇 개의 Replica로 배포할 것인가"를 중앙에서 관리할 수 있는 Control Plane이 반드시 필요했습니다.
이 문제를 해결하기 위해 Karmada라는 Multi-cluster 솔루션을 도입했습니다. Karmada(Kubernetes Armada)는 CNCF Incubation 프로젝트로, 여러 Kubernetes 클러스터와 클라우드에 걸쳐 애플리케이션을 변경 없이 실행할 수 있게 해주는 관리 시스템입니다. (GitHub)

Karmada는 그 자체로 독립된 Kubernetes API Server처럼 동작합니다. 사용자가 Karmada에 Resource를 배포하면, 사전에 설정한 PropagationPolicy에 따라 지정된 멤버 클러스터로 자동 배포됩니다. 예를 들어, "이 모델은 eastus와 westus에 각각 3개씩 배포하되, koreacentral에는 2개만 배포하라"와 같은 정책을 선언적으로 정의할 수 있습니다. Karmada는 이 명세에 따라 ResourceBinding을 생성하고, 원격지 클러스터가 적절한 Resource를 생성하게 됩니다.
# PropagationPolicy 예시
apiVersion: policy.karmada.io/v1alpha1
kind: PropagationPolicy
metadata:
name: nginx-propagation
spec:
#...
**resourceSelectors:
- apiVersion: apps/v1
kind: Deployment
name: nginx
placement:
replicaScheduling:
replicaDivisionPreference: Weighted
replicaSchedulingType: Divided
weightPreference:
staticWeightList:
**- targetCluster:
clusterNames:
- eastus
- westus
weight: 3
- targetCluster:
clusterNames:
- koreacentral
weight: 1특히 Karmada에는 자체 Metric Server가 존재하여, 각각의 멤버 클러스터로부터 Metric을 수집한 뒤 하나의 HPA(Horizontal Pod Autoscaler)를 통해 N개의 클러스터에 대해 각 환경에 맞게 Autoscaling을 수행합니다. 이를 Karmada에서는 FederatedHPA라 부르는데, 트래픽이 몰리는 시간대에는 Capacity가 여유로운 Region에 자동으로 Replica를 늘리고, 트래픽이 줄면 다시 축소하는 것이 하나의 HPA 정의로 가능해진 것입니다. Karmada를 통해 저희는 하나의 Kubernetes Control Plane으로 사내 클러스터를 포함해 수십 개의 클러스터에 원하는 Workload를 배포하고 모니터링할 수 있게 되었습니다.

Multi cluster 환경에서의 스토리지: Blob Storage & Container Registry 활용
멀티클러스터 환경에서 컴퓨팅 자원을 관리하는 것도 중요하지만, 앞서 언급한 문제대로 각 클러스터에서 빠르게 접근할 수 있는 스토리지 역시 중요합니다. Azure에서는 안정적인 성능의 Blob Storage와 Azure Container Registry(ACR)를 사용할 수 있습니다.
Blob Storage의 경우, Azure에서 함께 제공하는 azcopy 도구를 통해 동일 Region이라면 굉장히 빠른 속도로 로컬에 Checkpoint를 받아올 수 있습니다. 10B, 30B 등 상대적으로 작은 사이즈의 LLM의 경우, 모델 Checkpoint를 Blob Storage에만 올려두더라도 바로바로 Scale할 수 있을 정도로 빠른 활용이 가능했습니다.
Container Registry에는 특이한 점이 하나 있는데, Geo-replication 기능입니다. 하나의 Registry만 관리하더라도 여러 Region에서 빠른 속도로 이미지를 pull할 수 있었습니다. 8개 이상의 클러스터를 운영하는 저희 입장에서, 단일 Container Registry를 관리하면서도 빠른 이미지 배포가 가능하다는 점은 큰 운영 편의성을 가져왔습니다.
Wrap up & Future work
여기까지 저희가 겪었던 문제들과 이를 해결해온 과정을 간단히 되짚어보겠습니다.

A. 안정적인 GPU의 안정적인 Capacity 확보 → Azure의 다양한 GPU 제품군(NC Series 등)과 빠른 Support를 통해 안정적으로 확보할 수 있었습니다. 장애 시에도 Azure 팀의 신속한 대응이 가능했습니다.
B. 여러 리전에 흩어져 있어도 빠르고 넉넉한 용량의 Storage → azcopy를 통해 Blob Storage로부터 빠르게 데이터를 가져올 수 있고, ACR의 Geo-replication 기능을 통해 단일 레지스트리로 여러 리전에서 빠르게 이미지를 pull할 수 있었습니다.
C. 하나의 Control Plane → AKS와 Karmada를 이용하여 하나의 Control Plane만으로 여러 클러스터에 원하는 워크로드를 배포하고, Istio Multi-cluster를 통해 하나의 Mesh로 묶어 서비스를 운영할 수 있었습니다.
이를 통해 저희의 전체 서빙 비용은 20% 이상 절약될 수 있었고, 운영 리소스 역시 절반 이상 절약할 수 있었습니다.
지금까지의 여정으로 안정적인 Multi-Region 서빙 인프라를 갖추게 되었지만, LLM Inference 분야는 워낙 빠르게 발전하고 있어서 저희가 주목하고 있는 Azure 내 기능들이 몇 가지 더 있습니다. 아직 프로덕션에 도입하지는 않았지만, 검토하고 있는 방향들을 간략히 소개합니다.
Azure Fleet Manager로의 마이그레이션
현재 Multi-cluster 관리를 위해 Karmada를 사용하고 있지만, Azure에서 자체적으로 제공하는 Azure Kubernetes Fleet Manager로의 마이그레이션을 검토하고 있습니다. Fleet Manager는 여러 AKS 클러스터를 대규모로 관리할 수 있는 솔루션으로, 안전한 Multi-cluster 업데이트, Kubernetes 리소스 배치, 그리고 DNS 기반 로드밸런싱 등을 지원합니다. Azure 네이티브 솔루션인 만큼, AKS와의 통합이 더욱 매끄러울 것으로 기대하고 있습니다.
Azure Managed Lustre를 활용 KV Cache Sharing
LLM Inference에서 최근 주목받는 최적화 기법 중 하나가 KV Cache Sharing입니다. 여러 서빙 인스턴스가 동일한 KV Cache를 공유 스토리지에 저장하고 재활용하면, 중복 연산을 줄여 Throughput은 올리고 Latency는 낮출 수 있습니다. 이를 위해서는 수백 대의 GPU 인스턴스가 동시에 접근할 수 있는 고성능 공유 파일시스템이 필요한데, 일반적인 Blob Storage로는 IOPS와 Latency 한계가 있습니다.
여기서 주목하고 있는 것이 Azure Managed Lustre입니다. Lustre는 세계 최고 성능의 슈퍼컴퓨터들이 사용하는 오픈소스 병렬 파일시스템으로, 수백 GBps의 처리량과 SSD급 저지연을 제공합니다. Azure Managed Lustre는 이 Lustre를 Managed PaaS로 제공하는 서비스로, 복잡한 파일시스템 인프라를 직접 구축하고 관리할 필요 없이 Azure Portal에서 몇 분 만에 배포할 수 있습니다. Azure Blob Storage와의 연동도 지원하여 데이터 티어링이 가능하고, AKS와도 CSI 드라이버를 통해 바로 연결할 수 있습니다.
수백 대의 서빙 인스턴스가 하나의 Managed Lustre 파일시스템을 KV Cache Storage로 공유하면, 인스턴스 간 Cache 재활용률을 크게 높여 서빙 비용을 줄일 수 있을 것으로 기대하고 있습니다.
KAITO & Azure ML 활용

Azure에서는 자체적으로 다양한 AI 배포 도구들이 나오고 있습니다. KAITO(Kubernetes AI Toolchain Operator)는 CNCF Sandbox 프로젝트로, Kubernetes 클러스터에서 AI/ML 모델의 추론과 튜닝 워크로드를 자동화하는 오퍼레이터입니다. GPU 노드 자동 프로비저닝, OpenAI 호환 API, vLLM 통합 등을 지원하며, AKS에서는 AI Toolchain Operator add-on으로 손쉽게 활성화할 수 있습니다. 오픈소스 모델들이 점점 좋아지는 만큼, KAITO와 Azure ML을 활용한 배포 역시 적극적으로 고려하고 있습니다.
마치며
zeta의 LLM Inference 인프라는 Neo Cloud 시절의 여러 한계를 겪으면서 지금의 형태로 진화해왔습니다. Azure의 안정적인 GPU Capacity, AKS의 Managed Kubernetes 환경, Blob Storage와 ACR의 편의성, 그리고 Karmada와 Istio 같은 오픈소스 솔루션들을 결합하여 8개 이상의 리전에 걸친 Multi-cluster 인프라를 운영하고 있습니다.
LLM 생태계는 하루가 다르게 발전하고 있고, 그에 맞춰 인프라에 요구되는 것들도 계속 달라지고 있습니다. 저희도 이 흐름 속에서 비용 효율적이고 안정적인 서빙 인프라를 유지하기 위해 꾸준히 고민하고 개선해나갈 예정입니다.
참고 자료
Kubernetes & Multi-Cluster
- Azure Kubernetes Service (AKS): https://learn.microsoft.com/en-us/azure/aks/
- Karmada: https://karmada.io/ | GitHub
- Karmada PropagationPolicy: https://karmada.io/docs/userguide/scheduling/resource-propagating/
- Istio: https://istio.io/
- Istio Multi-cluster : https://istio.io/latest/docs/setup/install/multicluster/
- Terraform Azure Provider: https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs
Azure Storage & Registry
- Azure Blob Storage: https://learn.microsoft.com/en-us/azure/storage/blobs/
- Azure Container Registry: https://learn.microsoft.com/en-us/azure/container-registry/
- ACR Geo-replication: https://learn.microsoft.com/en-us/azure/container-registry/container-registry-geo-replication
Other Azure Resources
- Azure Kubernetes Fleet Manager: https://learn.microsoft.com/en-us/azure/kubernetes-fleet/overview
- Azure Managed Lustre: https://learn.microsoft.com/en-us/azure/azure-managed-lustre/
- AKS AI Toolchain Operator: https://learn.microsoft.com/en-us/azure/aks/ai-toolchain-operator
Share article