6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Azureコストとサービス毎の内訳をTeams通知する

Last updated at Posted at 2024-11-20

0. はじめに

AzureのコストはAzure portalコスト管理で詳しく分析できますが、毎日ログインして確認するのはなかなか大変です。

そこで、Azureでどのサービスをいくら使っているか、今月と今年度のコストをTeamsに毎日通知するようにしてみました。

teams_post.png

1. 手順の流れ

Automation アカウントRunbookでコストを取得し、ロジック アプリワークフローTeamsに投稿します。(図中の番号は以下の章番号に対応しています。)

2. Automationアカウントの作成

2.1. Automationアカウントを作成する

Azure portalにサインインし、ナビゲーションバーでAutomation アカウントに移動します。

作成を選択し、サブスクリプションリソースグループAutomation アカウント名リージョンを入力してアカウントを作成します。

2.2. Automationアカウントにコストを閲覧する権限を付与する

コストを参照できるよう、AutomationアカウントのシステムマネジメントIDにコスト管理の閲覧者ロールを割り当てます。

作成したAutomationアカウントを選択し、アカウント設定>ID>システム割り当て済み>Azure ロールの割り当てをクリックします。

automation_add_role.png

ロールの割り当ての追加を選択し、スコープサブスクリプションにし、サブスクリプションを入力し、役割コスト管理の閲覧者を選んで保存します。

automation_add_role_costmanagementreader.png

3. Runbookの作成

3.1. AutomationアカウントにRunbookを作成する

Azureコストを取得し、月次コストおよび年次コストとそのサービス内訳を抽出して、ロジックアプリへHTTPリクエストを送信するRunbookを作成します。

作成したAutomationアカウントを選択し、プロセス オートメーション>Runbook>Runbook の作成をクリックし、Runbookの名前Runbook の種類ランタイム バージョンを入力して作成します。今回は以下を選択しました。

項目 設定値
名前 (任意)
Runbook の種類 PowerShell
ランタイム バージョン 7.2

PowerShell Runbook の編集で以下のコードを入力し保存公開します。

Runbookを作成(修正)したら、必ず公開して状態発行済みになっていることを確認してください。保存だけしても公開しないと有効になりません。

リソースグループの利用実績が無い場合コストがnullとなり正しく動かない場合があります。必要ならエラー処理などを追加してください。

Runbook
$SubscriptionID = Get-AutomationVariable -Name "SubscriptionID"
$RGName = Get-AutomationVariable -Name "ResourceGroupName"
$LogicAppsUri = Get-AutomationVariable -Name "LogicAppsUri"

if ((Get-Date).Month -ge 4) {
    $FiscalYear = (Get-Date).Year
} else {
    $FiscalYear = (Get-Date).Year - 1
}
$FYStartDay = (Get-Date -Year $FiscalYear -Month 4 -Day 1)
$Today = (Get-Date).Date

Connect-AzAccount -Identity
Set-AzContext -SubscriptionId $SubscriptionID

$MonthlyUsageDetail = Get-AzConsumptionUsageDetail -ResourceGroup $RGName
$MonthlyCost = [Math]::Round($($MonthlyUsageDetail.PretaxCost | Measure -Sum).Sum, [MidpointRounding]::AwayFromZero).ToString("#,#")
$MonthlyServicesCost = $MonthlyUsageDetail | Group-Object -Property ConsumedService | Sort-Object -Property {@($_.Group.PretaxCost | Measure -Sum).Sum} -Descending | ForEach-Object {
    [PSCustomObject]@{
        Service = $_.Name -replace '^Microsoft\.', ''
        Cost = [Math]::Round(($_.Group.PretaxCost | Measure -Sum).Sum, [MidpointRounding]::AwayFromZero).ToString("#,#")
    }
}

$AnnualUsageDetail = Get-AzConsumptionUsageDetail -ResourceGroup $RGName -StartDate $FYStartDay -EndDate $Today
$AnnualCost = [Math]::Round($($AnnualUsageDetail.PretaxCost | Measure -Sum).Sum, [MidpointRounding]::AwayFromZero).ToString("#,#")
$AnnualServicesCost = $AnnualUsageDetail | Group-Object -Property ConsumedService | Sort-Object -Property {@($_.Group.PretaxCost | Measure -Sum).Sum} -Descending | ForEach-Object {
    [PSCustomObject]@{
        Service = $_.Name -replace '^Microsoft\.', ''
        Cost = [Math]::Round(($_.Group.PretaxCost | Measure -Sum).Sum, [MidpointRounding]::AwayFromZero).ToString("#,#")
    }
}

