본문으로 건너뛰기

카나리 배포 운영 가이드

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-percentspec.predictor.canaryTrafficPercent 두 곳을 동시에 패치 — annotation 은 UI 표시용, spec 필드가 실제 라우팅 제어.
  • M2 는 Istio VirtualService 를 작성하지 않음. RawDeployment 모드 + KServe native split 으로 충분. M3 에서 헤더 기반 sticky-session 라우팅이 필요해지면 VirtualService 추가.

2. 라이프사이클

  1. 신규 모델 배포POST /deployments + POST /deploycanary_percent=0 (전체 트래픽이 primary).
  2. 점진 노출PUT /deployments/{id}canary_percent 단계적 증가: 5 → 25 → 50.
  3. 모니터링 — Prometheus /metrics + audit log model.predict.upstream_error 카운트, 회귀 신호 감시.
  4. 결정:
    • 안정 → 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.updatechanged=[…] + previous={…}
POST /{id}/promotemodel.deploy.promotemodel + version + caller
POST /{id}/rollbackmodel.deploy.rollbackmodel + version + caller
POST /{name}/predictmodel.predictrevision + 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-statusready: 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"
}'

관련