본문으로 건너뛰기
ML 플랫폼 실습 07. 로컬 실행 계약을 Azure ML로 옮기기

ML 플랫폼 실습 07. 로컬 실행 계약을 Azure ML로 옮기기

✎ 이 문서 수정하기 GitHub에서 수정

컴퓨터를 바꿔 실행한다고 데이터와 모델의 관계가 저절로 유지되지는 않는다. 로컬 경로, 인증, 실행 환경과 결과 저장 위치가 달라진다. 과정은 같은 Python 구현을 Azure ML의 독립된 작업으로 옮기는 데 초점을 둔다.

문서의 배포와 제출 명령은 사용자가 비용과 권한을 검토한 뒤 실행하는 선택 단계이다. 자료 작성 과정에서는 Azure 리소스 생성, 작업 제출과 엔드포인트 배포를 실행하지 않았다.

1. 로컬에서 구성만 만들기

uv run ml-labs azure pipeline --output .ml-labs/azure/pipeline.yml --compute azureml:cpu-cluster
az bicep build --file infra/azure/main.bicep --outfile .ml-labs/azure/main.json

첫 명령은 파이프라인과 아홉 개의 component YAML을 만든다. 각 프로젝트가 prepare → train/index → evaluate로 연결된다. 두 번째 명령은 Bicep을 ARM JSON으로 컴파일할 뿐 리소스를 생성하지 않는다.

GPU 없이 실제 YOLO로 바꿀 때는 별도 구성을 만든다. 기본 구성의 카드 모델은 색상 규칙 기준선이다.

uv run ml-labs azure pipeline --output .ml-labs/azure/yolo-pipeline.yml --compute azureml:cpu-cluster --cards-backend yolov8

YOLO 학습과 평가 단계는 environment-vision.yml을 사용한다. 사전학습 가중치 다운로드와 CPU 학습 시간도 고려해야 한다.

2. 필요한 리소스와 권한 확인하기

infra/azure/main.bicep은 Storage, Key Vault, ACR, Application Insights와 Azure ML workspace를 정의한다. deployCompute=true일 때만 최소 노드 0, 최대 노드 2의 CPU 클러스터를 추가한다. deployRagServices=true이면 AI Search와 Azure OpenAI 및 채팅 배포도 추가한다.

이 구성은 공개 네트워크를 사용하는 학습용 출발점이다. Private Endpoint, VNet, 조직 정책, 고객 관리 키와 운영용 권한 분리는 구현하지 않았다. 학습 구독의 전용 리소스 그룹에서만 검토한다.

배포 계정에는 리소스 생성 권한과 role assignment 생성 권한이 필요하다. workspace의 managed identity에는 Blob, Key Vault와 ACR 역할이 부여된다. 개발자가 데이터를 읽거나 작업을 제출할 권한은 별도로 확인해야 한다. 역할 전파에는 시간이 걸릴 수 있다.

AI Search에서는 문서를 쓰는 Search Index Data Contributor와 인덱스 정의를 관리하는 Search Service Contributor가 다른 역할이다. OpenAI 호출에는 Cognitive Services OpenAI User가 필요하다. developerPrincipalId는 사용자 object ID용이며 서비스 principal을 넣으려면 템플릿의 principal type도 바꿔야 한다.

3. 비용이 발생하는 선택 배포

아래 자리표시자를 실제 학습 구독과 지역으로 바꾸고 Azure Portal에서 현재 구독을 확인한다. 리소스 그룹을 먼저 별도로 준비해야 한다.

az login
az account show
az deployment group what-if --resource-group <lab-resource-group> --template-file infra/azure/main.bicep --parameters namePrefix=<unique-prefix> deployCompute=true

what-if도 Azure에 접근하는 관리 작업이지만 실제 리소스를 배포하지는 않는다. 검토가 끝난 뒤에만 다음 명령을 실행한다.

az deployment group create --resource-group <lab-resource-group> --template-file infra/azure/main.bicep --parameters namePrefix=<unique-prefix> deployCompute=true

OpenAI 모델의 지역 지원, 버전 수명과 quota는 별도로 확인한다. 템플릿의 예시 모델 버전이 현재 구독에서 사용 가능하다는 보장은 없다. RAG 리소스를 배포할 때는 chatModelName, chatModelVersion, developerPrincipalId도 확인해서 넘긴다.

Storage, ACR, Search 등의 비용은 학습 작업이 없을 때도 생길 수 있다. 클러스터의 최소 노드가 0이라는 것은 전체 환경의 비용이 0이라는 뜻이 아니다. 실행 전에 구독 예산과 알림을 설정한다.

4. 기존 workspace 연결하기

루트의 config.json을 다음 구조로 작성한다. 이 파일은 Git에서 제외된다.

{
  "subscription_id": "<subscription-id>",
  "resource_group": "<lab-resource-group>",
  "workspace_name": "<workspace-name>"
}

uv run --extra azure를 사용하면 SDK v2와 MLflow 연동 플러그인이 설치된다. CLI의 --execute는 리소스 구성을 만드는 옵션이 아니라 이미 렌더링한 작업을 기존 workspace에 제출하는 옵션이다.

