Triton + TensorRT-LLM 자동 스케일링과 로드 밸런싱

Triton + TensorRT-LLM 자동 스케일링과 로드 밸런싱 (Autoscaling & Load Balancing)

트리톤 인퍼런스 서버가 서빙하는 대형 언어 모델(LLM)에 자동 확장(autoscaling)과 로드 밸런싱을 붙이는 건 사실 어렵지 않지만, 준비는 필요해요. 이 가이드는 Hugging Face에서 모델을 받아 TensorRT용으로 최적화하고, 쿠버네티스에서 자동 스케일링과 로드 밸런싱을 설정하는 전체 과정을 다룹니다. 참고로 쿠버네티스의 기초, 클러스터에서 외부 클라이언트로의 보안 ingress/egress, 클라우드 제공자의 쿠버네티스 인터페이스 구현은 이 가이드의 범위 밖이에요.

제대로 구성하면 자동 확장은 LLM 기반 서비스가 현재 부하에 맞춰 리소스를 자동으로 늘리고 줄입니다. 클라이언트 수가 늘어나면 특정 트리톤 서버 배포의 추론 부하가 커지고, 결국 큐 대비 연산 비율(queue-to-compute ratio)이 커져 가로 팟 자동 확장기(Horizontal Pod Autoscaler, HPA)가 트리톤 서버 인스턴스 수를 늘립니다. 반대로 클라이언트가 줄면 배포된 트리톤 서버 인스턴스도 줄어들게 되죠.

다루는 주제는 다음과 같습니다.

  • 클러스터 설정 (핵심 클러스터 서비스, 메트릭 수집 서비스, NFS 생성)
  • 트리톤 준비 (파드 초기화 스크립트, 모델 준비, 커스텀 컨테이너 이미지, 쿠버네티스 Pull Secret)
  • 트리톤 배포 (단일 GPU 모델, 단일 GPU로는 너무 큰 모델, 여러 GPU SKU 활용, 쿠버네티스에서 모니터링)
  • 이 가이드 작성 과정

시작 전에 준비할 것들: 쿠버네티스 제어 CLI(kubectl), Helm CLI(helm), Docker CLI(docker), YAML 편집용 텍스트 에디터, 쿠버네티스 클러스터, 그리고 클러스터에 대한 관리자 권한이 있는 kubectl 설정입니다.

출처: 공식문서 - Autoscaling and Load Balancing

클러스터 설정

이 절은 쿠버네티스 클러스터에서 트리톤 인퍼런스 서버를 위한 가로 팟 자동 확장(HPA)을 설정하는 방법을 차례로 안내해요.

사전 요구사항

이 가이드는 NVIDIA GPU가 있는 모든 노드에 다음이 적용돼 있다고 가정합니다.

  • NVIDIA GPU 노드를 쉽게 식별할 수 있게 nvidia.com/gpu=present 노드 라벨
  • GPU가 아닌 파드가 GPU 노드에 배포되지 않도록 nvidia.com/gpu=present:NoSchedule 노드 테인트(taint)

[!참고] AKS, EKS, GKE 같은 쿠버네티스 제공자를 쓸 때는 kubectl로 직접 구성하기보다 해당 제공자의 인터페이스를 쓰는 게 보통 좋아요.

핵심 클러스터 서비스

노드 라벨링과 테인트가 끝나면, 트리톤 서버의 자동 가로 확장을 켜는 데 필요한 메트릭을 수집·제공하도록 클러스터를 준비해요. 아래 단계들은 새 클러스터를 전제로 합니다.

Kubernetes Node Feature Discovery 서비스

차트 저장소를 로컬 캐시에 추가하고:

helm repo add kube-nfd https://kubernetes-sigs.github.io/node-feature-discovery/charts \
&& helm repo update

서비스를 설치합니다.

helm install -n kube-system node-feature-discovery kube-nfd/node-feature-discovery \
--set nameOverride=node-feature-discovery \
--set worker.tolerations[0].key=nvidia.com/gpu \
--set worker.tolerations[0].operator=Exists \
--set worker.tolerations[0].effect=NoSchedule

[!참고] 위 명령이 설정하는 toleration 덕분에 일치하는 테인트가 있는 노드에도 파드를 배포할 수 있어요. 이 문서의 사전 요구사항에 적힌 테인트를 참고하세요.

