0. Contents


1. Overview

관리 셸1. 설치 절로 이동1helm install kukie-gpu …2. 선언 절로 이동2kubectl apply -f servedmodel.yaml클러스터 kukie-gpuEKS 컨트롤 플레인AWS 가 관리kube-apiserver + etcd객체가 사는 곳ServedModel gpt-oss-20b: 눌러서 설명 보기ServedModel gpt-oss-20bPVC gpt-oss-20b-models: 눌러서 설명 보기PVC gpt-oss-20b-modelsJob …-download-e599ed24: 눌러서 설명 보기Job …-download-e599ed24Deployment gpt-oss-20b: 눌러서 설명 보기Deployment gpt-oss-20bService gpt-oss-20b: 눌러서 설명 보기Service gpt-oss-20bPV pvc-<uid>: 눌러서 설명 보기PV pvc-<uid>Pod …-download-…-4qxtb: 눌러서 설명 보기Pod …-download-…-4qxtbPod gpt-oss-20b-…: 눌러서 설명 보기Pod gpt-oss-20b-…파랑: 사람 주황: 오븐 보라: CSI 회색: 쿠버네티스kube-controller-manager: 눌러서 설명 보기kube-controller-managerJob 컨트롤러 → 다운로드 PodDeployment 컨트롤러 → ReplicaSet → vLLM Podkube-scheduler: 눌러서 설명 보기kube-schedulernodeSelector 와 taint 로 GPU 노드를 고른다지켜본다적는다일반 노드Spot 2대kukie-oven: 눌러서 설명 보기kukie-oven1. 설치 절로 이동1ns kukie-gpu · ghcr.io/durokukie/kukie-oven:0.3.0이름을 먼저 검사하고 자식 리소스를 맞춘다3. 이름 검사 절로 이동3server-side apply, 필드 매니저 kukie-ovenPod 상태를 status.phase 로 옮긴다7. 상태 기록 절로 이동7ebs-csi-controller: 눌러서 설명 보기ebs-csi-controller ×24. PVC · 볼륨 절로 이동4ns kube-system · 역할 kukie-gpu-ebs-csiPod 의 노드가 정해지면 그 AZ 에 볼륨을 만든다볼륨에 Environment=gpu 태그를 단다경계: 그 태그의 볼륨과 인스턴스만PV 를 API 에 적는다GPU 노드g6e.xlarge · AZ 2bkubelet · ebs-csi-node: 볼륨을 포맷해 /models 로 마운트한다4. PVC · 볼륨 절로 이동4Pod · ns llm다운로드 Job: 눌러서 설명 보기다운로드 Jobhf downloadopenai/gpt-oss-20b5. 다운로드 절로 이동5vLLM: 눌러서 설명 보기vLLMvllm-openai:v0.32.0:8000 · GPU 1장6. vLLM 절로 이동6/models EBS gp3 40GiB · retainOnDelete 로 남는다NVIDIA L40S 46GiB · --gpu-memory-utilization 0.92AWS EC2 APICreateVolume · AttachVolume인터넷 (NAT)ghcr.io · docker.io · huggingface.co지켜본다적는다① 설치 절로 이동① 설치② 선언 절로 이동② 선언③ 이름 검사 절로 이동③ 이름 검사④ PVC · 볼륨 절로 이동④ PVC · 볼륨⑤ 다운로드 절로 이동⑤ 다운로드⑥ vLLM 절로 이동⑥ vLLM⑦ 상태 기록 절로 이동⑦ 상태 기록④ 의 볼륨은 ⑤ 의 Pod 노드가 정해진 뒤 생기고, ⑦ 은 끝이 아니라 매 단계 반복한다. 컨트롤러와 스케줄러는 ④ ⑤ ⑥ 을 돕는다
사람이 하는 일은 ① ② 뿐이다. 번호를 누르면 해당 절로 이동하고, 리소스 칸을 누르면 설명이 열린다

