DevOps & MLOps

2023 오픈소스 컨트리뷰션 DevOps & MLOps (5) MLOps편 (Azure 클라우드에 머신러닝 모델 카나리 배포 적용하기)

jamie-lee 2023. 8. 16. 00:32

MLOps 구현하기 1: Azureml examples 튜토리얼 따라하기 (모델 배포하기)


들어가기 전에

이전 편에서는 모델을 클라우드 환경에서 훈련시키고 해당 모델을 훈련한 결과를 클라우드 대시보드에서 확인하는 과정을 수행했다. 이제는 이 모델을 실제로 배포하는 과정을 수행한다. 이를 위해 Azure 머신러닝 Python SDK v2 라는 것을 사용할 것이다.

이전 편에서 clone한 동일한 저장소에서 tutorials/get-started-notebooks/deploy-model.ipynb 노트북을 실행한다.

워크 스페이스 핸들 생성하기

이전 편에서 모델을 훈련시키기 위해서 ml_client를 생성하였다. 이번에도 모델을 클라우드 환경에서 지지고 볶고 하기 위해서 ml_client가 필요하다.

from azure.ai.ml import MLClient
from azure.identity import DefaultAzureCredential

# authenticate
credential = DefaultAzureCredential()

# Get a handle to the workspace (이전 주피터 파일에서 복붙하자)
ml_client = MLClient(
    credential=credential,
    subscription_id="구독 아이디",  # Azure Portal -> Subscription 항목에서 확인 가능
    resource_group_name="리소스 그룹 이름",
    workspace_name="워크스페이스 그룹 이름",
)

모델 등록하기

이전에 train-model.ipynb 튜토리얼을 완료했다면 “모델 훈련시키기 > 커맨드 기능을 이용해 훈련 잡을 구성하고 생성하기” 항목에서 훈련 모델을 이미 등록시켰으므로, 이 과정을 건너뛸 수 있다.

그 과정을 거치지 않았다면 아래 코드를 통해 모델 등록이 필요하다. 배포하기 전에 모델을 등록하는 것이 권장되는 모범 사례라고 한다. 나는 이전 편에서 등록 절차를 거쳤으므로 이 단계를 건너 뛰었다.

# Import the necessary libraries
from azure.ai.ml.entities import Model
from azure.ai.ml.constants import AssetTypes

# Provide the model details, including the
# path to the model files, if you've stored them locally.
mlflow_model = Model(
    path="./deploy/credit_defaults_model/",  # 업로드할 파일의 경로
    type=AssetTypes.MLFLOW_MODEL,   
    name="credit_defaults_model",
    description="MLflow Model created from local files.",
)

# Register the model
ml_client.models.create_or_update(mlflow_model)

위 코드를 실행하면 SDK가 자동으로 파일을 업로드하고 모델을 등록한다.

[!NOTE] Azure Machine Learning Python SDK란?
SDK는 작은 도구 상자에 비유할 수 있다. 집을 지을 때 망치, 너트, 볼트, 드릴 등 다양한 도구가 필요하듯이 SDK는 특정 플랫폼이나 언어를 위한 도구들의 모음이다. 안드로이드 앱을 개발하고자 한다면 안드로이드 SDK는 안드로이드 앱 개발에 필요한 모든 도구와 라이브러리, 가이드라인을 제공한다. SDK는 개발자로 하여금 쉽고 빠르게 개발할 수 있게 도와준다.
Azure Machine Learning Python SDK v2는 Azure 클라우드 환경에서 파이썬 언어를 이용해 기계 학습 작업을 손쉽게 수행할 수 있게 해주는 강력한 도구를 제공한다.

모델 등록 확인하기

Azure 머신러닝 스튜디오 > Models에서 등록한 모델과 그의 버전 정보를 확인할 수 있다. 이렇게 버전 정보를 자동으로 매핑해줌으로써 모델 관리가 더욱 쉬워진다.

Pasted image 20230815150927.png

코드를 통해 모델의 가장 최신 버전 넘버를 출력해볼 수도 있다. 나의 경우는 1이 출력되는 것을 확인할 수 있다.

registered_model_name = "credit_defaults_model"

# Let's pick the latest version of the model
latest_model_version = max(
    [int(m.version) for m in ml_client.models.list(name=registered_model_name)]
)

print(latest_model_version)  # 버전 정보를 출력

❗ERROR: ClientAuthenticationError

위 코드를 실행하면서 아래와 같은 에러를 맞닥뜨렸다.

DefaultAzureCredential failed to retrieve a token from the included credentials.
Attempted credentials:
	EnvironmentCredential: EnvironmentCredential authentication unavailable. Environment variables are not fully configured.
