マネージド ID を使ってオンライン エンドポイントから Azure リソースにアクセスする

適用対象:Azure CLI ML 拡張機能 v2 (現行)Python SDK azure-ai-ml v2 (現行)

オンライン エンドポイントと、システム割り当てマネージド ID またはユーザー割り当てマネージド ID のいずれかを使用して、スコアリング スクリプトから Azure リソースにアクセスする方法を説明します。

マネージド エンドポイントと Kubernetes エンドポイントの両方を使うと、Azure Machine Learning で、コンピューティング リソースのプロビジョニングと機械学習モデルのデプロイの負担を管理できます。 通常、モデルは、Azure Container Registry や推論用の BLOB ストレージなどの Azure リソースにアクセスする必要がありますが、マネージド ID を使用すると、コード内で資格情報を管理することなく、それらのリソースにアクセスできます。 マネージド ID の詳細を確認してください。

このガイドでは、マネージド ID、ストレージ アカウント、オンライン エンドポイントがないことを前提としています。 これらのコンポーネントが既にある場合は、「マネージド ID にアクセス許可を付与する」セクションに進んでください。

前提条件

  • Azure Machine Learning を使用するには、Azure サブスクリプションが必要です。 Azure サブスクリプションをお持ちでない場合は、開始する前に無料アカウントを作成してください。 無料版または有料版の Azure Machine Learning を今すぐお試しください。

  • Azure CLI と ML (v2) 拡張機能をインストールして構成します。 詳細については、2.0 CLI のインストール、設定、使用に関するページを参照してください。

  • Azure リソース グループ。ユーザー (または使用するサービス プリンシパル) に "ユーザー アクセス管理者" と "共同作成者" のアクセスが必要です。 前の記事に従って ML 拡張機能を構成した場合は、そのようなリソース グループが存在します。

  • Azure Machine Learning ワークスペース。 前の記事に従って ML 拡張機能を構成した場合は、既にワークスペースが存在します。

  • スコアリングとデプロイの準備が整ったトレーニング済みの機械学習モデル。 サンプルに従っている場合は、モデルが提供されます。

  • まだ Azure CLI の既定値を設定していない場合は、既定の設定を保存する必要があります。 サブスクリプション、ワークスペース、およびリソース グループの値を複数回渡さないようにするには、次のコードを実行します。

    az account set --subscription <subscription ID>
    az configure --defaults gitworkspace=<Azure Machine Learning workspace name> group=<resource group>
    
  • サンプルに従って処理するには、サンプル リポジトリを複製し、ディレクトリを cli に変更します。

    git clone https://github.com/Azure/azureml-examples --depth 1
    cd azureml-examples/cli
    

制限事項

  • エンドポイントの ID は不変です。 エンドポイントの作成時に、システム割り当て ID (既定) またはユーザー割り当て ID に関連付けることができます。 エンドポイントが作成された後は、ID を変更できません。
  • ARC と BLOB ストレージがプライベートとして (仮想ネットワークの背後に) 構成されている場合、お使いのワークスペースがパブリックかプライベートかに関係なく、Kubernetes エンドポイントからのアクセスはプライベート リンク経由となる必要があります。 プライベート リンク設定の詳細については、ワークスペース vnet をセキュリティで保護する方法に関する記事を参照してください。

デプロイ用の変数を構成する

デプロイメントで使用するために作成するエンドポイント、ワークスペース、ワークスペースの場所について、それぞれの変数名を構成します。

次のコードは、これらの値をエンドポイントの環境変数としてエクスポートするものです。

export WORKSPACE="<WORKSPACE_NAME>"
export LOCATION="<WORKSPACE_LOCATION>"
export ENDPOINT_NAME="<ENDPOINT_NAME>"

次に、BLOB ストレージ アカウント、BLOB コンテナー、ファイルに付けたい名前を指定します。 ここでこれらの変数名を定義しておいて、次のセクションの az storage account create コマンドや az storage container create コマンドから参照することになります。

次のコードは、それらの値を環境変数としてエクスポートするものです。