NVIDIA Device Plugin for Kubernetes

이미 클러스터에 디바이스 플러그인이 설치되어 있으면 이 단계는 건너뛰어요. AKS·EKS·GKE 같은 턴키 쿠버네티스 클러스터는 GPU 노드가 추가되면 보통 자동으로 설치합니다.

클러스터에 필요한지 확인하려면 다음을 실행해 nvidia-device-plugin-daemonset을 찾아보세요.

kubectl get daemonsets --all-namespaces

예시 출력:

NAME                                          DESIRED  CURRENT  READY  UP-TO-DATE  AVAILABLE
kube-proxy                                    6        6        6      6           6
kube-system   node-feature-discovery-worker   1        1        1      1           1
nvidia-device-plugin-daemonset                6        6        6      6           6

없으면 아래 명령으로 설치합니다. 설치되면 컨테이너가 클러스터의 GPU에 접근할 수 있어요.

kubectl create -f https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v0.15.0/deployments/static/nvidia-device-plugin.yml

NVIDIA GPU Feature Discovery 서비스

이미 설치돼 있으면 건너뜁니다. kubectl get daemonsets --all-namespacesgpu-feature-discovery를 찾아보고, 없으면 아래 명령으로 서비스를 설치해요.

curl https://raw.githubusercontent.com/NVIDIA/gpu-feature-discovery/v0.8.2/deployments/static/gpu-feature-discovery-daemonset.yaml \
>  nvidia_gpu-feature-discovery_daemonset.yaml

그다음:

kubectl apply -f ./nvidia_gpu-feature-discovery_daemonset.yaml

메트릭 수집 서비스

이제 클러스터가 GPU 리소스를 컨테이너에 할당할 수 있습니다. 다음은 DCGM과 트리톤 서버용 메트릭 수집을 설정하는 단계예요. 메트릭 서비스는 쿠버네티스 가로 팟 자동 확장기에 이용률·가용성 데이터를 제공하고, 그 데이터는 자동 확장 결정에 쓰입니다.

모니터링 네임스페이스 만들기

모든 메트릭·모니터링 서비스용 monitoring 네임스페이스를 만듭니다.

kubectl create namespace monitoring

Prometheus 서비스

클러스터와 배포된 서비스에서 수집한 메트릭을 모으고 저장·집계·제공할 서비스가 필요해요. 가장 쉬운 방법 중 하나는 Prometheus Metrics Server를 활용하는 겁니다. 아래 단계로 kube-prometheus-stack Helm 차트를 설치해 Prometheus를 씁니다.

helm repo add prometheus-community https://prometheus-community.github.io/helm-charts \
&& helm repo update

helm install -n monitoring prometheus prometheus-community/kube-prometheus-stack \
--set tolerations[0].key=nvidia.com/gpu \
--set tolerations[0].operator=Exists \
--set tolerations[0].effect=NoSchedule

NVIDIA DCGM Exporter

클러스터의 GPU 관리를 위한 최선의 방법은 NVIDIA DCGM이지만, 여기선 스택 전체가 아니라 DCGM Exporter만 설치해 GPU 메트릭 수집만 켭니다.

helm repo add nvidia-dcgm https://nvidia.github.io/dcgm-exporter/helm-charts \
&& helm repo update

helm install -n monitoring dcgm-exporter nvidia-dcgm/dcgm-exporter --values nvidia_dcgm-exporter_values.yaml

DCGM·트리톤 메트릭을 Prometheus에 연결

Prometheus가 수집한 메트릭을 쿠버네티스 HPA가 읽을 수 있게 내보내는 메커니즘이 필요해요. 아래 단계는 Prometheus에서 메트릭을 읽도록 커스텀 메트릭 서비스 API를 만드는 Prometheus Adapter를 설치합니다.

helm install -n monitoring prometheus-adapter prometheus-community/prometheus-adapter \
--set metricsRelistInterval=6s \
--set customLabels.monitoring=prometheus-adapter \
--set customLabels.release=prometheus \
--set prometheus.url=http://prometheus-kube-prometheus-prometheus \
--set additionalLabels.release=prometheus

설치가 끝난 뒤 최소 60초 기다렸다가 확인해요. 어댑터가 설치되고 커스텀 메트릭이 제공되기까지는 눈에 띄는 지연이 있으니 참고하세요.