결과

  • kukie-gpu 의 L40S 에서 gpt-oss-20b 를 띄웠다
  • 노드 0대에서 시작해 14분 11초 만에 Ready 가 됐고 사람 개입은 없었다
  • 부하 측정과 429 는 아직 없다. 직접 만드는 이유의 핵심인 두 기능은 다음 구현 대상이다

2. Install — 차트와 GHCR

① 설치 절로 이동① 설치② 선언 절로 이동② 선언③ 이름 검사 절로 이동③ 이름 검사④ PVC · 볼륨 절로 이동④ PVC · 볼륨⑤ 다운로드 절로 이동⑤ 다운로드⑥ vLLM 절로 이동⑥ vLLM⑦ 상태 기록 절로 이동⑦ 상태 기록

설치 값

helm upgrade --install kukie-gpu charts/kukie-gpu --namespace kukie-gpu \
  --set dcgm.enabled=false --set rbac.enabled=false --set preflight.enabled=false --set namespaces.create=false \
  --set oven.enabled=true --set oven.image.tag=0.3.0 \
  --set oven.image.digest=sha256:13f621dd04412df0f76651eb94a2a562d2ed3694770ea2614f91d13939f2a40c \
  --set 'oven.imagePullSecrets[0].name=ghcr-pull' --wait --timeout 120s

kukie-gpu 의 1층은 아직 손으로 적용한 상태이고 Kukie GPU 화면이 쓰고 있어, 오븐만 별도 namespace 에 올렸다. 오븐이 뜨면 ServedModel 을 기다린다.

CRD 와 권한의 복사본

  • 차트는 Go 코드에서 생성한 CRD 와 Role 의 복사본을 files/oven/ 에서 읽는다
  • make manifests 가 함께 갱신하고, CI 와 단위 테스트가 원본과 다르면 실패시킨다

릴리스

  • 태그 v0.3.0 을 달면 이미지를 먼저 올린다
  • 방금 만든 이미지의 digest 를 values 에 채운 뒤 차트를 올린다
  • 받는 쪽은 차트만 정하면 이미지까지 고정된다

uninstall 동작

임시 kind 클러스터의 실제 출력$ helm uninstall kukie-gpu --namespace kukie-gpuThese resources were kept due to the resource policy:1[CustomResourceDefinition] servedmodels.serving.kukie.io2[Namespace] llmrelease "kukie-gpu" uninstalled지워지는 것Deployment kukie-ovenServiceAccount kukie-ovenClusterRole · ClusterRoleBindingRole · RoleBinding (리더 선출)오븐이 사라지면 ServedModel 을 맞추는 일만 멈춘다남는 것CRD servedmodels.serving.kukie.io1Namespace llm2ServedModel gpt-oss-20bPVC gpt-oss-20b-models① 이나 ② 가 지워지면 ServedModel 과 모델 파일이 사라진다
처음에는 CRD 만 남겼다. kind 에서 namespace 와 함께 ServedModel 이 사라지는 것을 보고 ② 를 더했다

임시 kind 에서 확인하다 찾은 문제다. CRD 만 남겼더니 차트가 만든 llm namespace 가 지워지며 ServedModel 과 PVC 가 함께 사라졌다. 오븐을 켰을 때 그 namespace 도 남기도록 고쳤다.


3. ServedModel — 모델 하나의 선언