export STORAGE_ACCOUNT_NAME="<BLOB_STORAGE_TO_ACCESS>"
export STORAGE_CONTAINER_NAME="<CONTAINER_TO_ACCESS>"
export FILE_NAME="<FILE_TO_ACCESS>"

これらの変数をエクスポートした後、テキスト ファイルをローカルに作成します。 エンドポイントがデプロイされると、スコアリング スクリプトは、エンドポイントの作成時に生成されるシステム割り当てマネージド ID を使用して、このテキスト ファイルにアクセスします。

デプロイ構成を定義する

CLI を使用してオンライン エンドポイントをデプロイするには、YAML ファイルで構成を定義する必要があります。 YAML スキーマの詳細については、オンライン エンドポイント YAML リファレンスに関するドキュメントを参照してください。

次の例の YAML ファイルは、オンライン エンドポイントを作成するために使用されます。

次の YAML の例は、endpoints/online/managed/managed-identities/1-sai-create-endpoint にあります。 このファイルによって、以下が行われます。

  • エンドポイントを参照する際に使用する名前 (my-sai-endpoint) を定義します。
  • エンドポイントへのアクセスに使用する承認の種類 (auth-mode: key) を指定します。
$schema: https://azuremlschemas.azureedge.net/latest/managedOnlineEndpoint.schema.json
name: my-sai-endpoint
auth_mode: key

この YAML の例 (2-sai-deployment.yml) によって、次のことが行われます。

  • 作成するエンドポイントの種類が online であることを指定します。
  • エンドポイントに、blue というデプロイが関連付けられるように指定します
  • デプロイするモデル、使用する環境とスコアリング スクリプトなど、デプロイの詳細を構成します。
$schema: https://azuremlschemas.azureedge.net/latest/managedOnlineDeployment.schema.json
name: blue
model:
  path: ../../model-1/model/
code_configuration:
  code: ../../model-1/onlinescoring/
  scoring_script: score_managedidentity.py
environment:
  conda_file: ../../model-1/environment/conda-managedidentity.yaml
  image: mcr.microsoft.com/azureml/openmpi4.1.0-ubuntu20.04:latest
instance_type: Standard_DS3_v2
instance_count: 1
environment_variables:
  STORAGE_ACCOUNT_NAME: "storage_place_holder"
  STORAGE_CONTAINER_NAME: "container_place_holder"
  FILE_NAME: "file_place_holder"

マネージド ID を作成する

Azure リソースにアクセスするには、オンライン エンドポイントに対するシステム割り当てマネージド ID またはユーザー割り当てマネージド ID を作成します。

オンラインエンドポイントを作成すると、システム割り当てマネージド ID が自動的に生成されるため、個別に作成する必要はありません。

Storage アカウントとコンテナーを作成する

この例では、BLOB ストレージ アカウントと BLOB コンテナーを作成し、先ほど作成したテキスト ファイルを BLOB コンテナーにアップロードします。 このストレージ アカウントと BLOB コンテナーに、オンライン エンドポイントとマネージド ID にアクセスする権限を付与します。

まず、ストレージ アカウントを作成します。

az storage account create --name $STORAGE_ACCOUNT_NAME --location $LOCATION

次に、ストレージ アカウントに BLOB コンテナーを作成します。

az storage container create --account-name $STORAGE_ACCOUNT_NAME --name $STORAGE_CONTAINER_NAME

その後、テキスト ファイルを BLOB コンテナーにアップロードします。

az storage blob upload --account-name $STORAGE_ACCOUNT_NAME --container-name $STORAGE_CONTAINER_NAME --name $FILE_NAME --file endpoints/online/managed/managed-identities/hello.txt

オンライン エンドポイントの作成

次のコードでは、デプロイを指定せずにオンライン エンドポイントを作成します。

警告

エンドポイントの ID は不変です。 エンドポイントの作成時に、システム割り当て ID (既定) またはユーザー割り当て ID に関連付けることができます。 エンドポイントが作成された後は、ID を変更できません。