kubectl get --raw /apis/custom.metrics.k8s.io/v1beta1

명령이 실패하면 더 기다렸다 재시도해요. 몇 분이 지나도 실패하면 어댑터가 잘못 구성된 것이니 점검이 필요합니다.

트리톤 메트릭 Prometheus Rule

Prometheus rule은 수집 중인 데이터에 작용하는 공식으로 새 메트릭 데이터를 생성하는 메커니즘입니다. 자동 확장에 유용한 트리톤 서버 전용 rule 세트를 만들 거예요.

triton-metrics_prometheus-rule.yaml 파일을 만들고 다음으로 적용합니다(기본 네임스페이스에 생성됨, 다른 곳을 원하면 -n 추가).

kubectl apply -f ./triton-metrics_prometheus-rule.yaml

예제 Helm 차트의 모든 values 파일에서 HPA는 위 rules가 제공하는 triton:queue_compute:ratio 메트릭을 쓰도록 설정되어 있어요. 이 메트릭을 쓰는 이점은 하드웨어·모델과 무관하다는 점입니다. 추론 큐에서 보낸 시간 대비 큐를 나간 뒤 완료까지 걸린 시간의 비율을 재기 때문이에요. 절대 응답 시간이 더 중요하다면 triton:request_duration:averagetriton:compute_duration:average 메트릭이 더 맞을 수 있어요.

NFS 생성

Hugging Face에서 모델을 내려받고 TRT-LLM 모델을 만들려면 파드들이 접근할 수 있는 NFS가 필요해요. 특정 NFS를 강제하진 않으며, 이 예시에서는 Amazon EFS(Elastic File System)를 씁니다.

여러 노드에 배포된 여러 파드가 같은 모델의 샤드를 로딩해, 단일 GPU로는 너무 큰 추론 요청을 협력해서 처리하려면 공통·공유 저장 위치가 필요해요. 쿠버네티스에서 이런 공유 저장소를 영구 볼륨(persistent volume)이라 부릅니다. 영구 볼륨은 원하는 만큼 많은 파드에 볼륨 매핑될 수 있고, 파드 안 프로세스는 마치 자기 파일시스템의 일부인 것처럼 접근합니다. 여기선 EFS를 영구 볼륨으로 써요. 그리고 영구 볼륨을 파드에 할당할 영구 볼륨 클레임(PVC)도 만듭니다.

  1. IAM 역할 생성 — EFS 파일시스템용 IAM 역할 생성(추후 EFS CSI 드라이버 설치에 사용): https://docs.aws.amazon.com/eks/latest/userguide/efs-csi.html#efs-create-iam-resources
  2. EFS CSI 드라이버 설치 — AWS 콘솔의 Amazon EKS 애드온으로 설치: https://docs.aws.amazon.com/eks/latest/userguide/efs-csi.html#efs-install-driver. EKS 콘솔 Add-ons에서 Status가 Active 인지 확인.
  3. EFS 파일시스템 생성https://github.com/kubernetes-sigs/aws-efs-csi-driver/blob/master/docs/efs-create-filesystem.md 단계를 따르되, 마지막 단계의 서브넷 마운트를 올바르게 해야 노드가 EFS에 접근할 수 있어요.
  4. NFS 테스트https://github.com/kubernetes-sigs/aws-efs-csi-driver/tree/master/examples/kubernetes/multiple_pods 로 파일시스템이 노드와 잘 동작하는지 확인.
  5. EFS용 PVC 생성 — 예시는 pvc_aws 폴더에 pv_aws.yaml, claim_aws.yaml, storageclass_aws.yaml이 있어요. pv_aws.yamlvolumeHandle 값을 자신의 EFS 파일시스템 ID로 바꿔야 합니다.

pv.yaml:

apiVersion: v1
kind: PersistentVolume
metadata:
name: efs-pv
spec:
capacity:
storage: 200Gi
volumeMode: Filesystem
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain
storageClassName: efs-sc
csi:
driver: efs.csi.aws.com
volumeHandle: fs-0cf1f987d6f5af59c # Change to your own ID

claim.yaml:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: efs-claim
spec:
accessModes:
- ReadWriteMany
storageClassName: efs-sc
resources:
requests:
storage: 200Gi

