실습: 서빙 환경 확인 결과 기록하기¶
승인된 모델 패키지와 API 응답을 대조해도, 실제로 보지 않은 대상 환경까지 결론 낼 수는 없습니다. 이 실습에서는 어떤 모델 패키지(model package)와 API 입출력 형식을 어느 환경에서 직접 확인했는지 기록합니다.
실습 결과로 남길 네 가지
- 로컬 또는 대상 환경에서 확인한 모델 패키지의
profile과 해시값 - API 모델 정보와 정상 200·비정상 422의 실제 응답
- 직접 확인한 URL·환경·시간
- 아직 확인하지 못한 대상 환경과 다음 확인 담당자
강의 순서에서의 위치
로컬 API 성공과 대상 Kubernetes 환경의 성공은 같은 근거가 아닙니다. 2일차 1교시에 Compose의 200, 422, 요청 ID를 확인하고, 2교시에 API와 모델 파일, 배포 설정을 대조합니다. 3교시에는 Kubernetes 배포 선언을, 4교시에는 GitOps 화면과 배포 완료의 네 단계를 기록합니다.
실습 목표와 확인 환경¶
선택한 모델 패키지, API가 돌려준 모델 정보, 확인한 실행 환경이 서로 맞아야 보고서에서 실행 중인 모델을 설명할 수 있습니다. 이 실습에서는 이 세 자료를 연결하며, profile, 해시값, request_id, target_pending의 의미가 낯설다면 실행 환경과 운영 기록을 먼저 읽습니다.
실행 경로 선택
모든 명령은 tta-aiqa 저장소 루트에서 실행합니다. 실습 환경 준비에서 내 공개 HTTPS와 가상 컴퓨터 접속을 확인합니다. 공개 베이스에서는 /health/ready와 /v1/model을 GET하고, Docker가 있으면 로컬 Compose http://127.0.0.1:8000으로 입출력 형식을 연습합니다. 없으면 설정 파일과 노트북의 정적 검사를 사용합니다.
로컬 Compose는 기존 운영 모델을 나타내는 baseline 프로필의 공개 API만 재현하며 /v1/model의 backend=local입니다. 수업용 공개 HTTPS의 /v1/model은 backend=kserve입니다. 실제 응답을 받지 않았다면 score나 request_id를 추정하지 않으며, Candidate B 대상 환경을 보지 못했다면 실행하지 못한 이유와 다음에 필요한 환경을 기록합니다.
0. 확인할 환경 정하기¶
운영 환경 확인 상태는 직접 본 자료에 맞춰 정해야 합니다. 2장에서 확정한 Candidate
B의 APPROVE는 바꾸지 않습니다. 설정 파일과 노트북만 확인하는 동안에는
prepared로 기록하고, Candidate B를 대상 후보로 정한 뒤에도 URL과 운영 근거가
없다면 최종 상태를 target_pending으로 갱신합니다.
상태값은 외우는 답이 아니라 지금 가진 근거로 보고 범위를 고르는 기준입니다.
| 상태값 | 이 실습에서의 운영 환경 확인 상태 |
|---|---|
prepared |
로컬 모델 파일과 배포 설정을 확인했지만 API 또는 대상 환경은 직접 보지 못했습니다. |
baseline scope=local |
기본 로컬 Compose에서 기존 운영 모델의 정보와 정상·비정상 응답을 확인했습니다. Candidate B의 운영 환경 확인 상태는 아닙니다. |
local_verified |
Candidate B를 로컬에서 실제 서빙하고 같은 모델의 정보, 정상·비정상 요청과 운영 자료를 직접 확인했습니다. |
target_verified |
제공된 대상 환경에서 모델 정보와 필요한 운영 자료를 직접 확인했습니다. |
target_pending |
대상 환경을 아직 확인하지 못했으며, 필요한 담당자와 자료를 보고서에 남겼습니다. |
1. 로컬 모델 패키지 준비 상태 확인¶
이 단계에서는 강사가 준비한 로컬 API가 어떤 기존 운영 모델을 읽는지만 확인하며, Candidate B 대상 환경의 실행을 증명하지 않습니다.
런타임 동일성은 파일 하나의 이름이 아니라 배포 기록, 메타데이터, 세 해시값, 읽기 전용 마운트, API 응답이 같은 모델을 가리키는지로 판단합니다. 다음 명령은 생성된 로컬 모델 패키지가 있을 때만 실행 증거를 만듭니다.
MODEL_DIR=artifacts/models/revisions/v2/deployed
if test ! -f "$MODEL_DIR/deployment.json" || \
test ! -f "$MODEL_DIR/metadata.json" || \
test ! -f "$MODEL_DIR/model.joblib"; then
echo "BLOCKED: generated runtime model package is missing"
else
jq '{profile, model_sha256, canonical_evidence_sha256, release_status}' \
"$MODEL_DIR/deployment.json"
jq '{profile, model_sha256,
feature_contract_sha256: .feature_contract.sha256}' \
"$MODEL_DIR/metadata.json"
shasum -a 256 "$MODEL_DIR/model.joblib" \
"$MODEL_DIR/metadata.json" configs/contracts/model-input.yaml
rg -nF '../artifacts/models/revisions/v2/deployed:/runtime/model:ro' \
deploy/compose.yaml
curl -sS http://127.0.0.1:8000/v1/model | \
jq '{backend, profile, version, threshold, feature_count, education_only}'
fi
모든 런타임 파일이 있으면 기존 운영 모델에서 다음 값이 서로 연결돼야 합니다. 전체 값을 그대로 기록해야 앞 12자리만 같은 다른 파일을 잘못 승인하는 일을 막을 수 있습니다.
| 대조 대상 | 예상값 | 기록할 관측값 | QA 해석 |
|---|---|---|---|
deployment.json |
profile=baseline, release_status=BASELINE_ROLLBACK, model_sha256=f2576f12512a490c9814e5238c3f0d2a421a21637a4b03c882df6ff25a637edc |
[직접 출력] |
로컬에 선택한 배포 기록입니다. |
metadata.json |
같은 profile과 model_sha256, feature_contract_sha256=fbd02c6149682807d0f3a6d8f7a1c0b823fee96eccf0c13eb584e88a320aede3 |
[직접 출력] |
모델과 133개 입력 규약의 연결입니다. |
| 실제 파일 SHA-256 | 모델 f2576f...637edc, 메타데이터 8bbb9b827cce06cc1458b14b88ec6188e1d57001cc93fe3688633dc97f81a6e9, 입력 규약 fbd02c...aede3 |
[직접 출력] |
선언값과 실제 바이트가 같은지 확인합니다. |
deploy/compose.yaml |
../artifacts/models/revisions/v2/deployed:/runtime/model:ro |
[행 번호와 설정] |
컨테이너가 같은 디렉터리를 읽기 전용으로 사용합니다. |
/v1/model |
backend=local, profile=baseline, version=baseline-f2576f12512a, threshold=0.5, feature_count=133, education_only=true |
[직접 응답 또는 API 미실행] |
실제 프로세스가 보고한 공개 런타임 식별값입니다. |
생성물은 저장소를 받은 직후 존재하지 않을 수 있으므로, 하나라도 없으면 런타임
동일성 결과를 BLOCKED로 기록합니다. 이때 추적되는 정적 자료는 다음처럼 확인할
수 있지만, 이 자료로 파일 마운트나 API 실행을 확인했다고 쓰지 않습니다.
jq '{initial_deployed_profile,
baseline: .bundles.baseline}' \
docs/evidence/model-v2/model-bootstrap.json
jq '{approved_profile, approved_model,
baseline_model: .model_bundles["baseline/model.joblib"],
baseline_metadata: .model_bundles["baseline/metadata.json"]}' \
docs/evidence/model-v2/release-manifest.json
정적 fallback은 기존 운영 모델의 예상 모델 및 메타데이터 SHA-256과 Candidate B의
승인 식별값을 비교하는 자료입니다. 생성된 런타임 파일과 /v1/model이 없으면
상태는 계속 BLOCKED이며, 서빙 담당자가 모델 패키지를 생성한 뒤 같은 명령을 다시
실행해야 합니다.
baseline은 안전하게 되돌릴 수 있는 공개 API 동작을 연습하기 위한 로컬 프로필입니다. 이 명령의 결과나 로컬 Compose의 200, 422는 Candidate B 대상 환경의 실행 근거가 아닙니다. PersistentVolumeClaim(PVC)은 컨테이너가 사용할 저장소를 요청하는 Kubernetes 리소스입니다. Candidate B는 다음 절의 정적 배포 설정에서 예상 해시값과 PVC 경로를 먼저 대조하고, 실제 대상 환경은 GitOps가 Git에 저장한 배포 선언을 동기화한 뒤에만 확인합니다.
JSON 출력에는 profile=baseline, release_status=BASELINE_ROLLBACK, 기존 운영 모델 해시값이 보여야 합니다. 이 파일은 로컬 마운트에 무엇을 준비했는지 알려 주므로 prepared 범위의 자료로 기록합니다.
2. Docker Compose API 확인¶
로컬 API에서 확인할 핵심은 정상 입력의 HTTP 200과 의도적으로 잘못 만든 입력의 HTTP 422를 구분하는 것입니다. 아래 명령은 기존 운영 모델 API의 입출력 형식과 요청 기록을 만드는 경로입니다.
실행 순서는 다음과 같습니다.
- Risk API를 시작하고
/health/ready,/v1/model으로 준비 상태와 모델 정보를 봅니다. baseline트래픽으로 정상 200과 응답의 요청 ID를 확인합니다.invalid트래픽으로 422와MODEL_INPUT_INVALID를 확인합니다.- 실행하지 못했다면 노트북의 정적 검사와 막힌 조건만 기록합니다.
docker compose -f deploy/compose.yaml up -d --no-build risk-api
curl http://127.0.0.1:8000/health/ready
curl http://127.0.0.1:8000/v1/model
docker compose -f deploy/compose.yaml \
--profile traffic run --rm \
--user "$(id -u):$(id -g)" \
traffic-generator baseline --count 20 --fast
docker compose -f deploy/compose.yaml \
--profile traffic run --rm \
--user "$(id -u):$(id -g)" \
traffic-generator invalid --count 3 --fast
이 명령에서 확인할 핵심은 정상 트래픽의 HTTP 200과 의도적으로 잘못 만든 트래픽의 HTTP 422입니다. /v1/model의 모델 정보, 응답 본문에 든 request_id 하나, 트래픽 응답 요약, 생성된 artifacts/traffic/ 경로를 기록합니다.
상태 코드는 오류가 난 위치를 알려 줍니다. 같은 실패로 묶어 쓰지 않습니다.
| HTTP 상태 | 이 실습에서 뜻하는 것 | 보고서에 쓰지 않는 것 |
|---|---|---|
| 200 | 이 요청이 입력 검사를 통과하고 예측 응답을 받았다 | 모델 품질이 좋다, Candidate B가 대상에서 실행 중이다 |
| 422 | 입력 규약 오류로 모델 실행 전에 거절됐다 | 모델이 고장 났다, 5xx와 같은 운영 장애다 |
| 413 | 요청 본문이 너무 커서 파싱하지 않았다 | 입력 필드 이름 오류와 같은 422다 |
| 5xx | 서버 처리 문제 후보 | 입력 오류나 모델 성능 저하를 바로 증명한다 |
요청 ID는 나중에 로그와 처리 경로에서 같은 요청을 찾는 연결값입니다. 인증 정보나 원인 증명이 아닙니다.
이 단계의 --fast는 요청 간격과 수집 대기를 생략해 API 규약을 빠르게 확인합니다. 따라서 4장의 Grafana 요청률·시나리오 비교 근거로 사용하지 않습니다. 4장 실습에서는 --fast를 빼고 Alloy 수집 대기를 유지합니다.
트래픽 JSONL에는 run ID와 request ID가 저장되지만 응답 헤더는 저장되지 않습니다. 따라서 이 경로를 사용했다면 X-Request-ID 헤더를 확인했다고 쓰지 않습니다. 여기서 확인하는 request_id는 한 요청을 나중에 로그와 추적 기록에서 연결하는 값이며, Prometheus 지표 레이블로 쓰지 않습니다.
입력 거절 계약은 직접 요청을 손으로 만들기 전에 통합 테스트로 재현할 수 있습니다. 이 검사는 필수 필드 누락, 허용되지 않은 필드 추가, 잘못된 타입이 모두 422로 분류되는지와 크기 제한을 넘은 본문이 413으로 먼저 거절되는지를 확인합니다.
uv run pytest -q tests/integration/apps/serving/test_risk_api.py \
-k 'rejects_contract_errors or oversized or framework_request_validation'
| 검사 입력 | 예상 상태와 분류 | 기록할 결과 | 보고 범위 |
|---|---|---|---|
| 모델 특성 누락 | 422, missing |
[통과/실패] |
입력 규약 거절 확인 |
| 허용되지 않은 특성 또는 요청 필드 추가 | 422, extra |
[통과/실패] |
입력 규약 거절 확인 |
| 특성 또는 요청 본문의 타입 오류 | 422, type |
[통과/실패] |
입력 규약 거절 확인 |
| 제한보다 큰 요청 본문 | 413, REQUEST_BODY_TOO_LARGE |
[통과/실패] |
본문 크기 제한 확인 |
이 저장소에는 5xx를 재현한 준비된 증거가 없습니다. 위 테스트가 통과해도 5xx를
관측한 것이 아니므로 보고서에는 5xx=미관측, 출처는 준비된 증거 없음, 다음
행동은 서빙 담당자가 대상 시간대의 서버 로그와 지표를 수집으로 기록합니다.
Docker 명령을 실행할 수 없거나 로컬 서비스가 시작하지 않으면 다음 노트북의 정적 검사 절을 실행합니다. API_NOT_RUNNING은 대상 환경이나 실제 API의 결과가 아니라, 실행을 막은 조건과 다음 조치를 알려 주는 출력입니다.
labs/chapters/ch03/01_verify_risk_api.ipynb
노트북은 운영용 입력 묶음에서 만든 133개 특성 요청과 KServe 기준 배포 설정의 입출력 규칙을 읽습니다. 로컬 API가 없을 때에는 prepared만 보고합니다. 기본 baseline API를 실행했다면 기존 운영 모델의 로컬 확인 범위만 scope=local로 기록하며, Candidate B를 실제 로컬 서빙한 근거 없이 local_verified라고 쓰지 않습니다.
요청별 기록 확인¶
트래픽 명령을 실행한 뒤에는 /v1/model의 모델 정보와 정상, 비정상 응답 기록을 분리해 봅니다. 트래픽 생성기는 133개 특성을 모두 채운 요청을 만들고 artifacts/traffic/compose.jsonl에 request_id, 시나리오, 상태 코드, 응답 본문을 덧붙입니다. 일부 특성만 손으로 넣고 정상 요청이라고 가정하지 않습니다.
기존 compose.jsonl은 이전 실행과 다른 응답 형식이나 Candidate B 시나리오를 포함할 수 있으므로, 명령을 실행하지 않았다면 이번 교시의 관측 근거로 사용하지 않습니다. 직접 실행한 경우에도 이번 실행에서 생성한 run ID와 행만 고르고, education_only나 입력 오류 분류가 비어 있으면 확인한 필드까지만 기록합니다.
curl -sS http://127.0.0.1:8000/v1/model | \
jq '{backend, profile, version, threshold, feature_count, education_only}'
jq -c 'select(.scenario == "baseline") |
{request_id, scenario, status_code, response_request_id: .body.request_id,
profile: .body.model_profile, version: .body.model_version,
education_only: .body.education_only}' \
artifacts/traffic/compose.jsonl | tail -n 1
jq -c 'select(.scenario == "invalid") |
{request_id, scenario, status_code, response_code: .body.detail.code,
validation_category: .body.detail.validation_category}' \
artifacts/traffic/compose.jsonl | tail -n 1
정상적인 기존 운영 모델의 로컬 API에서는 /v1/model에서 backend=local, profile=baseline, version=baseline-f2576f12512a, threshold=0.5, feature_count=133, education_only=true를 확인합니다. score와 prediction은 입력에 따라 달라지므로 특정 숫자를 예상 결과로 쓰지 않습니다.
두 JSONL 행에서는 기존 운영 모델 API의 status_code=200, 응답 본문의
request_id가 바깥 request_id와 연결되는지, education_only=true인지
확인합니다. 이 값은 예측을 임상 판단에 사용할 수 있다는 승인이 아니라
교육용 경계를 응답마다 유지하는 표시입니다. 비정상 행에서는
status_code=422, response_code=MODEL_INPUT_INVALID,
validation_category가 missing|extra|type|other 중 하나인지 확인합니다.
응답 본문의 요청 ID는 4장에서 같은 요청의 로그와 추적 기록을 찾는 데 쓰며
Prometheus 지표 레이블이 아닙니다.
3. Kubernetes 배포 설정 점검¶
수강생은 Kubernetes 공동 환경에 요청하거나 배포 명령을 다루지 않습니다. 다음 계약 검사로 Candidate B 배포 선언의 프로필·전체 SHA-256·고정 모델 경로를 대조합니다. 실제 서버 측 검사와 GitOps 동기화는 플랫폼 담당자가 수행합니다.
uv run --group dev pytest -q tests/integration/deployment/test_kubernetes_contract.py \
-k 'test_risk_api_uses_internal_kserve_and_read_only_secret_volume or candidate_and_rollback_overlays_select_only_approved_models'
sed -n '1,125p' deploy/k8s/base/risk-api.yaml
sed -n '1,90p' deploy/k8s/base/inference-service.yaml
jq '{images, target_verification}' \
docs/evidence/deployment/runtime-images-v2.json
rg -n 'image: .*@sha256:' deploy/k8s/base/risk-api.yaml \
deploy/k8s/base/inference-service.yaml
git log -1 --format=%H -- .dockerignore pyproject.toml uv.lock apps packages
배포 선언에서는 서로 대신할 수 없는 두 지문을 함께 읽습니다. 이미지 digest는 실행 코드와 라이브러리를 식별하고, 모델 SHA-256은 학습 결과 파일을 식별합니다. 이미지가 같아도 연결한 모델 경로가 다르면 예측 규칙이 달라집니다.
이 테스트는 candidate-b-c712a8e52344 고정 PVC subPath를 읽는 Candidate B 배포 설정과 기존 운영 모델 롤백 설정을 확인합니다. 결과는 다음처럼 해석합니다.
- 성공: 배포 설정이 승인된 Candidate B 경로와 기존 운영 모델 롤백 경로를 선택합니다.
- 실패: 모델 패키지와 배포 선언의 연결을 다시 확인해야 합니다.
- 한계: Candidate B 대상 API를 실제로 확인한 결과는 아니므로
target_verified라고 기록하지 않습니다.
정적 배포 증거는 네 연결 지점을 한 행씩 기록해야 누락된 네트워크 연결이나 잘못된 이미지와 모델 조합을 찾을 수 있습니다.
| 연결 지점 | 설정에서 확인할 값 | 출처 | 기록할 결과와 해석 |
|---|---|---|---|
| Service selector와 port | app.kubernetes.io/name=risk-api, Service port=80, 컨테이너 containerPort=8000 |
deploy/k8s/base/risk-api.yaml |
[확인/미확인]; 외부 요청이 Risk API Pod로 향하는 선언입니다. |
| Risk API에서 predictor | backend=kserve, 내부 mortality-risk-predictor URL |
첫 번째 계약 테스트와 risk-api.yaml |
[확인/미확인]; API가 로컬 모델 대신 predictor를 호출하는 선언입니다. |
| 모델 PVC mount | claimName=course-models, readOnly=true, Candidate B subPath=physionet-2012/v2/candidate-b-c712a8e52344 |
두 manifest와 overlay 테스트 | [확인/미확인]; API와 predictor가 같은 승인 모델 경로를 읽는 선언입니다. |
| 실행 이미지와 모델 지문 | Risk API sha256:20f47861095b23548d82d3270f01f8bc54b5aa1cd91eb6172f6919403ebd959c, predictor sha256:63ff48ef33105181186919b777e3e60ac3bbc6c78f0f545154049701bbcd8fb0, Candidate B 모델 c712a8e52344c09a493629f8e6a0283c6c3139fb46cc53e293a44ee490a07c95 |
runtime-images-v2.json, 두 base manifest, overlay, release-manifest.json의 정적 대조 |
[확인/미확인]; 코드 이미지 두 개와 모델 파일을 따로 식별합니다. |
docs/evidence/deployment/runtime-images-v2.json의 로컬 검증은 verified이지만
target_verification.status=pending입니다. 따라서 이 표는 배포 선언의 일관성을
확인할 뿐이며, 대상 클러스터에서 이미지가 실행됐거나 Candidate B 요청이 성공했다는
근거가 아닙니다.
이미지 증거의 source_commit과 마지막 명령의 현재 빌드 입력 개정본이 다르면 두
manifest의 digest 문자열이 JSON과 같더라도 이미지 출처 확인은 미확인으로
기록합니다. 이 경우 담당자는 빌드 담당자이며, 다음 행동은 현재 개정본으로 이미지
증거를 다시 발행하고 플랫폼 담당자가 대상 검증을 완료하는 것입니다.
Candidate B 배포와 롤백은 5장에서 판단 조건으로 다룹니다. 수강생은 직접
릴리스 상태를 바꾸지 않습니다. 대상 환경을 확인하지 않았다면 정적 검사만 확인하고
target_pending으로 남깁니다.
4. GitOps와 배포 완료 기록¶
수강생은 Argo Application을 만들거나 sync하지 않습니다. 강사가 보여 준 화면이 있으면 아래 네 단계를 각각 확인했는지 적고, 보지 못한 단계는 미확인으로 남깁니다.
배포 완료는 한 화면의 Synced만으로 주장하지 않습니다. 목표 상태가 올바른지, Git 기록이 반영됐는지, Pod와 모델 서비스가 준비됐는지, 실제 요청이 성공했는지를 순서대로 봅니다.
| 단계 | 확인하는 것 | 상태 | 출처 | 담당자 | 다음 행동 |
|---|---|---|---|---|---|
| 1. 목표 상태 | overlay의 프로필, 모델 SHA-256, 경로 | [확인/미확인] |
overlay 테스트와 manifest | QA | 승인 식별값과 다르면 배포 보류 사유를 기록합니다. |
| 2. Git 반영 | 개정본과 동기화 상태 | 미확인 |
준비된 Argo 상태 자료 없음 | 플랫폼 담당자 | 승인된 대상 화면과 개정본을 수집합니다. |
| 3. 준비 상태 | Pod와 InferenceService 준비 상태 |
미확인 |
준비된 Argo 상태 자료 없음 | 플랫폼 담당자 | 대상 컨텍스트에서 준비 상태와 확인 시각을 수집합니다. |
| 4. 실제 요청 | 대상 /v1/model과 정상 예측 |
미확인 |
runtime-images-v2.json의 target_verification.status=pending |
서빙 담당자 | 승인된 대상 URL에서 모델 정보와 정상 요청을 확인합니다. |
연결 오류로 현재 상태를 읽지 못하면 sync와 health도 확인하지 못한 것입니다. 그 아래 층을 추측해 채우지 않습니다. rollback overlay 파일이 있다는 사실만으로 복구 완료를 적지 않습니다.
복구 역시 선언, 적용, 준비, 요청의 네 증거가 모두 있어야 완료로 판단합니다. 현재는
준비된 Argo 상태 자료가 없고 대상 검증도 pending이므로 확인하지 않은 상태를
그대로 남깁니다.
| 복구 증거 | 상태 | 출처 | 담당자 | 다음 행동 |
|---|---|---|---|---|
| rollback overlay가 기존 운영 모델 SHA-256과 경로를 선택 | [확인/미확인] |
overlay 계약 테스트 | QA | 테스트 결과와 전체 모델 SHA-256을 기록합니다. |
| Git 반영 상태 | 미확인 |
준비된 Argo 상태 자료 없음 | 플랫폼 담당자 | rollback 개정본과 동기화 상태를 수집합니다. |
Pod와 InferenceService 준비 상태 |
미확인 |
준비된 Argo 상태 자료 없음 | 플랫폼 담당자 | 복구 워크로드의 준비 상태와 확인 시각을 수집합니다. |
복구 후 /v1/model과 정상 요청 |
미확인 |
runtime-images-v2.json의 target_verification.status=pending |
서빙 담당자 | 기존 운영 모델의 전체 식별값과 요청 결과를 수집합니다. |
5. 확인 결과와 후속 조치 기록¶
실행 결과는 확인한 환경에 맞게 기록합니다. 로컬 API를 확인하지 못했다면 그 이유와 다음 담당자를 함께 적습니다. 관측 결과마다 보고할 사실과 후속 조치를 구분합니다.
| 관측한 결과 | 보고서에 쓸 수 있는 사실 | 담당자와 다음 조치 |
|---|---|---|
기존 운영 모델의 로컬 deployment.json |
선택한 profile과 해시값이 로컬 마운트에 준비됨 |
서빙 담당자: Compose API가 같은 모델 정보를 내보내는지 확인 |
/v1/model과 정상, 비정상 응답 |
로컬 확인 범위에서 API 형식, 200, 422, 요청 ID 연결을 확인 | 검토 담당자와 서빙 담당자: 응답의 profile, version과 기대한 모델 해시값 대조 |
| Candidate B 배포 설정 테스트 | 승인된 Candidate B 경로와 롤백 경로가 설정 파일에 선언됨 | 플랫폼 담당자: GitOps 동기화 뒤 대상 모델 정보와 시간대 확인 |
| KServe 정적 또는 생성한 배포 설정 | 예상 모델 해시값, PVC subPath, 고정 이미지, ghcr-pull 설정 |
플랫폼 담당자: 대상 환경 GitOps 동기화와 상태 자료 수집 |
API_NOT_RUNNING, Docker 또는 kubectl 사용 불가 |
실제 API는 확인하지 못함 | QA: 막힌 조건과 target_pending 기록, 교육 환경 또는 플랫폼 담당자에게 환경 요청 |
예상과 다른 profile/모델 해시값 또는 정상 요청의 422 |
서빙 모델 불일치 또는 입력 형식 문제 가능성 | 서빙 담당자: 모델 파일, 설정, 요청 경로 조사. 모델 승인 결과는 바꾸지 않음 |
실습 결과 정리¶
기존 운영 모델의 로컬 API와 Candidate B 배포 설정은 서로 다른 증거 범위입니다. 결과를 정리할 때 기존 운영 모델의 로컬 확인 범위와 Candidate B 대상 환경의 확인 범위를 같은 상태값으로 섞지 않습니다.
결과를 쓰기 전에는 다음을 확인합니다.
- 로컬 API의 근거와 Candidate B 대상 배포 설정의 근거를 별도 행으로 남겼는가
- 응답을 직접 보지 않았다면
score·request_id·대상 환경 성공을 추정하지 않았는가 - Candidate B의
APPROVE와operational_deployment_scope를 서로 다른 필드로 남겼는가
기존 운영 모델의 로컬 근거와 Candidate B 대상 근거는 확인한 범위가 다릅니다.
| 단계 | 확인한 사실 | 확인한 범위 | 아직 모르는 것 |
|---|---|---|---|
| 기존 운영 모델의 로컬 API | 로컬 deployment.json, 모델 정보와 정상 200, 비정상 422 |
기존 운영 모델 API의 입출력 형식을 scope=local 범위에서 확인 |
Candidate B 로컬·대상 환경의 모델 정보와 운영 자료 |
| Candidate B 대상 배포 | Candidate B 배포 설정 검사와 예상 모델 해시값 | Candidate B 대상 환경 확인 상태는 target_pending; 배포 설정만 확인함 |
대상 환경 GitOps 동기화, 대상 Candidate B 모델 정보, 트래픽 시간대와 운영 관측값 |
“기존 운영 모델의 로컬 API가 200을 반환했으므로 Candidate B 대상 환경 배포가 끝났다”는 문장은 쓰면 안 됩니다. Candidate B 대상 환경은 같은 profile과 모델 해시값을 가진 대상 API 정보, 같은 시간대의 운영 자료를 실제로 확인하기 전까지 target_pending으로 기록합니다.
기존 운영 모델의 로컬 API는
scope=local범위에서 확인했다. Candidate B는 [배포 설정과 해시값]만 확인했으므로operational_deployment_scope를target_pending으로 기록한다. Candidate B의APPROVE는 유지한다. [Candidate B 로컬 또는 대상 모델 정보/같은 모델의 트래픽 시간대]는 [담당자]가 확인할 때까지 배포 상태를 결론 내리지 않는다.
운영 기록은 API 모델 정보와 같은 시간대에 대조해야 어떤 신호를 믿을 수 있는지 판단할 수 있습니다. 4장에서는 이 전제에서 트래픽 시나리오와 지표, 로그, 추적 기록이 무엇을 보여 주고 무엇을 아직 확정하지 않는지 확인합니다.