ml-azureml-adf-automation について
CI で Azure Machine Learning のコードアセットを登録し、登録済みバージョンを Azure Data Factory のワークフローへ渡すスキルです。SDK が返すバージョンを正とし、ネットワークや依存関係を実行時に検証します。
主な機能
- 01CI からの Azure ML コードアセット登録
- 02SDK が返すアセットバージョンの伝達
- 03ポインターブロブによるバージョン連携
- 04ADF WebActivity のネットワーク設定
- 05プライベートストレージアクセスの検証
- 06Azure ML SDK 依存関係の固定
活用シーン
- 01CI でのコードアセット登録の自動化
- 02正確なアセットバージョンの ADF ジョブへの伝達
- 03プライベートストレージのアクセス障害調査
- 04Azure ML と ADF の変更を実行時に検証
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ josiahsiegel/ claude-plugin-marketplace --skill ml-azureml-adf-automationインストール後、Claude Code で/ml-azureml-adf-automationを入力して読み込まれたか確認します。
詳細
Azure ML と ADF の自動化
概要
CI でコードアセットを登録し、Azure Data Factory を通じてトレーニング、スコアリング、登録、デプロイをオーケストレーションする Azure Machine Learning の自動化には、このスキルを使用します。基本的な不変条件は、実行時システムが、パイプラインが要求しようとしたバージョンではなく、実際に登録された Azure ML アセットの正確なバージョンを使用することです。Azure ML、ADF、ストレージのネットワーク、SDK の依存関係の動作は、静的な API ドキュメントと異なる場合があるため、すべての推奨事項を実行時の動作と照らし合わせて検証してください。
基本的な不変条件
- CI が Azure ML コードアセットの登録を担い、実際に SDK から返されたバージョンを公開します。
- ADF は実行時に AML コードバージョンを探索するのではなく、通常はストレージのポインターブロブなど、明示的な契約を通じてコードバージョンを受け取ります。
- SDK の結果が信頼できる情報源です。要求したバージョン、ビルド ID、ブランチ名、コミットから生成した文字列は、正式な情報ではありません。
- プライベートストレージには、適切な RBAC と、実行ランタイムからデータプレーンに到達できることの実証が両方必要です。
- ADF WebActivity のネットワークは、JSON として検証するだけでなく、想定する統合ランタイムを通じてテストする必要があります。
- Azure ML 自動化の依存関係の制約は、CI 環境で固定します。
- 実行時の証拠は、妥当と思われる ARM パス、ドキュメントの抜粋、テンプレートのコンパイル成功よりも優先されます。
Azure ML コードアセットの登録
自動化で登録済みバージョンを確実に取得する必要がある場合は、Azure ML コードアセットの登録に Python SDK を優先して使用してください。Azure CLI を使用するのは、対象環境の az ml 拡張機能が必要なコードコマンドに対応し、後続の自動化に十分な情報を返すことを確認した後にしてください。
from azure.ai.ml import MLClient
from azure.ai.ml.entities._assets._artifacts.code import Code
from azure.identity import AzureCliCredential
ml_client = MLClient(
AzureCliCredential(),
subscription_id,
resource_group,
workspace_name,
)
result = ml_client._code.create_or_update(
Code(name=code_name, version=requested_version, path=staged_code_path)
)
actual_version = result.version
print(actual_version)
requested_version == result.version とは限らないため、そう仮定しないでください。Azure ML コードアセットでは、ステージングしたディレクトリが以前のアセットと一致すると、コンテンツハッシュによってアップロードが重複排除され、既存のバージョンが返されることがあります。これはストレージの動作としては便利ですが、CI が SDK から返されたバージョンではなく、要求したビルド識別子を公開すると問題になります。
CI 出力変数のパターン
返されたバージョンをパイプラインの出力変数として公開し、後続のステップではその出力を参照します。
print(
"##vso[task.setvariable "
f"variable=trainingCodeVersion;isOutput=true]{result.version}"
)
推奨例:
$registeredVersion = '$(RegisterTrainingCode.trainingCodeVersion)'
避ける例:
$registeredVersion = '$(Build.BuildId)'
コードの内容が同じでもアセットのバージョンを一意にする必要がある場合は、コードディレクトリをステージングし、登録前に .aml-code-asset-version などの小さなマーカーファイルを書き込みます。これは重複排除を回避するためだけの方法として扱ってください。本来の契約は、あくまで SDK から返された result.version です。
ADF による Azure ML バージョンの解決
正確なパスが実行時に検証されていない限り、ADF から Azure ML ARM のコードコンテナーエンドポイントを使って AML コードバージョンを探索することは避けてください。一部の AML 管理エンドポイントは REST ドキュメントでは有効に見えても、ADF WebActivity の実行時に未対応の操作として失敗することがあります。RBAC の問題と決めつけず、別の証拠が得られるまではサービスの動作として扱ってください。
登録とオーケストレーション間の実行時契約には、CI が書き込むポインターブロブを使用します。
https://<storage-account>.blob.core.windows.net/ml-globals/code-assets/training-code/latest.json
ペイロードの例:
{
"assetName": "training-code",
"version": "<actual-sdk-returned-version>",
"workspaceName": "<workspace-name>",
"resourceGroup": "<resource-group>",
"subscriptionId": "<subscription-id>",
"buildId": "<build-or-run-id>",
"sourceBranch": "<branch>",
"sourceVersion": "<source-version>",
"registeredAtUtc": "<timestamp>"
}
ADF はこのブロブから version を読み取り、トレーニング、スコアリング、モデル登録、デプロイの各パイプラインにパラメーターとして渡します。ペイロードには来歴情報を含めてもかまいませんが、後続のジョブが依存するのは、意図的に契約の一部としたフィールドだけにしてください。
ポインターブロブの読み取りに使用する ADF WebActivity
マネージド ID 認証を使用して、Azure Storage からポインターブロブを読み取ります。
{
"name": "ReadLatestTrainingCodeVersion",
"type": "WebActivity",
"typeProperties": {
"method": "GET",
"url": {
"type": "Expression",
"value": "@concat('https://', pipeline().globalParameters.StorageAccountName, '.blob.core.windows.net/ml-globals/code-assets/training-code/latest.json')"
},
"headers": {
"x-ms-version": "2023-11-03",
"Accept": "application/json"
},
"authentication": {
"type": "MSI",
"resource": "https://storage.azure.com/"
},
"connectVia": {
"referenceName": "<managed-vnet-ir-name>",
"type": "IntegrationRuntimeReference"
}
}
}
重要な配置ルール:ADF WebActivity では、connectVia は typeProperties の中に配置します。アクティビティのルートに配置すると無視されることがあり、その場合、トラフィックがパブリックインターネット経由で送信され、defaultAction: Deny が設定されたストレージアカウントへのアクセスに失敗します。
一般的に必要なアクセス権は次のとおりです。
- ADF マネージド ID:ポインターコンテナーまたはアカウントスコープでの
Storage Blob Data Reader。 - CI サービス接続 ID:ポインターブロブを書き込むための
Storage Blob Data Contributor。 - CI サービス接続 ID:パイプラインでストレージファイアウォールルールを管理する場合の
Storage Account Contributor。
プライベートストレージとホステッド CI エージェント
プライベートエンドポイントがあり、defaultAction: Deny が設定されたストレージアカウントでは、Microsoft がホストする CI エージェントは通常、実行ごとに異なるパブリック IP アドレスから外部へ接続します。エージェントがストレージのデータプレーンに到達できない場合、RBAC が正しく設定されているだけでは不十分です。Azure ML SDK、ADF、IAM の問題を疑う前に、エージェントからストレージに到達できることを確認してください。
安全な CI パターン:
- エージェントのパブリック IP を解決します。
- その IP に対する一時的なストレージネットワークルールを追加します。
- 反映されるまで待ちます。
- ストレージのデータプレーンへのアクセスをスモークテストします。
- コードアセットを登録し、ポインターブロブを書き込みます。
always()クリーンアップステップで一時ルールを削除します。
$agentIp = (Invoke-RestMethod -Uri 'https://api.ipify.org' -TimeoutSec 20).Trim()
az storage account network-rule add `
--resource-group $rg `
--account-name $storageAccount `
--action Allow `
--ip-address $agentIp `
--only-show-errors
Start-Sleep -Seconds 30
az storage container list `
--account-name $storageAccount `
--auth-mode login `
--only-show-errors `
-o none
登録に失敗した場合でも、クリーンアップが実行されるようにしてください。Azure DevOps YAML では、condition: always() を指定したステップにネットワークルールの削除を記述します。
Python の依存関係のバージョン固定
一部の azure-ai-ml バージョンは、marshmallow 4.x では使用できない非公開の marshmallow シンボルをインポートします。ホステッドエージェントでは互換性のない推移的依存関係のバージョンがインストールされ、Azure ML API が呼び出される前に失敗することがあります。該当するバージョンを使用する場合は、SDK と推移的依存関係を組み合わせてバージョンを固定してください。
python -m pip install --upgrade `
"azure-ai-ml==1.24.0" `
"azure-identity==1.19.0" `
"marshmallow>=3.18,<4.0"
新しい SDK を使用する場合は、ローカルで成功したからといってバージョン固定を解除せず、CI で依存関係の動作を確認してください。
ADF の開発ワークフロー
未公開の Git ブランチの状態を読み取る ADF の実行モードと、公開済みのファクトリー定義を実行するモードを確認してください。デバッグ実行ではブランチの状態が使われる場合がありますが、スケジュール実行と本番実行では通常、最後に公開されたファクトリーが実行されます。手動トリガーの動作は、ファクトリーの設定と起動方法によって異なります。検証対象の変更を実際に実行できるモードを選択してください。
ランタイム検証の基準
構造上もっともらしいことではなく、ランタイムの証拠を基準にしてください。次の点を検証します。
- Azure ML の登録処理から
result.versionが返され、CI でその値がそのまま引き継がれていること。 - ポインターブロブに、Azure ML が実際に登録したバージョンが含まれていること。
- ADF が意図した統合ランタイムとマネージド ID を使用してブロブを読み取っていること。
- 実際のファイアウォール設定と CI エージェントの外部接続経路でストレージをテストしていること。
- 下流の ADF パラメーターが、実行時に使用される AML ジョブ定義に渡されていること。
- AML のトレーニングジョブまたはスコアリングジョブが、想定したコードアセットのバージョンで開始されること。
- CI と同じホステッドエージェントイメージで SDK のインポートが成功すること。
不十分な検証の例:エンドポイントの存在を示すドキュメント、JSON の解析、もっともらしい ARM URL、デプロイテンプレートの成功、ログで要求したバージョンが出力されているものの result.version を確認していない状態、またはランタイムの証拠がないレビューコメント。
運用チェックリスト
- Azure ML のコードアセットの登録を CI が担当していますか?
- CI は SDK が返す
result.versionを取得して公開していますか? - ADF は明示的なパラメーターまたはポインターブロブを通じて、正確なコードバージョンを受け取っていますか?
- ポインターペイロードでは、契約フィールドと任意の来歴メタデータが分けられていますか?
- プライベートネットワークが必要な場合、ADF WebActivities の
connectViaはtypeProperties内にありますか? - MSI によるブロブアクセスでは、認証リソース
https://storage.azure.com/を使用していますか? - ADF のマネージド ID に
Storage Blob Data Readerが付与されていますか? - CI サービス接続の ID に
Storage Blob Data Contributorが付与されていますか? - CI がストレージのファイアウォール規則を変更する場合、クリーンアップ時に追加、待機、スモークテスト、削除を行っていますか?
- 既知の Azure ML SDK の依存関係制約が固定されていますか?
- コンパイルやレビューだけでなく、実行時のインフラストラクチャ経路に対して検証を行いましたか?
簡潔なルール
- 対象環境での CLI の動作が検証済みでない限り、コードの登録には Azure ML Python SDK を使用してください。
- 要求したバージョンと登録されたバージョンが同じだと決めつけないでください。
- SDK の
result.versionを信頼できる情報源として扱ってください。 - 実行時のテストを行わずに、ADF から AML ARM
/codes/...の探索を行わないでください。 - ADF から読み取り可能な ML アセットのバージョン契約には、ブロブポインターを使用してください。
- ADF WebActivity の
connectViaはtypeProperties内に配置してください。 - ホステッド CI エージェントがプライベートストレージにアクセスするには、一時的なストレージのファイアウォールアクセスが必要だと想定してください。
- AML SDK のインポートに既知の制約がある場合は、推移的依存関係を固定してください。
- ML インフラストラクチャの変更には、実行時の検証を必須としてください。
参考資料
- Azure Machine Learning のドキュメント:https://learn.microsoft.com/azure/machine-learning/
- Azure Data Factory Web アクティビティのドキュメント:https://learn.microsoft.com/azure/data-factory/control-flow-web-activity
- Azure Storage のファイアウォールと仮想ネットワークに関するドキュメント:https://learn.microsoft.com/azure/storage/common/storage-network-security
- Azure Machine Learning Python SDK のドキュメント:https://learn.microsoft.com/python/api/overview/azure/ai-ml-readme