オンライン エンドポイントを作成すると、既定ではそのエンドポイントに対してシステム割り当てマネージド ID が作成されます。

az ml online-endpoint create --name $ENDPOINT_NAME -f endpoints/online/managed/managed-identities/1-sai-create-endpoint.yml

エンドポイントの状態を次のようにして確認します。

az ml online-endpoint show --name $ENDPOINT_NAME

問題が発生した場合は、「オンライン エンドポイントのデプロイとスコアリングのトラブルシューティング」を参照してください。

マネージド ID にアクセス許可を付与する

重要

オンライン エンドポイントでは、コンテナー レジストリーに対する Azure Container Registry のプルアクセス許可である AcrPull アクセス許可と、ワークスペースの既定データストアに対するストレージ BLOB データ閲覧者アクセス許可が必要です。

オンライン エンドポイント アクセス許可でシステム割り当てマネージド ID を使用してストレージにアクセスできるようにしたり、ユーザー割り当てマネージド ID に対するアクセス許可を付与して、前のセクションで作成されたストレージ アカウントにアクセスできるようにすることができます。

エンドポイントに対して作成されたシステム割り当てマネージド ID を取得します。

system_identity=`az ml online-endpoint show --name $ENDPOINT_NAME --query "identity.principal_id" -o tsv`

ここから、システム割り当てマネージド ID に、ご使用のストレージへのアクセス許可を与えることができます。

az role assignment create --assignee-object-id $system_identity --assignee-principal-type ServicePrincipal --role "Storage Blob Data Reader" --scope $storage_id

Azure リソースにアクセスするためのスコアリング スクリプト

ID トークンを使用して Azure リソースにアクセスする方法を理解するには、次のスクリプトを参照してください。このシナリオでは、前のセクションで作成したストレージ アカウントです。

import os
import logging
import json
import numpy
import joblib
import requests
from azure.identity import ManagedIdentityCredential
from azure.storage.blob import BlobClient


def access_blob_storage_sdk():
    credential = ManagedIdentityCredential(client_id=os.getenv("UAI_CLIENT_ID"))
    storage_account = os.getenv("STORAGE_ACCOUNT_NAME")
    storage_container = os.getenv("STORAGE_CONTAINER_NAME")
    file_name = os.getenv("FILE_NAME")

    blob_client = BlobClient(
        account_url=f"https://{storage_account}.blob.core.windows.net/",
        container_name=storage_container,
        blob_name=file_name,
        credential=credential,
    )
    blob_contents = blob_client.download_blob().content_as_text()
    logging.info(f"Blob contains: {blob_contents}")


def get_token_rest():
    """
    Retrieve an access token via REST.
    """

    access_token = None
    msi_endpoint = os.environ.get("MSI_ENDPOINT", None)
    msi_secret = os.environ.get("MSI_SECRET", None)

    # If UAI_CLIENT_ID is provided then assume that endpoint was created with user assigned identity,
    # # otherwise system assigned identity deployment.
    client_id = os.environ.get("UAI_CLIENT_ID", None)
    if client_id is not None:
        token_url = (
            msi_endpoint + f"?clientid={client_id}&resource=https://storage.azure.com/"
        )
    else:
        token_url = msi_endpoint + f"?resource=https://storage.azure.com/"

    logging.info("Trying to get identity token...")
    headers = {"secret": msi_secret, "Metadata": "true"}
    resp = requests.get(token_url, headers=headers)
    resp.raise_for_status()
    access_token = resp.json()["access_token"]
    logging.info("Retrieved token successfully.")
    return access_token


def access_blob_storage_rest():
    """
    Access a blob via REST.
    """

    logging.info("Trying to access blob storage...")
    storage_account = os.environ.get("STORAGE_ACCOUNT_NAME")
    storage_container = os.environ.get("STORAGE_CONTAINER_NAME")
    file_name = os.environ.get("FILE_NAME")
    logging.info(
        f"storage_account: {storage_account}, container: {storage_container}, filename: {file_name}"
    )
    token = get_token_rest()

    blob_url = f"https://{storage_account}.blob.core.windows.net/{storage_container}/{file_name}?api-version=2019-04-01"
    auth_headers = {
        "Authorization": f"Bearer {token}",
        "x-ms-blob-type": "BlockBlob",
        "x-ms-version": "2019-02-02",
    }
    resp = requests.get(blob_url, headers=auth_headers)
    resp.raise_for_status()
    logging.info(f"Blob contains: {resp.text}")