① 설치 절로 이동① 설치② 선언 절로 이동② 선언③ 이름 검사 절로 이동③ 이름 검사④ PVC · 볼륨 절로 이동④ PVC · 볼륨⑤ 다운로드 절로 이동⑤ 다운로드⑥ vLLM 절로 이동⑥ vLLM⑦ 상태 기록 절로 이동⑦ 상태 기록
ServedModel (샘플과 실기 status)apiVersion: serving.kukie.io/v1alpha1kind: ServedModelmetadata:name: gpt-oss-20bnamespace: llmspec:source:1huggingface: openai/gpt-oss-20bengine:2image: vllm/vllm-openai:v0.32.0@sha256:…3gpus: 1args: ["--max-model-len", "16384", …]storage:4size: 40Gi5retainOnDelete: truestatus:6phase: Readyreason: HealthyobservedGeneration: 1download: {percent: 100}conditions: [Downloaded, Ready]모델 출처gated 모델은 tokenSecretRefJob …-download-e599ed241엔진 이미지digest 가 없으면 API 서버가 거부Deployment gpt-oss-20b2GPU 수요청 수이자 tensor parallelnvidia.com/gpu: 13디스크 크기확장은 사용자가 정한다PVC …-models 40Gi4남길지 여부다음에 같은 이름이 재사용PVC 에 소유자 없음5결과Kukie 화면이 이 객체 하나를 읽는다Ready / Healthy6
왼쪽 표시한 줄이 오른쪽 결과를 만든다. 오른쪽 값은 첫 GPU 실기에서 만들어진 실제 객체다

CRD 로 만든 이유: 상태를 한곳에

  • 스크립트나 Job 체인은 끝나면 상태가 남지 않는다
  • CRD 는 원하는 상태와 현재 상태를 한 객체에 둔다
  • Kukie 화면은 이 객체 하나를 읽으면 된다

단계와 이유

phase뜻reason 예시
Pending만들어짐, 또는 예전 리소스를 기다림Created, WaitingForOldResources
Downloading다운로드 중JobRunning, Retrying
LoadingvLLM 이 /health 에 답하기를 기다림Starting
Ready/health 통과Healthy
Measuring측정 요청을 받음. Job 은 구현 전MeasureJobNotImplemented
Failed사용자가 봐야 하는 실패Unschedulable, NameConflict, DownloadFailed

Failed 는 끝이 아니다

  • 노드가 없으면 Failed/Unschedulable 이다
  • 노드가 뜨면 사람 손 없이 다음 단계로 간다. 실기에서 그대로 확인했다

4. Reconcile — 만들기가 아니라 맞추기