storageclass.yaml:

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: efs-sc
provisioner: efs.csi.aws.com

배포:

kubectl apply -f pvc/

  1. chart/templates/deployment.yaml의 claimName 편집:
persistentVolumeClaim:
claimName: nfs-claim-autoscaling-2 (Edit your claimName)

트리톤 준비

파드 초기화 스크립트

server.py 파일을 만들어 그 안에 파드 초기화·서빙 로직을 넣습니다. 이 방식은 클러스터의 모든 노드가 공유하는 네트워크 저장 위치에 모델/GPU별 plan과 engine 파일을 캐시하면 더 개선될 수 있어요. 같은 GPU를 쓰는 새 노드에서 다음 파드가 시작될 때 로컬에서 생성하는 대신 미리 생성된 파일을 내려받을 수 있게 되니까요.

모델 준비 단계

컴퓨트 노드 안에서 TRT-LLM 엔진을 빌드하고 트리톤 모델 레포지토리를 세팅하려면:

  • setup_ssh_nfs.yaml 수정 — "sleep infinity"를 수행해 컴퓨트 노드 안에 EFS와 함께 ssh 접근을 세팅한다. 값 조정: image(기본 24.08, TRT-LLM v0.12.0 지원), nvidia.com/gpu(노드당 GPU 수, limits·requests 모두), claimName(EFS PVC 이름).
  • 컴퓨트 노드에 ssh로 접속해 TRT-LLM 엔진 빌드
cd multinode_helm_chart/
kubectl apply -f setup_ssh_nfs.yaml
kubectl exec -it setup-ssh-nfs -- bash

cd <EFS_mount_path>
git clone https://github.com/triton-inference-server/tensorrtllm_backend.git -b v0.12.0
cd tensorrtllm_backend
git lfs install
git submodule update --init --recursive

Llama3-8B 엔진을 Tensor Parallelism=1, Pipeline Parallelism=1로 빌드:

cd tensorrtllm_backend/tensorrt_llm/examples/llama

pip install -U "huggingface_hub[cli]"
huggingface-cli login
huggingface-cli download meta-llama/Meta-Llama-3-8B --local-dir ./Meta-Llama-3-8B --local-dir-use-symlinks False

python3 convert_checkpoint.py --model_dir ./Meta-Llama-3-8B \
--output_dir ./converted_checkpoint \
--dtype bfloat16 \
--tp_size 1 \
--pp_size 1 \
--load_by_shard \
--workers 1

trtllm-build --checkpoint_dir ./converted_checkpoint \
--output_dir ./output_engines \
--max_num_tokens 4096 \
--max_input_len 65536 \
--max_seq_len 131072 \
--max_batch_size 8 \
--use_paged_context_fmha enable \
--workers 1

  • 트리톤 모델 레포지토리 준비
cd <EFS_MOUNT_PATH>/tensorrtllm_backend
mkdir triton_model_repo

cp -r all_models/inflight_batcher_llm/ensemble triton_model_repo/
cp -r all_models/inflight_batcher_llm/preprocessing triton_model_repo/
cp -r all_models/inflight_batcher_llm/postprocessing triton_model_repo/
cp -r all_models/inflight_batcher_llm/tensorrt_llm triton_model_repo/

python3 tools/fill_template.py -i triton_model_repo/preprocessing/config.pbtxt tokenizer_dir:<PATH_TO_TOKENIZER>,tokenizer_type:llama,triton_max_batch_size:8,preprocessing_instance_count:1
python3 tools/fill_template.py -i triton_model_repo/tensorrt_llm/config.pbtxt triton_backend:tensorrtllm,triton_max_batch_size:8,decoupled_mode:True,max_beam_width:1,engine_dir:<PATH_TO_ENGINES>,enable_kv_cache_reuse:False,batching_strategy:inflight_batching,max_queue_delay_microseconds:0
python3 tools/fill_template.py -i triton_model_repo/postprocessing/config.pbtxt tokenizer_dir:<PATH_TO_TOKENIZER>,tokenizer_type:llama,triton_max_batch_size:8,postprocessing_instance_count:1
python3 tools/fill_template.py -i triton_model_repo/ensemble/config.pbtxt triton_max_batch_size:8