def init():
    global model
    # AZUREML_MODEL_DIR is an environment variable created during deployment.
    # It is the path to the model folder (./azureml-models/$MODEL_NAME/$VERSION)
    # For multiple models, it points to the folder containing all deployed models (./azureml-models)
    # Please provide your model's folder name if there is one
    model_path = os.path.join(
        os.getenv("AZUREML_MODEL_DIR"), "model/sklearn_regression_model.pkl"
    )
    # deserialize the model file back into a sklearn model
    model = joblib.load(model_path)
    logging.info("Model loaded")

    # Access Azure resource (Blob storage) using system assigned identity token
    access_blob_storage_rest()
    access_blob_storage_sdk()

    logging.info("Init complete")


# note you can pass in multiple rows for scoring
def run(raw_data):
    logging.info("Request received")
    data = json.loads(raw_data)["data"]
    data = numpy.array(data)
    result = model.predict(data)
    logging.info("Request processed")
    return result.tolist()

自分の構成を使用してデプロイを作成する

オンライン エンドポイントに関連付けられているデプロイを作成します。 オンライン エンドポイントへのデプロイの詳細について学習します

警告

基になる環境とイメージが初めて構築されるものであるかどうかに応じて、このデプロイには 8 分から 14 分程度かかる場合があります。 その後、同じ環境を使用したデプロイは、それよりも短時間で完了します。

az ml online-deployment create --endpoint-name $ENDPOINT_NAME --all-traffic --name blue --file endpoints/online/managed/managed-identities/2-sai-deployment.yml --set environment_variables.STORAGE_ACCOUNT_NAME=$STORAGE_ACCOUNT_NAME environment_variables.STORAGE_CONTAINER_NAME=$STORAGE_CONTAINER_NAME environment_variables.FILE_NAME=$FILE_NAME

Note

--name 引数の値によって、YAML ファイル内の name キーがオーバーライドされる可能性があります。

デプロイの状態を確認します。

az ml online-deployment show --endpoint-name $ENDPOINT_NAME --name blue

特定のデータのみが返されるように上記のクエリを調整する方法については、Azure CLI コマンドの出力の照会に関するページを参照してください。

Note

スコアリング スクリプトの init メソッドは、システム割り当てマネージド ID トークンを使用して、ストレージ アカウントからファイルを読み取ります。

init メソッドの出力をチェックするには、次のコードでデプロイ ログを確認します。

# Check deployment logs to confirm blob storage file contents read operation success.
az ml online-deployment get-logs --endpoint-name $ENDPOINT_NAME --name blue

デプロイが完了すると、モデル、環境、エンドポイントが Azure Machine Learning ワークスペースに登録されます。

エンドポイントをテストする

オンライン エンドポイントがデプロイされたら、要求でその操作をテストして確認します。 推論の詳細は、モデルによって異なります。 このガイドでは、JSON クエリ パラメーターは次のようになります。

{"data": [
    [1,2,3,4,5,6,7,8,9,10], 
    [10,9,8,7,6,5,4,3,2,1]
]}

エンドポイントを呼び出すには、次を実行します。

az ml online-endpoint invoke --name $ENDPOINT_NAME --request-file endpoints/online/model-1/sample-request.json

エンドポイントとストレージ アカウントを削除する

デプロイしたオンライン エンドポイントとストレージを今後使用する予定がない場合は、コストを節約するためにそれらを削除してください。 エンドポイントを削除すると、そこに関連付けられているデプロイもすべて削除されます。

az ml online-endpoint delete --name $ENDPOINT_NAME --yes
az storage account delete --name $STORAGE_ACCOUNT_NAME --yes