$Body = @{
    resourcegroup = $RGName
    monthlycost = $MonthlyCost
    monthlyservicescost = $MonthlyServicesCost
    annualcost = $AnnualCost
    annualservicescost = $AnnualServicesCost
}
Invoke-RestMethod -Uri $LogicAppsUri -Method Post -Body ($Body | ConvertTo-Json -Depth 3) -ContentType "application/json"

3.2. Runbookにスケジュールを設定する

作成したAutomationアカウントを選択し、共有リソース>スケジュール>スケジュールの追加をクリックし、名前開始時繰り返し間隔有効期限を入力して作成します。
今回は月曜日から金曜日の午前9時に実行するスケジュールを作成しました。

runbook_schedule_01.png

作成したAutomationアカウントを選択し、プロセス オートメーション>Runbook>作成したRunbook名を選択し、スケジュールをリンクをクリックします。

runbook_schedule_02.png

スケジュールを Runbook にリンクします>作成したスケジュールを選択し、OKをクリックします。

runbook_schedule_03.png

3.3. Runbookの変数を設定する

Runbookから呼び出す変数を設定します。

作成したAutomationアカウントを選択し、共有リソース>変数>変数の追加をクリックし、以下の変数を作成します。

名前 タイプ
LogicAppsUri 文字列 コスト情報をRunbookからロジックアプリへ送信するためのロジックアプリのアドレス
5.9. ロジックアプリのアドレスをRunbook変数に設定参照)
ResourceGroupName 文字列 コストを取得するリソースグループ名
SubscriptionID 文字列 サブスクリプションID

4. ロジックアプリの作成

Azure portalのナビゲーションバーでロジック アプリに移動します。

追加を選択し、ホスティング オプションの選択マルチテナントを選択して選択をクリックします。

logicapps_create_01.png

ロジック アプリの作成(マルチテナント)サブスクリプションリソース グループロジック アプリ名リージョンを入力して作成します。

5. ワークフローの作成

Runbookからコスト情報を受信し、月次コストおよび年次コストを取得して、Teamsチャネルに投稿するロジックアプリワークフローを作成していきます。

workflow.png

作成したロジックアプリ名を選択し、開発ツール>ロジック アプリ デザイナーを選択します。

5.1. HTTPリクエストの受信

Runbookからコスト情報を含むHTTPリクエストを受信します。

ロジック アプリ デザイナートリガーの追加を選択し、Request>When a HTTP request is receivedをクリックします。

workflow_01.png

トリガー名を変更します。

トリガー名
HTTPリクエストの受信

パラメーターに以下の項目を入力し、>>でトリガーを折りたたみます。

パラメーター 入力内容
Method POST
Request Body JSON Schema 以下参照
Request Body JSON Schema
{
    "properties": {
        "resourcegroup": "string",
        "monthlycost": "string",
        "monthlyservicescost": {
            "type": "array",
            "items": {
                "properties": {
                    "Service": "string",
                    "Cost": "string"
                },
                "type": "object"
            }
        },
        "annualcost": "string",
        "annualservicescost": {
            "type": "array",
            "items": {
                "properties": {
                    "Service": "string",
                    "Cost": "string"
                },
                "type": "object"
            }
        }
    },
    "type": "object"
}

5.2. 月次コストの初期化

月次コストを出力するに当たって、変数を初期化します。

HTTPリクエストの受信トリガーの下の>アクションの追加を選択し、Variables>Initialize variableをクリックします。

アクション名を変更します。

アクション名
月次コスト変数の初期化

パラメーターに以下の項目を入力し、>>でアクションを折りたたみます。

パラメーター 入力内容
Name monthlyServicesCostFormatted
Type String
Value (空白)

5.3. 月次コストの出力

サービス毎の月次コストを取得するため、繰り返し制御を行います。

月次コスト変数の初期化アクションの下の>アクションの追加を選択し、Control>For eachをクリックします。

アクション名を変更します。

アクション名
月次コストの出力

パラメーターに以下の項目を入力します。

パラメーター 入力内容
Select An Output From Previous Steps workflow_insert_content.png monthlyservicescost

設定に以下の項目を入力し、>>でアクションを折りたたみます。

設定 設定内容
Concurrency control オン
Degree of parallelism 1

5.4. 月次コスト変数にサービスコストを追加

繰り返し処理の中で、サービス毎の月次コストを取得します。

月次コストの出力アクションの中の>アクションの追加を選択し、Variables>AppendToStringVariableをクリックします。

アクション名を変更します。

アクション名
月次コスト変数にサービスコストを追加

パラメーターに以下の項目を入力します。

パラメーター 入力内容
Name monthlyServicesCostFormatted
Value workflow_insert_expression.png 以下参照
Value
concat('- ', items('月次コストの出力')?['Service'], ':', if(empty(items('月次コストの出力')?['Cost']), '0', items('月次コストの出力')?['Cost']), '円<br>')