[!참고] <PATH_TO_TOKENIZER><PATH_TO_ENGINES>를 올바른 값으로 바꿔야 해요. tokenizer·TRT-LLM 엔진·트리톤 모델 레포지토리는 노드 간 공유 저장소에 있어야 모델을 트리톤에서 띄울 수 있습니다. AWS EFS라면 해당 값들은 실제 EFS 마운트 경로 기준이어야 하고, 노드들이 그 파일에 접근 가능해야 해요.

  • 파드 삭제
exit
kubectl delete -f setup_ssh_nfs.yaml

커스텀 컨테이너 이미지

triton_trt-llm.containerfile로 커스텀 이미지를 만듭니다. 예시에서는 베이스 이미지 24.08-trtllm-python-py3의 날짜 부분을 맞춰 태그 24.08을 씁니다.

docker build \
--file ./triton_trt-llm.containerfile \
--rm \
--tag triton_trt-llm:24.08 \
.

  • 이미지를 클러스터가 볼 수 있는 저장소에 올리기 — 클러스터 노드가 이미지를 내려받을 수 있는 저장소에 push해야 해요. 예시에서는 데모용 가상 저장소 nvcr.io/example을 씁니다.
docker tag \
triton_trt-llm:24.08 \
nvcr.io/example/triton_trt-llm:24.08

docker push nvcr.io/example/triton_trt-llm:24.08

쿠버네티스 Pull Secrets

이미지 저장소가 인증을 요구하면 docker-registry 시크릿을 만듭니다. 비밀번호나 사용자명의 $ 같은 특수 문자는 이스케이프해야 해요.

kubectl create secret docker-registry ngc-container-pull \
--docker-password='dGhpcyBpcyBub3QgYSByZWFsIHNlY3JldC4gaXQgaXMgb25seSBmb3IgZGVtb25zdHJhdGlvbiBwdXJwb3Nlcy4=' \
--docker-server='nvcr.io' \
--docker-username='\$oauthtoken'

확인:

kubectl get secrets
kubectl get secret/ngc-container-pull -o yaml

출력의 .dockerconfigjson은 base64 인코딩된 문자열로, 아래처럼 디코딩됩니다.

{
"auths": {
"nvcr.io": {
"username":"$oauthtoken",
"password":"VGhpcyBpcyBub3QgYSByZWFsIHNlY3JldCwgaXQgaXMgb25seSBmb3IgZGVtb25zdHJhdGlvbiBwdXJwb3Nlcy4gUGxlYXNlIG5ldmVyIHVzZSBCYXNlNjQgdG8gaGlkZSByZWFsIHNlY3JldHMh",
"auth":"JG9hdXRodG9rZW46VkdocGN5QnBjeUJ1YjNRZ1lTQnlaV0ZzSUhObFkzSmxkQ3dnYVhRZ2FYTWdiMjVzZVNCbWIzSWdaR1Z0YjI1emRISmhkR2x2YmlCd2RYSndiM05sY3k0Z1VHeGxZWE5sSUc1bGRtVnlJSFZ6WlNCQ1lYTmxOalFnZEc4Z2FHbGtaU0J5WldGc0lITmxZM0psZEhNaA=="
}
}
}

한 줄로 같은 출력을 얻는 명령:

kubectl get secret/ngc-container-pull -o json | jq -r '.data[".dockerconfigjson"]' | base64 -d | jq

트리톤 배포

단일 GPU 모델 배포

단일 GPU에 들어가는 모델은 아래 단계로 간단히 배포합니다.

  • 필요한 값이 든 커스텀 values 파일 생성: 컨테이너 이미지 이름, 모델 이름, 지원/가용 GPU, 필요 시 이미지 pull 시크릿.
  • 커스텀 values 파일로 기본 values 파일을 덮어쓰고 트리톤 서버 배포를 생성.

[!팁] 커맨드라인에서 values 파일을 지정하는 순서는 중요해요. 나중에 지정한 값이 먼저 지정한 값을 덮어씁니다.

helm install <installation_name> \
--values ./chart/values.yaml \
--values ./chart/<custom_values>.yaml \
--set 'triton.image.name=<custom_image_name>' \
./chart/.

  • 차트 설치 확인
kubectl get deployments,pods,hpa,services,podmonitors --selector='app=<installation_name>'