Visit [https://aka.ms/azsdk/python/identity/environmentcredential/troubleshoot](https://aka.ms/azsdk/python/identity/environmentcredential/troubleshoot) to troubleshoot this issue.
	ManagedIdentityCredential: ManagedIdentityCredential authentication unavailable, no response from the IMDS endpoint.
	SharedTokenCacheCredential: SharedTokenCacheCredential authentication unavailable. No accounts were found in the cache.
	AzureCliCredential: Azure CLI not found on path
	AzurePowerShellCredential: PowerShell is not installed
	AzureDeveloperCliCredential: Azure Developer CLI could not be found. Please visit [https://aka.ms/azure-dev](https://aka.ms/azure-dev) for installation instructions and then,once installed, authenticate to your Azure account using 'azd auth login'.
To mitigate this issue, please refer to the troubleshooting guidelines here at [https://aka.ms/azsdk/python/identity/defaultazurecredential/troubleshoot.](https://aka.ms/azsdk/python/identity/defaultazurecredential/troubleshoot.)

---------------------------------------------------------------------------
ClientAuthenticationError                 Traceback (most recent call last)
Cell In[3], line 5
      1 registered_model_name = "credit_defaults_model"
      3 # Let's pick the latest version of the model
      4 latest_model_version = max(
----> 5     [int(m.version) for m in ml_client.models.list(name=registered_model_name)]
      6 )
      8 print(latest_model_version)

...

ClientAuthenticationError: DefaultAzureCredential failed to retrieve a token from the included credentials.
Attempted credentials:
	EnvironmentCredential: EnvironmentCredential authentication unavailable. Environment variables are not fully configured.
Visit [https://aka.ms/azsdk/python/identity/environmentcredential/troubleshoot](https://aka.ms/azsdk/python/identity/environmentcredential/troubleshoot) to troubleshoot this issue.
	ManagedIdentityCredential: ManagedIdentityCredential authentication unavailable, no response from the IMDS endpoint.
	SharedTokenCacheCredential: SharedTokenCacheCredential authentication unavailable. No accounts were found in the cache.
	AzureCliCredential: Azure CLI not found on path
	AzurePowerShellCredential: PowerShell is not installed
	AzureDeveloperCliCredential: Azure Developer CLI could not be found. Please visit [https://aka.ms/azure-dev](https://aka.ms/azure-dev) for installation instructions and then,once installed, authenticate to your Azure account using 'azd auth login'.
To mitigate this issue, please refer to the troubleshooting guidelines here at [https://aka.ms/azsdk/python/identity/defaultazurecredential/troubleshoot.](https://aka.ms/azsdk/python/identity/defaultazurecredential/troubleshoot.)

ml_client를 호출하는 과정에서 발생한 인증 관련 오류로 보인다. “워크 스페이스 핸들 생성하기” 항목에서 클라이언트 초기화를 진행하면서 credential 값을 넘겨주었는데 이 부분에서 문제가 있는지 토큰 정보를 가져올 수 없다는 문구이다. (워크 스페이스 핸들을 생성하면서 에러가 나지 않았던 이유는 ml_client를 최초로 호출할 때 lazy하게 실제 워크스페이스 연결이 이루어지기 때문이다.)

이전 편에서 train-model.ipynb 파일에서도 동일한 과정을 밟았지만 이런 에러는 보지 못했다. 다른 점은 디바이스를 바꿔서 진행했다는 점이다. (이전 편은 데스크탑, 본편은 랩탑으로 진행 중이다)

인증 정보가 제대로 세팅되고 있지 않다는 의심이 들었다. 그래서 다음과 같은 절차를 밟아나갔다.

  1. azure CLI가 설치되어 있는지 확인했다.

→ 아뿔싸, 설치가 안 되어 있었다. 그래서 설치해주었다! 하지만 여전히 해당 파이썬 코드에서 동일한 에러가 발생한다.

  1. az login 명령어를 입력하여 인증이 제대로 되는지 확인한다.

→ 아래와 같은 에러 발생하며 로그인 실패

The command failed with an unexpected error. Here is the traceback:
0. The ID token is not yet valid. Make sure your computer's time and time zone are both correct. Current epoch = 1692078285.

컴퓨터의 시간을 체크하라니 갑자기 뜬금없이 이게 무슨 소리일까?

https://github.com/Azure/azure-cli/issues 에 방문하여 관련 이슈를 찾아보았다. 그리고 다음 글에서 해결책을 찾았다. ☞ Can’t do az login: RuntimeError: 0. The ID token is not yet valid. · Issue #20388 · Azure/azure-cli (github.com)

결론부터 말하자면 이 에러를 해결하기 위해서 아래와 같이 시도하면 된다. (특히 WSL2 환경 유저)

  1. sudo hwclock -s 입력하여, 리눅스 시스템에서 하드웨어 시계와 시스템 시계 간 동기화를 수행한다.
  2. az login

로그인 성공이다. 그리고 앞서 에러가 났던 파이썬 코드를 재실행하자 인증 오류 없이 ml_client를 잘 불러오는 것을 확인했다.

🤔 시스템 시계와 하드웨어 시계가 서로 일치하지 않아 생긴 에러인데 도대체 원인이 무엇일까? 이슈 글에서 관련 내용을 확인할 수 있었다.

Pasted image 20230815155903.png
Pasted image 20230815160200.png

요약하자면 동일한 문제가 있었을 때 시간 어긋남이 최대 1초 미만이었다는 내용과 WSL을 이용해 요청을 보냈을 때 문제가 있었고, 절전 모드에서 시계가 꺼지는 알려진 WSL 이슈가 있다는 이야기다.

아니, 완전 나랑 똑같은 상황이다. WSL2 우분투 배포판을 사용하는 중이고 마침 절전 모드에서 랩탑을 깨우고 해당 과정을 진행했다. WSL2에 이런 이슈가 있는지 몰랐다. 알아둬야겠다! (이후 또 동일한 에러가 발생했고, 역시 절전 모드에서 깨우고 나서였다. 생각보다 빈번히 일어나는 에러인 듯 하다.)

엔드포인트와 디플로이먼트

모델 등록도 마쳤겠다, 이제 배포하여 다른 사람들이 사용할 수 있게 해보자. 이를 위해 Azure 머신러닝은 엔드포인트를 생성하고 그것들에 디플로이먼트를트 추가할 수 있다.

엔드포인트란 HTTPS 패스로, 클라이언트가 훈련된 모델에 요청(입력 데이터)을 보낼 수 있는 인터페이스를 제공한다. 클라이언트는 모델에 입력 값을 넣고 돌린 추론(scoring) 결과를 받을 수 있다.

엔드포인트는 다음과 같은 것을 제공해준다.

  1. key 혹은 token 베이스 인증
  2. TSL(SSL) 터미네이션
  3. 안정적인 scoring URI (endpoint-name.region.inference.ml.azure.com)

디플로이먼트란 실제로 추론 결과를 제공해 줄 모델을 호스팅하는데 필요한 리소스 집합을 말한다.

하나의 엔드포인트는 여러 개의 디플로이먼트를 포함할 수 있다. 엔드포인트와 디플로이먼트는 Azure 포털에서 나타나는 독립적인 Azure Resource Manager 리소스이다.

Azure 머신러닝은 클라이언트 데이터에 대해 실시간 추론을 위한 온라인 엔드포인트를 구현할 수 있게 해주며, 일정 기간 동안 대량의 데이터에 대한 추론을 위해 batch 엔드포인트도 구현할 수 있게 한다. 이 튜토리얼에서는 관리형 온라인 엔드포인트(managed online endpoint)를 구현한다. 확장 가능하고, Azure의 CPU와 GPU 머신과 함께 작동하므로, 기본 배포 인프라를 설정하고 관리하는 어려움이 줄어든다.

온라인 엔드포인트 생성하기

앞서 등록한 모델에 대한 온라인 엔드포인트를 생성하는 코드이다. 엔드포인트 이름은 Azure 리전 안에서 유일해야 한다. 그를 위해 UUID를 사용할 것이다.

더 많은 endpoint 네이밍 룰이 궁금하면 다음 링크를 참고한다. ☞ Manage resources and quotas - Azure Machine Learning | Microsoft Learn

import uuid

# Create a unique name for the endpoint
online_endpoint_name = "credit-endpoint-" + str(uuid.uuid4())[:8]

그 다음으로는 엔드포인트를 정의내릴 차례다. ManagedOnlineEndpoint라는 클래스를 이용한다.

from azure.ai.ml.entities import ManagedOnlineEndpoint

# define an online endpoint
endpoint = ManagedOnlineEndpoint(
    name=online_endpoint_name,
    description="this is an online endpoint",
    auth_mode="key",  # key 기반 인증을 뜻한다. `aml_token`은 Azure 머신러닝 토큰 인증이다. 
    tags={ 
        "training_dataset": "credit_defaults",
    },
)

추가한 주석에 덧붙여 auth_mode에 관해 말하자면, key 인증은 만료하지 않지만 aml_token은 만료 기간이 있다.

tags를 이용해 태그를 지정할 수도 있다.

다음 코드를 실행하면 이전에 생성한 ml_client 객체를 이용해 워크페이스에 엔드포인트를 생성하고 확인 응답을 받는다. 이 부분은 시간이 좀 걸린다.

# create the online endpoint
# expect the endpoint to take approximately 2 minutes.

endpoint = ml_client.online_endpoints.begin_create_or_update(endpoint).result()

엔드포인트가 잘 생성되었는지 다음 코드를 이용해 확인해보자.

endpoint = ml_client.online_endpoints.get(name=online_endpoint_name) 

print(
    f'Endpoint "{endpoint.name}" with provisioning state "{endpoint.provisioning_state}" is retrieved'
)

"Endpoint “credit-endpoint-9c6ca031” with provisioning state “Succeeded” is retrieved"와 같은 문구가 출력되며 나의 엔드포인트 이름과 상태 정보를 잘 알려주고 있다.

온라인 디플로이먼트 이해하기

디플로이먼트에는 다음과 같은 주요 키워드가 있다.

  • name: 디플로이먼트의 이름
  • endpoint_name: 디플로이먼트를 포함하는 엔드포인트 이름
  • model: 디플로이먼트를 위해 사용할 모델. 이는 워크스페이스에 이미 존재하는 모델일 수도 있고, 인라인으로 특정하는 모델일 수도 있다.
  • environment: 디플로이먼트를 위해, 혹은 모델을 실행하기 위해 사용할 환경. 이는 이미 워크스페이스에 존재하는 환경일 수도 있고, 인라인으로 특정하는 환경일수도 있다. 환경은 Conda 디펜던시를 가지고 있는 도커 이미지일수도 있고 도커 파일일수도 있다.
    • code_configuration: 소스 코드와 scoring script를 위한 구성이다.
    • path: 모델 scoring을 위한 소스 코드 디렉토리 경로
  • scoring_script: 소스 코드 디렉토리의 scoring 파일을 위한 상대 경로. 인풋 요청을 실행한다. scoring 스크립트의 예시를 참고 하고 싶으면 Understand the scoring script 이 링크에서 확인 가능.
  • instance_type: 디플로이먼트를 위해 사용할 VM 크기. 지원하는 크기 리스트를 알고 싶으면 여기를 참고한다. ☞  Managed online endpoints SKU list
  • instance_count: 디플로이먼트를 위해 사용할 인스턴스의 수 (1개 이상으로 지정)

Azure 머신러닝은 MLflow를 이용해 생성되고 로깅되는 모델에 대해 노코드 배포를 지원한다. 즉, 모델 배포를 위해 채점 스크립트(scoring script)나 environment를 제공할 필요가 없다는 뜻이다. MLflow 모델을 훈련시킬때 자동으로 생성되기 때문이다. 하지만 커스텀 모델을 사용하는 경우는 그에 맞는 scoring_script와 environment를 지정해야 한다. 커스텀 모델을 배포하면서도 MLflow 모델을 사용하여 동일한 기능을 달성하려면 Using MLflow models for no-code deployment를 참고하라고 한다.

모델을 엔드포인트에 배포하기

들어오는 트래픽의 100%를 다루는 단일 디플로이먼트를 "blue"라고 이름 짓고 생성한다. ManagedOnlineDeployment라는 클래스를 이용할 것이다. (배포할 모델이 MLflow 모델이면 환경과 채점 스크립트를 지정해줄 필요가 없다.)

from azure.ai.ml.entities import ManagedOnlineDeployment

# Choose the latest version of our registered model for deployment
model = ml_client.models.get(name=registered_model_name, version=latest_model_version)

# define an online deployment
# if you run into an out of quota error, change the instance_type to a comparable VM that is available.
# Learn more on https://azure.microsoft.com/en-us/pricing/details/machine-learning/.
blue_deployment = ManagedOnlineDeployment(
    name="blue",  # Blue / Green 배포 
    endpoint_name=online_endpoint_name,
    model=model,
    instance_type="Standard_DS2_v2", # 이름에 주의. Korea region 사용 가능 VM 다름.  https://learn.microsoft.com/en-us/azure/machine-learning/reference-managed-online-endpoints-vm-sku-list?view=azureml-api-2
    instance_count=1,
)

[!NOTE]
이때 quota 에러가 발생할 수 있는데, 가용 자원이 부족한 경우에 발생하는 에러이다. 사용하지 않는 리소스를 삭제하거나, 인스턴스 타입을 바꾸거나, 할당량을 늘려야 할 수 있다. 이 단계에서는 겪지 않았지만 아래에서 quota 이슈를 만나 해결했다.

ml_client를 이용해서 워크스페이스에 디플로이먼트를 생성하자. 다음 코드를 실행하면 디플로이먼트를 생성하고 확인 응답을 받는다. 이 과정은 시간이 조금 걸린다. (약 8~10분)

# create the online deployment
blue_deployment = ml_client.online_deployments.begin_create_or_update(
    blue_deployment
).result()

# 블루에게 100% 모든 요청 받게 한다
# expect the deployment to take approximately 8 to 10 minutes.
endpoint.traffic = {"blue": 100}
ml_client.online_endpoints.begin_create_or_update(endpoint).result()

여기서 아래와 같은 경고 메시지가 떴는데 그냥 진행해도 특별히 문제는 없다.

Instance type Standard_DS2_v2 may be too small for compute resources. Minimum recommended compute SKU is Standard_DS3_v2 for general purpose endpoints. Learn more about SKUs here: [https://learn.microsoft.com/en-us/azure/machine-learning/referencemanaged-online-endpoints-vm-sku-list](https://learn.microsoft.com/en-us/azure/machine-learning/referencemanaged-online-endpoints-vm-sku-list)
Check: endpoint credit-endpoint-9c6ca031 exists

아래 내용으로 시작하는 응답 결과를 받으면 성공이다.

ManagedOnlineEndpoint({'public_network_access': 'Enabled', 'provisioning_state': 'Succeeded', 'scoring_uri': 'https://credit-endpoint-9c6ca031.koreacentral.inference.ml.azure.com/score', 'openapi_uri': 'https://credit-endpoint-9c6ca031.koreacentral.inference.ml.azure.com/swagger.json', 'name': 'credit-endpoint-9c6ca031', 'description': 'this is an online endpoint', 'tags': {'training_dataset': 'credit_defaults'}, 'properties': .....

...

엔드포인트 상태 확인하기

이제 모델이 에러 없이 잘 배포 되었는지 엔드포인트 상태를 확인할 수 있다.

# return an object that contains metadata for the endpoint
endpoint = ml_client.online_endpoints.get(name=online_endpoint_name)

# print a selection of the endpoint's metadata
print(
    f"Name: {endpoint.name}\nStatus: {endpoint.provisioning_state}\nDescription: {endpoint.description}"
)

# 출력 결과
Name: credit-endpoint-9c6ca031
Status: Succeeded
Description: this is an online endpoint

트래픽 상세 정보와 채점 URI도 출력해본다.

# existing traffic details
print(endpoint.traffic)

# Get the scoring URI
print(endpoint.scoring_uri)

# 출력 결과
{'blue': 100}
[https://credit-endpoint-9c6ca031.koreacentral.inference.ml.azure.com/score](https://credit-endpoint-9c6ca031.koreacentral.inference.ml.azure.com/score)

여기서 scoring_uri로 바로 접속하면 아래와 같은 에러가 뜬다.

key_auth_bad_header_forbidden
Please check this guide to understand why this error code might have been returned 
https://docs.microsoft.com/en-us/azure/machine-learning/how-to-troubleshoot-online-endpoints#http-status-codes

아무나 내 머신러닝 코드를 마구 돌리게 했다가 비용 폭탄을 맞을 지도 모른다. 하여 인증 키가 필요하다. 이와 관련해서는 아래 포스트맨 테스트에서 다시 설명한다.

샘플 데이터로 엔드포인트 테스트하기

이제 모델이 엔드포인트에 배포되었으므로, 모델의 추론 결과를 얻어보자. 요청 파일 샘플을 생성하자.

import os

# Create a directory to store the sample request file.
deploy_dir = "./deploy"
os.makedirs(deploy_dir, exist_ok=True)

"./deploy"라는 디렉토리를 만들었다. 아래 코드는 IPython magic을 이용해 방금 만든 디렉토리에 파일을 생성한다.

%%writefile {deploy_dir}/sample-request.json
{
  "input_data": {
    "columns": [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22],
    "index": [0, 1],
    "data": [
            [20000,2,2,1,24,2,2,-1,-1,-2,-2,3913,3102,689,0,0,0,0,689,0,0,0,0],
            [10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, 9, 8]
            ]
                }
}

ml_client를 이용해 엔드포인트 핸들링할 수 있다. 엔드포인트는 다음과 같은 파라미터를 사용해 invoke 명령을 통해서 호출할 수 있다.

  • endpoint_name: 엔드포인트 이름
  • request_file: 요청 데이터 파일. 위에서 만든 “sample-request.json” 파
  • deployment_name: 테스트할 엔드포인트가 속해 있는 디플로이먼트 이름. “blue” 배포를 이용할 것이다.
# test the blue deployment with the sample data
ml_client.online_endpoints.invoke(
    endpoint_name=online_endpoint_name,
    deployment_name="blue",
    request_file="./deploy/sample-request.json",
)

Azure 머신러닝 스튜디오 > Endpoints > Test에서도 테스트 할 수 있었다.

Pasted image 20230815171959.png

인풋 데이터를 넣고 테스트했더니 "1, 0"이라는 값을 얻은 것을 볼 수 있다. 참고로 신용카드 유저 파산 확률을 예측하는 머신러닝 모델이었다.

디플로이먼트 log 얻기

성공적으로 잘 호출됐는지 로그를 확인해본다. 이 작업은 시간이 좀 걸린다.

logs = ml_client.online_deployments.get_logs(
    name="blue", endpoint_name=online_endpoint_name, lines=50
)
print(logs)

50줄의 로그가 찍힌다. /score라는 path로 요청 로그가 찍힌 것을 볼 수 있었다.

# 출력 결과

2023-08-15 08:23:16,703 I [687] azmlinfsrv - POST /score?verbose=true 200 8.760ms 6
2023-08-15 08:23:16,703 I [687] gunicorn.access - 127.0.0.1 - - [15/Aug/2023:08:23:16 +0000] "POST /score?verbose=true HTTP/1.0" 200 6 "-" "-"

포스트맨을 이용해 테스트하기

이번에는 포스트맨을 이용해 테스트한다. 여기서 주의할 점은 위에서 언급했듯이 Authorization 헤더를 설정해주어야 한다는 점이다.

POST 메소드로 위에서 알아낸 scoring_uri를 path로 입력하고, Authorization 타입은 Bearer Token으로 지정한다. (Azure 측에서 Key라고 지칭하길래 API Key로 선택했다가 조금 헤맸다!)

그리고 Azure 스튜디오 > Endpoints > consume > Authentication에서 Primary Key 혹은 Secondary Key 둘 중 아무 값으로 토큰 값을 지정한다. 그리고 Body 부분은 raw > JSON 타입으로 지정하여 위에서 생성한 샘플 요청 JSON을 그대로 넣어줬다. 그리고 요청을 보내면…

Pasted image 20230815173337.png

Azure 포털에서 테스트 결과와 마찬가지로 "1, 0"이라는 결과를 얻었다.

Pasted image 20230815174224.png

대시보드의 Logs 탭에서 로그 확인도 가능하며 Postman 요청 로그가 잘 찍혀있다. 성공!

두 번째 디플로이먼트 생성하기

이번에는 green이라고 하는 두 번째 디플로이먼트를 생성해보자. 실제로 여러개의 디플로이먼트를 생성하고 그들의 퍼포먼스를 비교할 수 있다. 이러한 디플로이먼트들은 똑같은 모델의 각각 다른 버전을 사용할 수도 있고, 완전히 다른 모델을 사용할 수도 있고, 혹은 더 강력한 컴퓨트 인스턴스를 사용하게 만들 수도 있다.

우선 이전과 동일한 인스턴스 타입으로 디플로이먼트를 생성해본다.

# picking the model to deploy. Here we use the latest version of our registered model
model = ml_client.models.get(name=registered_model_name, version=latest_model_version)

# define an online deployment using a more powerful instance type
# if you run into an out of quota error, change the instance_type to a comparable VM that is available.
# Learn more on https://azure.microsoft.com/en-us/pricing/details/machine-learning/.
green_deployment = ManagedOnlineDeployment(
    name="green",  # Blue / Green 배포
    endpoint_name=online_endpoint_name,
    model=model,
    instance_type="Standard_DS2_v2", # 이름에 주의. Korea region 사용 가능 VM 다름.  https://learn.microsoft.com/en-us/azure/machine-learning/reference-managed-online-endpoints-vm-sku-list?view=azureml-api-2
    instance_count=1,
)

# create the online deployment
# expect the deployment to take approximately 8 to 10 minutes
green_deployment = ml_client.online_deployments.begin_create_or_update(
    green_deployment
).result()

❗ERROR: HttpResponseError

우려하던 Quota 에러를 맞닥뜨렸다.

HttpResponseError                         Traceback (most recent call last)
Cell In[22], line 17
      7 green_deployment = ManagedOnlineDeployment(
      8     name="green",  # Blue / Green 배포
      9     endpoint_name=online_endpoint_name,
   (...)
     12     instance_count=1,
     13 )
     15 # create the online deployment
     16 # expect the deployment to take approximately 8 to 10 minutes
---> 17 green_deployment = ml_client.online_deployments.begin_create_or_update(
     18     green_deployment
     19 ).result()

...

HttpResponseError: (BadRequest) The request is invalid.
Code: BadRequest
Message: The request is invalid.
Exception Details:	(InferencingClientCreateDeploymentFailed) InferencingClient HttpRequest error, error detail: {"errors":{"VmSize":["Not enough quota available for Standard_DS2_v2 in SubscriptionId <내 구독 ID>. Current usage/limit: 4/6. Additional needed: 4 Please see troubleshooting guide, available here: [https://aka.ms/oe-tsg#error-outofquota"]},"type":"https://tools.ietf.org/html/rfc7231#section-6.5.1","title":"One](https://aka.ms/oe-tsg#error-outofquota%22]},%22type%22:%22https://tools.ietf.org/html/rfc7231#section-6.5.1%22,%22title%22:%22One) or more validation errors occurred.","status":400,"traceId":"00-ace515331221833c2c9634e11b1c9d83-467c86a4c5791551-01"}

...

"Not enough quota available for Standard_DS2_v2 in SubscriptionId <내 구독 ID>. Current usage/limit: 4/6. Additional needed: 4"라는 문구가 눈에 들어온다. 4개가 더 필요한데 현재 2개밖에 사용할 수 없다고 한다.

리소스 현황을 한 눈에 살펴보고 싶어서 Azure 포털에서 확인하기로 했다.

Azure 포털 > 구독 > 사용량 및 할당량 > Machine Learning을 선택하고 지역 필터를 Korea Central로 선택하면 나의 사용량을 확인할 수 있었다.

Pasted image 20230815181228.png

Standard_DS2_v2 인스턴스의 할당량이 모자르다는 걸 알 수 있다. 하지만 무료 구독이라 할당량을 늘릴 수가 없다. 다른 인스턴스를 사용할 수밖에 없었다.

Managed online endpoints VM SKU list - Azure Machine Learning | Microsoft Learn에서 Standard_DS2_v2를 대신할 “Standard_D2a_v4” 인스턴스를 선택하여 다시 디플로이먼트를 생성했다. 성공적으로 배포가 올라갔다.

더 많은 트래픽 수용을 위해 디플로이먼트 확장하기

ml_client를 이용해 green 배포에 대한 핸들링을 할 수 있다. instance_count를 증가시키거나 감소시킴으로써 스케일링 한다.

다음 코드에서는 VM 인스턴스 개수를 직접 정의할 수 있다. 하지만 온라인 엔드포인트를 오토스케일링하는 것도 가능하다. 오토스케일링을 이용하면 앱의 로드를 다루기 위해 필요한 리소스의 양만 사용할 수 있다. 오토스케일링 관련 내용은 여기 참고 ☞ autoscale online endpoints

# update definition of the deployment
green_deployment.instance_count = 2  # 기본 1개만 구성 원하는 크기로 숫자 조절 가능.

# update the deployment
# expect the deployment to take approximately 8 to 10 minutes
ml_client.online_deployments.begin_create_or_update(green_deployment).result()

헌데 이 코드는 실행시키지 않았다.

그린 배포가 올라간 “Standard_D2a_v4” 인스턴스 타입은 1개의 인스턴스만 올라가 있지만 이미 가용량이 4/4로 가득 찬 상태라 Quota 이슈가 날게 뻔하기 때문…! 구독을 업그레이드 할 순 없기 때문에, 우선은 저렇게 인스턴스 개수를 조절할 수 있다는 걸 알아두는 정도로 넘어간다!

디플로이먼트에 트래픽 할당 비율 업데이트하기

나에게 “블루”, "그린"이라는 두 개의 디플로이먼트가 생겼다! 기존 배포 방식은 “blue” 디플로이먼트에 100% 트래픽을 할당하고 있었지만, 이제 두 배포에 트래픽 비율을 다르게 지정해볼 것이다. 이런 배포 방식을 Canary 배포라고 부른다.

[!NOTE] Canary 배포 방식이란?
신규 버전의 소프트웨어를 일부 사용자에게 제한적으로 배포하고, 문제가 없을 경우 점차 확대해나가는 배포 전략을 일컫는다. 광산에서 카나리아 새를 사용하던 전통에서 유래했다. 광산 안의 유독가스를 감지하면 카나리아 새가 먼저 반응하게 된다고 한다. 마찬가지로 새로운 버전의 문제점을 일찍 감지할 수 있는 방법이다. 즉, 새로운 소프트웨어에 문제가 있을 경우 즉시 롤백하여 다른 사용자에게 영향을 주지 않는다.

  1. 점진적 배포
  2. 리스크 관리
  3. 피드백 수집

라는 주요 특징을 가진다. 비율은 95대 5가 일반적이라고 한다.

green 배포에 5%의 트래픽을 부여한다.

endpoint.traffic = {"blue": 80, "green": 20}  # Canary 배포 
ml_client.online_endpoints.begin_create_or_update(endpoint).result()

성공하면 endpoint 상태 및 uri를 포함하는 결과를 반환한다.

Azure 머신러닝 스튜디오에서도 확인할 수 있다. Endpoints 대시보드에서 아래와 같이 Deployment traffic allocation이 보인다.

Pasted image 20230815232357.png

트래픽 배분을 테스트하기 위해 엔드포인트에 10번의 요청을 보내보았다.

# You can invoke the endpoint several times
for i in range(10):
    ml_client.online_endpoints.invoke(
        endpoint_name=online_endpoint_name,
        request_file="./deploy/sample-request.json",
    )
    

green 배포의 로그를 확인하여 요청이 제대로 들어갔는지 확인할 수 있다.

logs = ml_client.online_deployments.get_logs(
    name="green", endpoint_name=online_endpoint_name, lines=50
)
print(logs)

Azure 대시보드에서 blue, green 배포의 Log를 확인할 수 있다.

10번의 요청 중 1개의 요청만 green 배포에 들어왔음을 확인할 수 있었다. 어디까지나 확률이므로 항상 정확히 95:5의 비율로 요청이 배분됨을 보장할 순 없다. 하지만 많은 요청을 보내면 대략적으로 그 비율에 가까워질 가능성이 높다고 한다.

Pasted image 20230815233515.png

Pasted image 20230815233439.png

Azure Monitor로 metrics 확인하기

요청 횟수, 요청 latency, 네트워크 바이트, 리소스 사용량 등 온라인 엔드포인트와 디플로이먼트와 관련된 다양한 수치를 Azure Monitor에서 확인할 수 있다.

Azure 머신러닝 스튜디오 > Endpoints > Details > View metrics 를 클릭한다. 먼저 온라인 엔드포인트의 분당 요청 횟수를 확인해보았다.

Pasted image 20230815235104.png

다음은 블루 디플로이먼트의 CPU 평균 사용량도 한 번 보자.

Pasted image 20230815234947.png

새로운 디플로이먼트에 모든 트래픽 보내기

green 배포 버전의 소프트웨어가 아무 이상이 없었다치고, 이번에는 green 배포에 100% 트래픽을 할당해줬다.

endpoint.traffic = {"blue": 0, "green": 100} 
ml_client.begin_create_or_update(endpoint).result()

디플로이먼트 서머리에서 아래처럼 green 배포가 100%로 바뀐 것을 확인할 수 있다.

Pasted image 20230815235408.png

그러면 이제 블루 배포는 필요 없으므로 삭제한다.

이전 디플로이먼트 삭제하기

아래 코드를 실행하면 처음 생성했던 blue 디플로이먼트를 삭제할 수 있다. 이 작업은 꽤 시간이 소요될 수 있다.

ml_client.online_deployments.begin_delete(
    name="blue", endpoint_name=online_endpoint_name
).result()

그러면 아래처럼 그린 배포만 남아 있는 걸 확인할 수 있다! 이로서 머신러닝 모델을 블루/그린 카나리 배포하는 과정까지 성공적으로 마쳤다.

Pasted image 20230816000238.png

리소스 삭제하기

생성한 엔드포인트와 디플로이먼트를 튜토리얼 이후에도 사용할 계획이 없다면 삭제해줘야 한다. 아래 코드를 실행하여 삭제해주었다. 이 작업은 시간이 꽤 오래 걸릴 수 있다. (약 20분)

ml_client.online_endpoints.begin_delete(name=online_endpoint_name).result()

혹은 Azure 포털 > 구독 > 리소스에서 아래처럼 배포와 엔드포인트를 확인하고 직접 삭제할 수도 있다. 시간이 꽤 걸린다.

성질 급한 한국인 답게 여러 번 삭제 버튼을 눌렀고 이미 처리 중인 요청이라는 에러 알림을 받았다. 😊 삭제를 진행하고 차분히 기다리길 추천한다.

Pasted image 20230815235930.png

성공했다는 알림이 뜨고 말끔하게 지워진 것을 확인했다.

마치며

이전 편에서 본편까지는 머신러닝 프로젝트를 위한 단계(데이터 전처리 - 모델 학습 - 배포)를 클라우드 환경에서 실행하고 클라우드에서 대시보드로 확인하는 방법을 다뤘다. 이제 다음 편에서는 이런 각 단계를 컴포넌트로 만들어 파이프라인을 만들어보는 과정을 다룰 것이다~!