【警告】AOAIモデルをデプロイしただけで◯万円?PTUなモデルデプロイ有無を一括確認できるようにしてみた話
はじめに
先日、Azure OpenAI Service(以下、AOAI)でモデルをデプロイしただけで高額な課金が発生するという、ヒヤリとする体験をしました。同様の事例が他の方にも起こっていることを知り、これは対策が必要だと感じました。(せめて横並び確認の自動化くらいは・・・)
参考にした記事はこちらです:
この記事では、同じ問題に直面した背景と、その解決策としてテナント内のすべてのAOAIリソースを一括でチェックし、Provisioned-managedなデプロイメントを特定するシェルスクリプトを作成した経緯と使い方を紹介します。
背景
高額課金の発生
上記の記事と同様に、AOAIでモデルをデプロイしただけで、まだAPIを使用していないのに数時間後に数万円の課金が発生しました。ただ、今回は予算アラートを設定していたため、すぐに気づいて対処できましたが、設定していなければもっと大きな金額になっていたかもしれません。
PTUの料金について
PTUの料金などのAOAIの料金表については以下の公式ドキュメントをご参照ください。
例えば、以下の画像のように、カナダリージョンにて、50PTUでGPT-4oのPTU-managedをデプロイした場合、1日あたり約35万円(=50PTU×24h×289.031円/(PTU・h))となり、割と大きな額の課金となります。
原因の分析
原因は、モデルのデプロイ時に『Provisioned-Managed』という設定がデフォルトで選択されていたことです。この設定では、Provisioned Throughput Unit(PTU)が設定され、時間単位の課金が発生します。何も知らずにデプロイすると高額な課金が発生します。
加えて、一部のモデルでは、「グローバル標準」の設定ができず、デフォルトで「Provisioned-Managed」が指定されることがあります。これに気づかずデプロイすると、思わぬコストがかかる可能性があります。
以前まではPTU契約はMS営業を通して契約する必要がありましたが、8月頃に営業を通さず契約できる形態ができ、Standardデプロイと同様な感覚でPTU相当のデプロイができるようになっています。(検証などいろいろと便利な使い道はあるので、このアップデートは個人的には嬉しいアップデートでした。)
詳しくは以下にあります。
こういった想定外の重課金事象はクラウドあるあるな事象ですが、従量課金だけがクラウドの課金モデルではないことを心に留めておく必要があるなーと感じました。
対策の必要性
この問題は、AOAIを利用する多くの方々にとって見落としがちなポイントです。特に、大規模なAzure環境を管理している場合、どのリソースで「Provisioned-Managed」が設定されているかを一つ一つ確認するのは現実的ではありません。
そこで、自動化された方法でProvisioned-managedなデプロイメントを一括確認できるスクリプトを作成しました。
スクリプトの概要
このシェルスクリプトは、以下の機能を持ちます:
- 全サブスクリプションの取得:Azureアカウントに紐づくすべてのサブスクリプションIDを取得します。
-
OpenAIリソースの検出:各サブスクリプション内で、
kind
が"OpenAI"
のCognitive Servicesアカウントを特定します。 -
デプロイメントのチェック:各リソース内のデプロイメントを取得し、
sku.name
が"Provisioned-managed"
のものを特定します。 - 結果の出力:Provisioned-managedなデプロイメントと、それ以外のデプロイメントをそれぞれ別のファイルに出力します。ファイル名にはタイムスタンプが含まれます。
GitHubリポジトリ
このスクリプトはGitHubで公開しています。ご自由にダウンロード・ご利用ください。
スクリプトの使い方
前提条件
-
Azure CLIのインストール
Azure CLIがインストールされている必要があります。
# macOSの場合 brew update brew install azure-cli # Ubuntuの場合 curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
-
Azureへのログイン
az login
-
必要な拡張機能のインストール
az extension add --name cognitiveservices
-
jq
のインストール# macOSの場合 brew install jq # Ubuntuの場合 sudo apt-get install jq
-
適切なAzureロールの割り当て
スクリプトを正常に実行するためには、対象のサブスクリプションおよびリソースに対する読み取りアクセス権限が必要です。
- サブスクリプションレベルでの「閲覧者(Reader)」ロールが割り当てられていることを確認してください。
- これにより、スクリプトはサブスクリプション内のリソース情報を取得できます。
スクリプトの実行
-
スクリプトを保存
以下の内容をファイル(例:
check_provisioned_managed_deployments.sh
)に保存します。
check_provisioned_managed_deployments.sh
#!/bin/bash
# 現在の日時を取得してフォーマットする(例:YYYYMMDD_HHMMSS)
timestamp=$(date '+%Y%m%d_%H%M%S')
# 出力ファイル名(タイムスタンプを含む)
output_file_provisioned_managed="provisioned_managed_deployments_${timestamp}.txt"
output_file_other_deployments="other_deployments_${timestamp}.txt"
# 出力ファイルを初期化
> "$output_file_provisioned_managed"
> "$output_file_other_deployments"
# 全サブスクリプションを取得
subscriptions=$(az account list --query "[].id" -o tsv)
for subscription in $subscriptions; do
# サブスクリプションを設定
az account set --subscription "$subscription"
echo "Checking subscription: $subscription"
# OpenAIサービスリソースのリストを取得
resources=$(az cognitiveservices account list --subscription "$subscription" --query "[?kind=='OpenAI'].{Name:name, ResourceGroup:resourceGroup}" -o tsv)
if [ -z "$resources" ]; then
echo "No OpenAI resources found in subscription: $subscription"
continue
fi
any_provisioned_managed=false
any_other_deployments=false
resources_with_provisioned_managed_deployments=""
resources_with_other_deployments=""
# 各リソースについて確認
while read -r resourceName resourceGroup; do
echo "Checking resource: $resourceName in resource group: $resourceGroup"
# デプロイメントのリストを取得
deployments=$(az cognitiveservices account deployment list --resource-group "$resourceGroup" --name "$resourceName" --subscription "$subscription" -o json)
if [ -z "$deployments" ] || [ "$deployments" == "[]" ]; then
echo "No deployments found in resource: $resourceName"
continue
fi
# 各デプロイメントを確認
for row in $(echo "${deployments}" | jq -r '.[] | @base64'); do
_jq() {
echo "${row}" | base64 --decode | jq -r "${1}"
}
deploymentName=$(_jq '.name')
skuName=$(_jq '.sku.name')
modelName=$(_jq '.properties.model.name')
if [ "$skuName" == "ProvisionedManaged" ]; then
any_provisioned_managed=true
resources_with_provisioned_managed_deployments+="$resourceName (Resource Group: $resourceGroup, DeploymentName: $deploymentName, SKU Name: $skuName, ModelName: $modelName)\n"
else
any_other_deployments=true
resources_with_other_deployments+="$resourceName (Resource Group: $resourceGroup, DeploymentName: $deploymentName, SKU Name: $skuName, ModelName: $modelName)\n"
fi
done
done <<< "$resources"
# 'Provisioned-managed' なデプロイメントの出力
if [ "$any_provisioned_managed" = true ]; then
echo "Some deployments in subscription $subscription have SKU Name set to 'Provisioned-managed'."
echo "-------------------------------------" >> "$output_file_provisioned_managed"
echo "Subscription: $subscription" >> "$output_file_provisioned_managed"
echo "Resources with Provisioned-managed deployments and their models:" >> "$output_file_provisioned_managed"
echo -e "$resources_with_provisioned_managed_deployments" >> "$output_file_provisioned_managed"
echo "-------------------------------------" >> "$output_file_provisioned_managed"
else
echo "No deployments with SKU Name 'Provisioned-managed' found in subscription $subscription."
fi
# その他のデプロイメントの出力
if [ "$any_other_deployments" = true ]; then
echo "Some deployments in subscription $subscription are not 'Provisioned-managed'."
echo "-------------------------------------" >> "$output_file_other_deployments"
echo "Subscription: $subscription" >> "$output_file_other_deployments"
echo "Resources with other deployments and their models:" >> "$output_file_other_deployments"
echo -e "$resources_with_other_deployments" >> "$output_file_other_deployments"
echo "-------------------------------------" >> "$output_file_other_deployments"
else
echo "All deployments in subscription $subscription are 'Provisioned-managed' or no other deployments found."
fi
done
echo "Subscriptions with deployments have been saved to $output_file_provisioned_managed and $output_file_other_deployments"
-
実行権限を付与
chmod +x check_provisioned_managed_deployments.sh
-
スクリプトを実行
./check_provisioned_managed_deployments.sh
出力結果の例
スクリプトの実行後、タイムスタンプ付きの2つのファイルが生成されます。
provisioned_managed_deployments_YYYYMMDD_HHMMSS.txt
1. -------------------------------------
Subscription: XXXXXXXX-〇〇〇〇-〇〇〇〇-〇〇〇〇-XXXXXXXX〇〇〇〇
Resources with Provisioned-managed deployments and their models:
openai-resource-1 (Resource Group: openai-rg, DeploymentName: deployment-1, SKU Name: ProvisionedManaged, ModelName: gpt-4o)
-------------------------------------
other_deployments_YYYYMMDD_HHMMSS.txt
2. -------------------------------------
Subscription: XXXXXXXX-〇〇〇〇-〇〇〇〇-〇〇〇〇-XXXXXXXX〇〇〇〇
Resources with other deployments and their models:
openai-resource-2 (Resource Group: openai-rg, DeploymentName: deployment-2, SKU Name: Standard, ModelName: gpt-4o-mini)
-------------------------------------
アウトプットファイルの説明
-
provisioned_managed_deployments_YYYYMMDD_HHMMSS.txt
-
sku.name
がProvisionedManaged
のデプロイメントが含まれます。 - 高額な課金が発生する可能性のあるデプロイメントを特定できます。
-
-
other_deployments_YYYYMMDD_HHMMSS.txt
-
sku.name
がProvisionedManaged
ではないデプロイメント(例:Standard
)が含まれます。 - 他のデプロイメントの状況を把握するのに役立ちます。
-
注意事項
適切な権限の確認
- 必要なAzureロール
- スクリプトを正常に実行するためには、対象のサブスクリプションおよびリソースに対する読み取りアクセス権限が必要です。
- サブスクリプションレベルでの「閲覧者(Reader)」ロールが割り当てられていることを確認してください。
- 権限が不足している場合
- スクリプト実行時にエラーが発生する可能性があります。
- 組織のAzure管理者やサブスクリプションの所有者に問い合わせて、必要な権限を付与してもらってください。
その他の考慮事項
- Azure CLIと拡張機能のバージョン
- 最新版のAzure CLIとCognitive Services拡張機能を使用してください。
- jqのインストール
- JSONデータを処理するために必要です。
- セキュリティポリシー
- 最小権限の原則に従い、必要最低限の権限のみを付与することが推奨されます。
- 定期的な権限の見直し
- アカウントに過剰な権限が与えられていないか、定期的に確認してください。
対策と効果
このスクリプトを使用することで、以下のような効果が期待できます:
- 高額課金の防止:意図せず「Provisioned-Managed」が設定されているデプロイメントを早期に発見し、不要なリソースを削除または設定変更できます。
- リソース管理の効率化:複数のサブスクリプションやリソースグループにまたがる環境でも、一括で状況を把握できます。
- 定期的な監視:タイムスタンプ付きのファイルにより、過去の状況との比較やトラッキングが容易になります。
まとめ
AOAIを利用する際には、モデルのデプロイ設定に十分注意が必要です。特に、「Provisioned-Managed」の設定は高額な課金を招く可能性があるため、定期的な確認が推奨されます。
今後、MicrosoftがUIや設定プロセスの改善を進め、ユーザーが誤って高額な課金を発生させないような仕組みや誤って設定してしまった場合の通知の仕組みなどが導入されることも一案かもしれません。(筆者自身は、こういった誤認識による課金はクラウドあるあるなので、一定程度はユーザ側が注意すべき派ではありますが・・・)
そういった改善が進むことで、より安心してAOAIを利用できるようになるでしょう。
同じ問題に直面した経験から、このスクリプトを作成しました。ぜひ活用していただき、コストの最適化とリスクの低減に役立ててください。
また、社内注意喚起やコストアラートの設定、IaCによるデプロイのテンプレート化などでの対策も並行して実施するのも推奨します。
合わせて読みたい
AOAIにおいてオプトアウトができてるかをテナント単位で一括確認するスクリプトも作りました。
以下では、3大クラウドの日本リージョンでのGPT/Claude/Geminiモデルの提供事情もまとめています。
参考
公式ドキュメント:PTUについて
公式ドキュメント:スクリプト作成に参考にしたAzureのREST APIの仕様
(skuにデプロイタイプの値が入るなんて上記からだとわからなかったのが苦労ポイントでした)
免責事項
本記事およびスクリプトは、2024年9月14日時点の情報に基づいています。今後のAzure OpenAI Serviceの仕様変更などにより、スクリプトが正常に動作しなくなる可能性があります。本スクリプトの使用は自己責任で行ってください。また、本スクリプトに関するメンテナンスやサポートは提供されておりません。
Discussion