예시 출력(설치 이름이 "llama-3"일 때):

NAME                      READY   UP-TO-DATE   AVAILABLE
deployment.apps/llama-3   0/1     1            0

NAME                          READY   STATUS    RESTARTS
pod/llama-3-7989ffd8d-ck62t   0/1     Pending   0

NAME                                          REFERENCE            TARGETS   MINPODS   MAXPODS   REPLICAS
horizontalpodautoscaler.autoscaling/llama-3   Deployment/llama-3   0/1       1         8         1

NAME              TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)
service/llama-3   ClusterIP   10.100.23.237   <none>        8000/TCP,8001/TCP,8002/TCP

NAME
podmonitor.monitoring.coreos.com/llama-3

HPA TARGETS가 <unknown>/1로 나올 수 있는데, 보통은 문제가 아니에요. 클라이언트가 추론 쿼리를 보내지 않아 메트릭이 생성되지 않았기 때문입니다. 클라이언트가 요청을 보내기 시작하면 해결돼요.

  • 차트 제거
helm uninstall <installation_name>

단일 GPU로는 너무 큰 모델 배포

일부 AI 모델의 메모리 요구량은 단일 기기로 감당할 수 없어요. 트리톤과 TensorRT-LLM은 여러 GPU가 협력해 큰 모델을 호스팅하는 메커니즘을 제공합니다. 이 기능을 켜려면 model.tensorrtLlm.parallelism.tensor 값을 1보다 큰 정수로 조정해요. 텐서 병렬 처리(tensor parallelism)를 쓰면 여러 GPU의 메모리를 합쳐 단일 GPU에 안 들어가는 모델을 호스팅할 수 있습니다. model.tensorrtLlm.parallelism.pipeline 값을 바꾸면 파이프라인 병렬 처리가 켜져, 요청을 병렬로 처리하도록 여러 GPU의 연산 능력을 합칩니다.

모델 호스팅에 필요한 GPU 수는 .tensor.pipeline의 곱과 같아요. 모델을 호스팅하는 GPU는 반드시 같은 노드에 있어야 합니다. (서로 다른 노드의 GPU를 합치는 것은 이 가이드 범위 밖이에요.)

여러 GPU SKU 활용

특정 SKU GPU의 가용성이 제한적일 때 서비스는 혼합 GPU 하드웨어에서 돌아가야 하는 경우가 흔해요. 예를 들어 Hopper 기반 노드 수가 부족하고 Ampere 기반 노드가 남아 있다면, 같은 모델을 위 단계로 여러 번 배포하고 전부 하나의 쿠버네티스 서비스 뒤에 두면 됩니다. 차트가 서비스를 만들지 않도록 하고 공유 서비스의 셀렉터 라벨을 포함시키도록 차트를 갱신하면 각 SKU가 독립적으로 자동 확장되며 서비스에 연산 용량을 제공해요. 아래 예시는 서비스가 이미 만들어졌고 그 셀렉터가 model=llama-3-8b라고 가정합니다.

helm install llama-3-8b-a100 ./chart/. \
--values ./chart/values.yaml \
--values ./chart/llama-3-8b \
--set 'triton.image.name=<custom_image_name>' \
--set 'gpu[0]=NVIDIA-A100-SXM4-40GB' \
--set 'kubernetes.labels[0].model=llama-3-8b' \
--set 'kubernetes.noService=true'

helm install llama-3-8b-h100 ./chart/. \
--values ./chart/values.yaml \
--values ./chart/llama-3-8b \
--set 'triton.image.name=<custom_image_name>' \
--set 'gpu[0]=NVIDIA-H100-SXM5-80GB' \
--set 'kubernetes.labels[0].model=llama-3-8b' \
--set 'kubernetes.noService=true'

결과적으로 두 개의 배포가 생기고, 둘 다 서비스의 로드 밸런싱 풀에 속합니다.

kubectl get deployments --selector='model=llama-3-8b'
NAME                    READY   UP-TO-DATE   AVAILABLE
llama-3-8b-a100         1/1     1            1
llama-3-8b-h100         1/1     1            1

쿠버네티스에서 트리톤 모니터링

Prometheus 서비스 절에서 설치한 소프트웨어에는 Grafana 대시보드 서버가 포함돼 있어요. Grafana에 접속하려면 로컬 워크스테이션에서 클러스터로 네트워킹 터널을 만듭니다.