① 설치 절로 이동① 설치② 선언 절로 이동② 선언③ 이름 검사 절로 이동③ 이름 검사④ PVC · 볼륨 절로 이동④ PVC · 볼륨⑤ 다운로드 절로 이동⑤ 다운로드⑥ vLLM 절로 이동⑥ vLLM⑦ 상태 기록 절로 이동⑦ 상태 기록
servedmodel_controller.go reconcile (요약)1conflict, leftover, err := r.findNameConflict(ctx, sm)if leftover != "" { // WaitingForOldResourcesreturn ctrl.Result{RequeueAfter: leftoverRequeue}, nil }if conflict != "" { // Failed/NameConflictreturn ctrl.Result{RequeueAfter: requeueWhileChanging}, nil }2r.reconcilePVC(ctx, sm)3downloaded, err := r.reconcileDownload(ctx, sm)if !downloaded {4r.stopEngine(ctx, sm)return ctrl.Result{RequeueAfter: requeueWhileChanging}, nil}5r.reconcileEngine(ctx, sm)6verdict, err := r.observePods(ctx, sm, componentEngine)// Ready · Failed · Loading 을 status 에이름 검사만들기 전에. 남의 리소스를 빼앗지 않는다1PVCRWO 라 Job 과 엔진이 차례로 쓴다2다운로드이름에 출처 해시. 같으면 다시 안 받음3엔진 정지출처가 바뀌면 vLLM 을 먼저 내린다4엔진Deployment 와 Service5관찰Pod 상태를 phase 로 옮긴다6결과: status.phase 의 흐름PendingCreatedDownloadingJobRunning · RetryingLoadingStartingReadyHealthyFailed: Unschedulable · NameConflict · ApplyRejected · DownloadFailed · CrashLoopBackOff, 원인이 풀리면 다음 reconcile 에서 돌아간다
Reconcile 은 ServedModel, 자식 리소스, Pod 가 바뀔 때 다시 돈다. 같은 입력이면 몇 번을 돌아도 결과가 같다

실행 순서의 이유

  • 이름 검사가 맨 앞이다. 뒤의 apply 는 ForceOwnership 이라 남의 객체도 가져올 수 있다
  • 소유자 참조까지 붙으면 ServedModel 을 지울 때 그 객체가 함께 지워진다
  • 다운로드가 끝나기 전에는 엔진을 만들지 않는다. PVC 가 ReadWriteOnce 라 동시에 쓰지 못한다

4.1 Name Check — 남의 것과 예전 것

① 설치 절로 이동① 설치② 선언 절로 이동② 선언③ 이름 검사 절로 이동③ 이름 검사④ PVC · 볼륨 절로 이동④ PVC · 볼륨⑤ 다운로드 절로 이동⑤ 다운로드⑥ vLLM 절로 이동⑥ vLLM⑦ 상태 기록 절로 이동⑦ 상태 기록

같은 이름의 객체가 있을 때 세 경우를 구분해야 한다. reconcile 에서 가장 경계 조건이 많은 부분이다.

객체판정처리
이 ServedModel 소유소유자 UID 일치그대로 맞춘다
같은 이름의 지워진 ServedModel 소유소유자 이름은 같고 UID 가 다름WaitingForOldResources, 5초마다 확인
그 외소유자가 다르거나 없음Failed/NameConflict, 아무것도 만들지 않음

PVC 는 레이블로 판정

  • retainOnDelete 인 PVC 는 소유자가 없다
  • 같은 이름으로 다시 만들 때 그 파일을 쓰는 것이 목적이므로 레이블 serving.kukie.io/servedmodel 을 본다
  • 그래서 레이블을 첫 apply 부터 붙인다

사람이 지운 PVC

  • 우리 PVC 를 사람이 지우면 vLLM 이 도는 동안 pvc-protection 이 붙잡아 계속 삭제 중으로 남는다
  • 이것까지 기다리면 영원히 멈춘다. 그래서 다른 소유자의 PVC 만 기다린다

4.2 PVC — server-side apply 와 field manager

① 설치 절로 이동① 설치② 선언 절로 이동② 선언③ 이름 검사 절로 이동③ 이름 검사④ PVC · 볼륨 절로 이동④ PVC · 볼륨⑤ 다운로드 절로 이동⑤ 다운로드⑥ vLLM 절로 이동⑥ vLLM⑦ 상태 기록 절로 이동⑦ 상태 기록
reconcilePVCif apierrors.IsNotFound(err) {1r.Apply(ctx, desiredPVCSpec(sm),client.FieldOwner(pvcSpecFieldManager),client.ForceOwnership)}2return r.Apply(ctx, desiredPVCMetadata(sm),client.FieldOwner(FieldManager),client.ForceOwnership)처음 한 번: 크기, 접근 모드, 클래스클래스는 불변이고 크기 변경은 볼륨 확장이다매번: 레이블, 소유자 참조retainOnDelete 를 바꾸면 소유자 참조가 따라온다합치면 메타데이터만 보낼 때 spec 소유를 놓는다실제 PVC 의 managedFieldskukie-oven/pvc-specApplyspec, labels1kukie-ovenApplylabels2kube-schedulerUpdateannotation selected-nodekube-controller-managerUpdatebind annotation, status
kubectl get pvc --show-managed-fields 로 읽은 값이다. 오븐의 두 매니저와 쿠버네티스 컨트롤러가 필드를 나눠 갖는다
  • Server-side apply 는 매니저가 이번에 말하지 않은 필드의 소유를 놓는다
  • PVC 는 스펙과 메타데이터의 적용 시점이 달라 매니저를 둘로 나눴다

4.3 Volume — EBS CSI 와 태그 경계

① 설치 절로 이동① 설치② 선언 절로 이동② 선언③ 이름 검사 절로 이동③ 이름 검사④ PVC · 볼륨 절로 이동④ PVC · 볼륨⑤ 다운로드 절로 이동⑤ 다운로드⑥ vLLM 절로 이동⑥ vLLM⑦ 상태 기록 절로 이동⑦ 상태 기록

애드온 기본 클래스를 쓴 이유

  • 이 클러스터 root 에는 Kubernetes provider 가 없다
  • 애드온 설정 defaultStorageClass.enabled 면 provider 없이 기본 클래스 ebs-csi-default-sc 가 생긴다
  • 만들어지는 볼륨은 gp3 이고 WaitForFirstConsumer 다

권한을 좁힌 이유

경계 kukie-gpu-ebs-csi-boundary (요약)Sid = "ManageGpuVolumes"Action = ["ec2:AttachVolume", "ec2:DetachVolume","ec2:ModifyVolume", "ec2:DeleteVolume","ec2:CreateTags", "ec2:DeleteTags"]Resource = ["…:volume/*"]1Condition = { StringEquals = {"aws:ResourceTag/Environment" = "gpu" } }AWS 정책AmazonEBSCSIDriverPolicyCSI 태그만 본다계정 전체 범위경계kukie-gpu-ebs-csi-boundaryEnvironment=gpu 만스냅샷, 복사 없음역할 kukie-gpu-ebs-csi두 정책의 교집합이 실제 권한이다Pod Identity 로 ebs-csi-controller-sa 에 붙는다IAM 시뮬레이터: ec2:DeleteVolumeEnvironment=gpuallowedEnvironment=devimplicitDenyEnvironment=prodimplicitDeny실제로 만들어진 볼륨 태그와 속성Environment=gpugp3 · 40GiBCSI cluster=trueAZ 2b생성, 연결, 쓰기, 분리, 삭제까지 통과했다
허용 쪽은 실제 볼륨으로, 거부 쪽은 시뮬레이터로 확인했다. 다른 클러스터의 볼륨을 실제로 지워 보지는 않았다
  • 이 계정에는 다른 클러스터의 CSI 볼륨이 이미 있었다
  • AWS 정책만 붙이면 GPU 클러스터의 컨트롤러가 그 볼륨까지 지울 수 있다
  • 애드온이 controller.extraVolumeTags 로 볼륨에 Environment=gpu 를 붙이고, 경계가 그 태그만 허용한다
  • 허용은 실제 볼륨의 생성부터 삭제까지로, 거부는 IAM 시뮬레이터로 확인했다

고객 클러스터에는 넣지 않는다

  • 스토리지 드라이버는 클라우드마다 다르고 IAM 권한이 필요하다
  • 애드온은 PVC 만 요청하고, preflight 가 빠진 것을 알려 준다

4.4 Download — 다운로드 Job

① 설치 절로 이동① 설치② 선언 절로 이동② 선언③ 이름 검사 절로 이동③ 이름 검사④ PVC · 볼륨 절로 이동④ PVC · 볼륨⑤ 다운로드 절로 이동⑤ 다운로드⑥ vLLM 절로 이동⑥ vLLM⑦ 상태 기록 절로 이동⑦ 상태 기록

이름에 출처 해시

  • Job 이름은 gpt-oss-20b-download-e599ed24 처럼 출처 해시를 포함한다
  • 끝난 Job 을 지우지 않고 “이 출처는 받았다” 는 표시로 쓴다
  • 출처가 바뀌면 이름이 달라져 새 Job 이 돌고, 옛 Job 은 지운다

시간 상한과 재시도

  • backoffLimit: 2, 기본 2시간 상한(--download-deadline)
  • 멈춘 다운로드가 GPU 노드를 계속 잡지 못하게 하려는 것이다

같은 노드 조건

  • Job 도 엔진과 같은 GPU 노드 조건을 쓴다
  • EBS 볼륨은 처음 쓰는 Pod 의 AZ 에 묶이므로, 일반 노드에서 받으면 엔진이 다른 AZ 에 뜰 수 있다

4.5 Engine — vLLM 기동

① 설치 절로 이동① 설치② 선언 절로 이동② 선언③ 이름 검사 절로 이동③ 이름 검사④ PVC · 볼륨 절로 이동④ PVC · 볼륨⑤ 다운로드 절로 이동⑤ 다운로드⑥ vLLM 절로 이동⑥ vLLM⑦ 상태 기록 절로 이동⑦ 상태 기록

모델 파일은 볼륨에서만

  • 다운로드가 끝난 뒤에만 Deployment 와 Service 를 만든다
  • HF_HUB_OFFLINE=1 로 엔진이 허깅페이스에 다시 접속하지 못하게 한다

기동 대기: 최대 40분

  • 큰 모델은 적재에 오래 걸려 startupProbe 를 10초 간격 240회로 둔다
  • /health 가 답하면 Ready 다. 이번 실기에서는 194초가 걸렸다

출처가 바뀔 때

  • 볼륨이 ReadWriteOnce 라 vLLM 을 먼저 0대로 내리고 새 다운로드를 시작한다
  • 그동안 서빙이 멈춘다. 옛 파일이 남으므로 storage.size 는 두 모델을 합친 크기여야 한다

4.6 Status — 상태 기록과 실패의 구분

① 설치 절로 이동① 설치② 선언 절로 이동② 선언③ 이름 검사 절로 이동③ 이름 검사④ PVC · 볼륨 절로 이동④ PVC · 볼륨⑤ 다운로드 절로 이동⑤ 다운로드⑥ vLLM 절로 이동⑥ vLLM⑦ 상태 기록 절로 이동⑦ 상태 기록
경우처리이유
일시적 API 오류phase 유지, 재시도, observedGeneration 유지아직 이 spec 을 처리하지 못했다
API 서버의 거부(invalid, forbidden)Failed/ApplyRejected다시 해도 같으므로 사용자가 봐야 한다
스케줄 불가, 이미지 문제, CrashLoop쿠버네티스 문구 그대로 Failed패턴표 분류는 구현 전이다

5. First GPU Run — 14분 11초

① 설치 절로 이동① 설치② 선언 절로 이동② 선언③ 이름 검사 절로 이동③ 이름 검사④ PVC · 볼륨 절로 이동④ PVC · 볼륨⑤ 다운로드 절로 이동⑤ 다운로드⑥ vLLM 절로 이동⑥ vLLM⑦ 상태 기록 절로 이동⑦ 상태 기록
노드 0대에서 Ready 까지: 851초 (14분 11초)phaseFailed: 104초 (0~104초)Downloading: 553초 (104~657초)Loading: 194초 (657~851초)FailedDownloadingLoading단계노드: 86초 (0~86초)볼륨, 이미지: 249초 (86~335초)모델 다운로드: 322초 (335~657초)vLLM 기동: 194초 (657~851초)86초볼륨, 이미지 249초모델 다운로드 322초vLLM 기동 194초0합류 76Bound 104이미지 끝 335다운로드 끝 657Ready 851같은 노드에서 Pod 만 재시작: 171초단계vLLM 기동: 171초 (0~171초)vLLM 기동 171초모델과 이미지가 이미 있다. 받는 시간이 없다읽는 법851초 중 571초(볼륨 연결과 이미지 249초 + 모델 322초)가 받는 시간이다. 콜드 스타트는 여기부터 줄여야 한다phase 의 Failed 는 노드가 뜨기 전 Unschedulable 이고, 노드가 뜨자 스스로 Downloading 으로 넘어갔다
이번 1회 측정값이다. 모델 크기, NAT 속도, 노드 상태에 따라 달라진다
시점경과
노드 합류76초
노드 Ready86초
PVC Bound, 다운로드 Pod 생성104초
다운로드 시작(이미지 받기 끝)335초
다운로드 끝, vLLM 생성657초
vLLM 실행667초
Ready851초

확인한 것

  • 모델 파일을 받은 볼륨이 vLLM 에 그대로 붙었고, 요청 2건에 정상으로 답했다
  • GPU 는 L40S 로 잡혔고 메모리는 --gpu-memory-utilization 0.92 대로 41GiB 를 미리 잡았다
  • ServedModel 을 지우자 Deployment, Service, Job 이 사라지고 retainOnDelete PVC 가 남았다
  • 실험 비용은 GPU 약 27분, 약 $1 이다

시간 분포

  • 이미지와 모델을 받는 데 약 10분이 들었다
  • 둘 다 있는 상태의 재시작은 171초다
  • 콜드 스타트를 줄이려면 이 10분을 먼저 줄여야 한다

새 노드의 일시적 경고

  • 새 노드에 CSI 드라이버가 뜨기 전에 ProvisioningFailed (no topology key found for node) 가 한 번 났다
  • 드라이버가 뜨자 혼자 복구됐다. 지금 status 는 이벤트에만 있는 이 경고를 보여 주지 않는다

6. Review — 리뷰에서 고친 것

① 설치 절로 이동① 설치② 선언 절로 이동② 선언③ 이름 검사 절로 이동③ 이름 검사④ PVC · 볼륨 절로 이동④ PVC · 볼륨⑤ 다운로드 절로 이동⑤ 다운로드⑥ vLLM 절로 이동⑥ vLLM⑦ 상태 기록 절로 이동⑦ 상태 기록

오퍼레이터 PR 은 리뷰 6라운드를 거쳤다. 지적은 대부분 경계 조건이었다.

지적고친 것
레이블 없는 우리 PVC 를 남의 것으로 판정첫 apply 부터 레이블
예전 다운로드 Job 을 “이미 받음” 으로 착각해 빈 PVC 로 vLLM 기동다른 소유자의 Job 을 기다림
사람이 지운 PVC 에 영원히 대기다른 소유자의 PVC 만 기다림
restartPolicy: Never Pod 의 실패 원인이 Pod reason 에 없음컨테이너 종료 코드를 읽음
스토리지 없는 클러스터에서 Downloading 에 멈춘 채 원인을 안 보임스케줄 불가 사유를 status 로
사용자가 준 리소스와 기본값이 어긋나 거부키별 병합

CI 에서 드러난 테스트 경쟁

  • 컨트롤러는 Job 을 만든 뒤 status 를 쓴다
  • 테스트가 그 틈을 읽어 CI 에서 0.003초 만에 실패했고 로컬에서는 통과했다
  • 상태가 바뀔 때까지 기다린 뒤 검사하도록 고쳤다

7. Limits — 확인 못 한 것과 남은 일

확인 못 한 것

항목상태
처리량요청 2건뿐이다. 첫 토큰 시간도 각 1회라 측정값이 아니다
다른 AZ 의 노드이번에는 볼륨과 노드가 모두 2b 였다. 노드 그룹은 2a·2b 에 걸쳐 있어 어긋날 수 있다
노드부터 새로 켠 재사용171초는 노드가 떠 있고 이미지도 있을 때의 값이다

현재 한계

  • 쓰기 권한이 ClusterRole 이다. 공개 전에 namespace 로 좁힌다
  • 다운로드 진행률은 0 과 100 뿐이다
  • 실패 원인은 쿠버네티스 문구 그대로다
  • 측정과 어드미션은 필드만 있다

남은 일

  1. 측정 Job 으로 gpt-oss-20b 의 SLA 안 최대 동시 요청을 잰다
  2. 그 값을 status.baseline 에 기록한다
  3. 어드미션 위치를 정하고 429 를 잇는다

관련 문서

출처