5.5. 年次コストの初期化

年次コストを出力するに当たって、変数を初期化します。

HTTPリクエストの受信トリガーの下の>並列分岐の追加を選択し、Variables>Initialize variableをクリックします。

アクション名を変更します。

アクション名
年次コスト変数の初期化

パラメーターに以下の項目を入力し、>>でアクションを折りたたみます。

パラメーター 入力内容
Name annualServicesCostFormatted
Type String
Value (空白)

5.6. 年次コストの出力

サービス毎の年次コストを取得するため、繰り返し制御を行います。

年次コスト変数の初期化アクションの下の>アクションの追加を選択し、Control>For eachをクリックします。

アクション名を変更します。

アクション名
年次コストの出力

パラメーターに以下の項目を入力します。

パラメーター 入力内容
Select An Output From Previous Steps workflow_insert_content.png annualservicescost

設定に以下の項目を入力し、>>でアクションを折りたたみます。

設定 設定内容
Concurrency control オン
Degree of parallelism 1

5.7. 年次コスト変数にサービスコストを追加

繰り返し処理の中で、サービス毎の年次コストを取得します。

年次コストの出力アクションの中の>アクションの追加を選択し、Variables>AppendToStringVariableをクリックします。

アクション名を変更します。

アクション名
年次コスト変数にサービスコストを追加

パラメーターに以下の項目を入力します。

パラメーター 入力内容
Name annualServicesCostFormatted
Value workflow_insert_expression.png 以下参照
Value
concat('- ', items('年次コストの出力')?['Service'], ':', if(empty(items('年次コストの出力')?['Cost']), '0', items('年次コストの出力')?['Cost']), '円<br>')

5.8. チャネルにコストを投稿

月次コストおよび年次コストをTeamsチャネルに投稿します。

月次コストの出力アクションの下の>アクションの追加を選択し、Microsoft Teams>チャットまたはチャネルでメッセージを投稿するをクリックします。

サインインを選択し、Teams投稿に使用するアカウントを選択して認証します。

アクション名を変更します。

アクション名
チャネルにコストを投稿

設定に以下の項目を入力します。

設定 設定内容
Run after 月次コストの出力
年次コストの出力

パラメーターに以下の項目を入力し、>>でアクションを折りたたみます。

パラメーター 入力内容
投稿者 フロー ボット
投稿先 Channel
Team 任意のTeamsチーム
Channel 任意のTeamsチャネル
Message 以下参照
Message
<p class="editor-paragraph"><u><b><strong class="editor-text-bold editor-text-underline">今月の利用料金</strong></b></u><br>■合計<br>@{triggerBody()?['resourcegroup']}:@{triggerBody()?['monthlycost']}円<br>■内訳<br>@{variables('monthlyServicesCostFormatted')}<br><u><b><strong class="editor-text-bold editor-text-underline">今年度の利用料金</strong></b></u><br>■合計<br>@{triggerBody()?['resourcegroup']}:@{triggerBody()?['annualcost']}円<br>■内訳<br>@{variables('annualServicesCostFormatted')}</p><br>

最後に、保存をクリックしてロジックアプリを保存します。

5.9. ロジックアプリのアドレスをRunbook変数に設定

ロジックアプリを保存するとRunbookからHTTPリクエストを受信するためのアドレスが割り当てられるので、Runbookの変数に値を設定します。

HTTPリクエストの受信トリガーを選択し、パラメーター>HTTP URLをコピーします。

logicappsuri.png

ナビゲーションバーでAutomation アカウントに移動します。

作成したAutomationアカウント>共有リソース>変数>LogicAppsUriを選択し、にコピーしたアドレスをペーストして保存します。

runbook_variable.png

6. Teamsで通知確認

想定通りにAzureコストとサービス内訳をTeams通知できることを確認するため、Runbookを手動実行します。

Azure portalのナビゲーションバーでAutomation アカウントに移動します。

作成したAutomationアカウント>プロセス オートメーション>Runbook>作成したRunbookを選択し、開始>はいをクリックします。

runbook_start.png

Teamsチャネルにコストが通知されていることを確認します。
サービスはコストの高いものから降順に表示されます。

teams_post.png

7. まとめ

Azureコストとサービス毎の内訳をTeams通知する方法をご紹介しました。

注意点として、法人でCSP(Cloud Solution Provider)やEA(Enterprise Agreement)のライセンス形態を採用している場合、販売代理店ごとの割引や保守費用が発生するため、Azure portalで表示されるコストと実際の請求料金が一致しないことがあります。

ご利用の環境に合わせて算出式を変更するなどカスタマイズして取り入れていただければ幸いです。

※ 本ブログに記載した内容は個人の見解であり、所属する会社、組織とは全く関係ありません。
※ 2024年10月 現在

6
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?