uv run --extra azure ml-labs azure pipeline --output .ml-labs/azure/pipeline.yml --execute

이 단계부터 기존 compute가 실행되어 비용이 발생한다. 제출 함수는 workspace의 MLflow URI를 각 작업에 전달한다. 로컬 SQLite 기록이 Azure에 복사되는 것은 아니다.

업로드 때 .git은 제외되므로 렌더링한 component command에 코드 커밋이 포함된다. 렌더링 후 소스를 수정했다면 커밋하고 YAML을 다시 만든다. 작업에 기록된 커밋과 실제 업로드 코드가 달라지지 않게 해야 한다.

5. 작업 결과 확인하기

az ml job show --name <job-name> --resource-group <lab-resource-group> --workspace-name <workspace-name>
az ml job stream --name <job-name> --resource-group <lab-resource-group> --workspace-name <workspace-name>

Azure CLI의 ml extension이 없다면 az extension add --name ml로 설치한다. Studio에서 컴포넌트 입력과 출력, 환경 빌드 로그, run의 MLflow 모델과 평가 보고서를 확인한다.

Completed만 보지 말고 다음을 확인한다.

확인 대상봐야 할 근거
데이터 전달학습 입력이 prepare의 data 출력인지
독립 실행다른 작업의 로컬 경로 대신 선언된 output을 쓰는지
평가학습 후보와 같은 데이터 지문인지, 통과 보고서가 있는지
추적workspace tracking URI, run ID와 모델 아티팩트가 연결되는지
실패평가 게이트 거절이 작업 실패로 드러나는지

현재 파이프라인은 평가까지 연결한다. 자동 승인, Registry 승격과 운영 엔드포인트 트래픽 변경은 포함하지 않는다. 책의 KFP 학습을 Azure ML 제출로 대체하는 것도 아니다.

6. 로컬 검증 모델을 원격 엔드포인트로 내보내기

먼저 로컬에서 평가를 통과한 후보와 보고서를 사용한다. 클라우드 job에서 받은 candidate를 쓰려면 해당 tracking URI에 접근하는 인증과 모델 아티팩트 권한이 필요하다.

uv run ml-labs azure endpoint --candidate .ml-labs/runs/movies/candidate.json --report .ml-labs/reports/movies.json --output .ml-labs/azure/movie-endpoint

명령은 모델 파일과 deploy_endpoint.py를 내보낼 뿐 원격 엔드포인트를 생성하지 않는다. 같은 출력 폴더의 기존 모델은 덮어쓰지 않는다.

생성된 Python을 읽고 workspace 설정, VM SKU와 endpoint 이름을 확인한 뒤 명시적으로 실행한다.

uv run --extra azure python .ml-labs/azure/movie-endpoint/deploy_endpoint.py --endpoint-name <unique-endpoint-name>

이 스크립트는 등록 모델을 배포하는 것과 별개로, MLflow 아티팩트를 모델 자산으로 올리고 managed endpoint와 blue deployment를 만든다. 모델의 MLflow 환경으로 의존성을 복원하는 no-code inference 경로이다. 비용이 발생하며 instance count는 1이다.

영화 요청을 만들고 호출한다.

$request = @{ input_data = @{ columns = @("user_id"); data = @(@("u000")) } }
$request | ConvertTo-Json -Depth 8 | Set-Content .ml-labs/movie-request.json
az ml online-endpoint invoke --name <unique-endpoint-name> --request-file .ml-labs/movie-request.json --resource-group <lab-resource-group> --workspace-name <workspace-name>

카드 모델은 base64 이미지 요청을 사용하고, 로컬 RAG PyFunc는 query 열을 사용한다. PyFunc를 원격 배포해도 TF-IDF 인용 응답이 OpenAI 생성으로 바뀌지는 않는다. OpenAI 연결은 별도 RAG provider 경로이다.

7. 정리하기

작업 취소와 엔드포인트 삭제는 서로 다르다.

az ml job cancel --name <running-job-name> --resource-group <lab-resource-group> --workspace-name <workspace-name>
az ml online-endpoint delete --name <unique-endpoint-name> --resource-group <lab-resource-group> --workspace-name <workspace-name> --yes

취소할 작업이 없으면 첫 명령은 필요 없다. endpoint 삭제 후 deployment VM이 제거되었는지 확인한다. Search, OpenAI 배포, ACR과 Storage는 남으므로 사용하지 않으면 학습용으로 생성한 각 리소스를 Portal에서 확인하고 삭제한다. 기존 업무용 workspace가 들어 있는 리소스 그룹 전체를 삭제하지 않는다.

Key Vault는 purge protection 때문에 삭제 후에도 즉시 이름을 재사용할 수 없다. 보존 기간과 구독별 정책도 정리 계획에 포함한다.

참고: SDK v2 component pipeline, MLflow endpoint, Search RBAC.

이전: RAG와 LLMOps / 다음: 책과의 대응

실행 코드는 실습 저장소에서 내려받는다. 원본 가이드

마지막 수정 일자