카나리 배포 운영 가이드
GenD KServe 자동화 (Epic #1082 M2) 의 카나리 라이프사이클 정책을 정리한다.
1. 카나리 모델
PoC M2 의 카나리는 단일 InferenceService 안의 traffic split 을 단일 percent 값으로 제어한다:
client ──▶ KServe controller ──┬─ primary revision (100 - canary_percent)%
└─ canary revision (canary_percent)%
- 트래픽 분할은 KServe
spec.predictor.canaryTrafficPercent(KServe 0.13+) 에서 처리. apply_canary_traffic()가metadata.annotations.gend.genon.ai/canary-percent와spec.predictor.canaryTrafficPercent두 곳을 동시에 패치 — annotation 은 UI 표시용, spec 필드가 실제 라우팅 제어.- M2 는 Istio
VirtualService를 작성하지 않음. RawDeployment 모드 + KServe native split 으로 충분. M3 에서 헤더 기반 sticky-session 라우팅이 필요해지면 VirtualService 추가.
2. 라이프사이클
- 신규 모델 배포 —
POST /deployments+POST /deploy—canary_percent=0(전체 트래픽이 primary). - 점진 노출 —
PUT /deployments/{id}로canary_percent단계적 증가: 5 → 25 → 50. - 모니터링 — Prometheus
/metrics+ audit logmodel.predict.upstream_error카운트, 회귀 신호 감시. - 결정:
- 안정 →
POST /deployments/{id}/promote(100% — canary 가 primary 로 승격). - 회귀 →
POST /deployments/{id}/rollback(0% — primary 로 복구).
- 안정 →
3. 의사 결정 기준
각 단계 (5/25/50/100%) 사이에 다음 신호를 최소 30분 관측:
| 신호 | 임계 | 출처 |
|---|---|---|
| HTTP 5xx 비율 | < 1% | model.predict.upstream_error audit 라인 카운트 |
| p99 지연 | baseline + 20% 이내 | prometheus_client serving 메트릭 |
| ABAC 거부율 | 변동 없음 | model.predict.denied audit 라인 카운트 |
| 모델 정확도 (있다면) | baseline 동등 | shadow eval (M3) |
위 임계 중 하나라도 초과 시 즉시 /rollback. 모두 OK 면 다음 단계로.
4. /predict 의 카나리 분기 의미
/predict 프록시는 호출마다 random.randint(1, 100) 으로 primary vs canary 를 추첨하여 감사 라인의 revision=primary|canary 필드 에 기록:
gend.audit model.predict model=iris alias=Production caller=alice subject=… workspace=… revision=canary status=200 ms=12.3 outputs=1
- 실제 라우팅은 KServe controller 가 cluster 내부에서 처리 (proxy 는 URL 분기하지 않음).
- audit 의
revision은 "이 호출이 canary 로 갔다고 가정했을 때" 를 의미 — M3 에서 실제 라우팅과의 일치 여부를 비교하는 shadow eval 의 기준선. canary_percent=0→ 항상primary,canary_percent=100→ 항상canary.
5. API 호출 예시
# 단계적 카나리 노출
for pct in 5 25 50; do
curl -X PUT https://gend.genon.ai/api/v1/serving/deployments/$ID \
-H "Authorization: Bearer $JWT" \
-d "{\"canary_percent\": $pct}"
echo "Canary at ${pct}% — monitoring 30m..."
sleep 1800
done
# 안정 → 승격
curl -X POST https://gend.genon.ai/api/v1/serving/deployments/$ID/promote \
-H "Authorization: Bearer $JWT"
회귀 발견 시:
curl -X POST https://gend.genon.ai/api/v1/serving/deployments/$ID/rollback \
-H "Authorization: Bearer $JWT"
6. 감사 트레일
| 라우트 | 감사 키 | 페이로드 |
|---|---|---|
PUT /{id} | model.deploy.update | changed=[…] + previous={…} |
POST /{id}/promote | model.deploy.promote | model + version + caller |
POST /{id}/rollback | model.deploy.rollback | model + version + caller |
POST /{name}/predict | model.predict | revision + status + ms + outputs |
전부 gend.audit 채널 (AuditMiddleware 의 요청 단위 라인과 동일 태그). M3 에서 OpenSearch sink + L2 HMAC chain 통합.
7. 트러블슈팅
KServe 가 spec 패치를 거부 (409)
patch_namespaced_custom_object 가 stale revision 으로 409 → apply_canary_traffic() 가 ServingDeployError(status_code=409) 으로 전달, 라우터가 409 surface. 재시도하면 일반적으로 통과 (다른 controller 가 동시에 패치한 상태).
/predict 가 503 (predictor not yet ready)
KServe controller 가 새 revision 배치 중. GET /deployments/{id}/k8s-status 로 ready: true 확인 후 재시도. 30초 이상 지속 시 Pod 로그 확인:
kubectl logs -n gend -l serving.kserve.io/inferenceservice=<name> --tail=200
/predict 가 403 (ABAC 거부)
호출자에게 ModelGrant.invoke 가 없음. 관리자가 다음으로 등록:
curl -X POST https://gend.genon.ai/api/v1/model-grants \
-H "Authorization: Bearer $ADMIN_JWT" \
-d '{
"model_name": "<model>",
"subject_type": "user",
"subject_id": "<keycloak sub>",
"action": "invoke"
}'
관련
- serving-install.md — KServe 설치 + M2 신규 라우트 표
- model-access-control.md — ABAC
ModelGrant정책 - Epic #1082
- M2 ABAC PR #1228 —
ModelGrantService.check_access