kubectl port-forward -n monitoring svc/prometheus-grafana 8080:80

성공하면 아래 같은 출력이 보여요.

Forwarding from 127.0.0.1:8080 -> 3000
Forwarding from [::1]:8080 -> 3000

브라우저에서 http://127.0.0.1:8080/로 접속하고, 처음엔 Grafana 로그인이 필요합니다.

  • Username: admin
  • Password: prom-operator

새 대시보드를 만들려면 우측 상단 + 아이콘 → New dashboard → Import dashboard를 선택하고, 제공된 grafana_inference-metrics_dashboard.json의 내용을 Import via dashboard JSON model에 붙여 넣거나 파일을 업로드하면 돼요.

GPU 이용률 대비 queue:compute 비율을 보면, 비율 그래프가 추가 리소스가 필요한 시점을 더 깔끔하게 보여주는 반면 GPU 이용률 그래프는 노이즈가 많아 HPA가 신호로 쓰기 어렵다는 걸 알 수 있어요.

이 가이드 작성 과정에서 배운 것

  • 메트릭 구성은 과학이자 예술 — 쿠버네티스 HPA 컨트롤러가 커스텀 메트릭을 어떻게 소비하는지 이해하는 데 시간이 걸렸어요. Prometheus Stack 설치 시 v2 HPA 컨트롤러가 커스텀 메트릭용 custom.metrics.k8s.io/v1beta1 엔드포인트를 자동으로 설정한다는 걸 알았죠. 메트릭을 조회하려면:
kubectl get --raw /apis/custom.metrics.k8s.io/v1beta1
kubectl get --raw /apis/custom.metrics.k8s.io/v1beta1/namespaces/default/pod/*/triton:queue_compute:ratio

  • 왜 이 소프트웨어 조합인가 — 이 문서의 패키지 구성은 커스텀 Helm 차트·YAML을 일일이 만들지 않는 최소 실행 가능 구성에 가까워요. NVIDIA Device Plugin(스케줄러가 GPU를 리소스로 취급), GPU Feature Discovery(노드 자동 라벨링 — 없으면 특정 GPU SKU를 지정할 수 없음), Node Feature Discovery, DCGM Exporter(하드웨어 메트릭 — 트리톤이 직접 제공하는 것보다 별도 수집이 프로세스 오버헤드·직렬화 지연·수집 주기 차이 측면에서 낫다), Prometheus Stack, Prometheus Adapter를 씁니다.
  • 차트가 트리톤 서버를 직접이 아니라 파이썬 스크립트로 실행하는 이유 — 모델을 Hugging Face에서 받아 TensorRT-LLM용으로 변환·최적화·캐시하는 초기화 컨테이너가 가장 직관적이고, 멀티 GPU 배포의 특수한 커맨드라인을 Helm 스크립팅으로 생성하는 것보다 커스텀 server.py가 쉽기 때문이에요.
  • client/ 폴더는 무엇인가 — 이 가이드 검증에 쓴 도구와 배포 정의입니다. kubectl apply -f ./clients/llama-3-8b.yamlkubectl scale deployment/llama-3-8b --replicas=<수>로 클라이언트 수를 늘리면 트리톤 부하가 커지고 queue:compute 비율이 HPA를 구동해 서버 인스턴스를 늘립니다.
  • 로드 밸런서 지침이 없는 이유 — 파드 메트릭으로 최적 인스턴스를 고르는 특수 로드 밸런서는 kube-proxy의 round-robin보다 개선이 미미했어요. 환경에 따라 결과는 다를 수 있으니 직접 실험해 보길 권합니다.

이 문서에 등장한 소프트웨어 버전:

  • Triton Inference Server v2.45.0 (24.08-trtllm-python-py3)
  • TensorRT-LLM v0.9.0
  • NVIDIA Device Plugin for Kubernetes v0.15.0
  • NVIDIA GPU Discovery Service for Kubernetes v0.8.2
  • NVIDIA DCGM Exporter v3.3.5
  • Kubernetes Node Discovery Service v0.15.4
  • Prometheus Stack for Kubernetes v58.7.2
  • Prometheus Adapter for Kubernetes v4.10.0

더 알아보기 (Learn more)