Azure SQL Managed Instanceの費用節約について
はじめに
こんにちは。エヌデーデーの小嶋です。
現在、「Azure SQL Managed Instance」を使った業務システムの開発に携わっているのですが、そのノウハウの中から、開発環境のコスト削減策について書いてみます。
Microsoft Azureで提供されているPaaSのマネージドデータベースサービスである「Azure SQL Managed Instance」(以降SQLMI)は、これまで「使っていない時に停止して課金を抑える機能」がありませんでした。
SQLMI、まあまあ費用がかかります。。。これまでやむを得ないものとして頑張ってきましたが、いよいよ上司からの圧がきつくなってきたので少しでも自社のコスト削減に寄与したいと思い調べてみると、、、、、プレビューで実装されていました!!
(クラウドは本当に進化が早いですよね・・・気づいたのはプレビュー提供開始から3か月以上たってからでした・・・。がんばってキャッチアップしなければ!)
さっそく使ってみよう、と設定してみた際の作業記録を公開します。
新機能でできること
https://learn.microsoft.com/ja-jp/azure/azure-sql/managed-instance/instance-stop-start-how-to?view=azuresql-mi&tabs=azure-portal
インスタンスの停止と開始の機能では、主に以下の2つの方法で制御することができます。
- 手動での開始/停止
- スケジューリングによる開始/停止
現状では、2.のスケジューリングでの制御はそれほど柔軟ではありません。
必ず開始と停止をセットで設定する必要があるため、停止だけをスケジュールしておく、といったことはできないのです。
※詳細は、Microsoftのサイトをご覧ください。
作業環境
まず、今回私が作業を実施した環境の構成についてご紹介します。(実際にはもう少し多くの要素が絡んでいます。)
右側の赤枠で示しているのが、今回の主役となるSQLMIです。
また、詳細は割愛しますが、今回関わってくるポイントとしては以下となります。
- 別VNETのウェブアプリケーション(WebApps)からSQLMIを利用
- 社内から、P2S VPNにてSQLMIを操作
設定手順
だいぶ前置きが長くなってしまいましたが、ここからが実施した手順です。
なお、先に書いてしまいますが、以下の①~③の手順については、これからSQLMIを構築する場合 (※) には不要になる手順だと思います。
※厳密には、2022年11月以降に新バージョンのサブネットを使って構築する場合
①スタート!
作業開始前は、数回ポチれば設定できるよね?と思ってました・・・。
まずはAzureポータルでSQLMIの管理画面を開くと、ちゃんと新機能についての導線が表示されています。サクッとクリックしていきます。
次に表示されたのが以下の画面です。(ん?仮想ネットワーク・・・?)
どうも、仮想ネットワークのサブネット設定の方を変更しなくてはいけない、ということのようで、このあたりから若干不安を抱きつつも「仮想ネットワークを開く」を押下していきます。
作業開始時点では、もちろん新機能と互換性のあるサブネットは存在していません・・・。
ということで、次はサブネットを作成していくこととなります。
②新サブネットの作成とSQLMIの移動
では、新機能と互換性のあるサブネットを作成し、SQLMIの配置を新サブネットの方に移動させていきます。
簡単なイメージとしては、以下となります。
これについては特別な設定が必要というわけではありませんでした。現時点で新たに作成したサブネットであれば、特に問題ないようです。
Azureポータルから、[仮想ネットワーク] – [(SQLMIを配置している仮想ネットワーク)] – [サブネット] を開いていき、新規で追加していきます。
サブネットの作成が完了したので、SQLMIの配置を変更していきます。再度①の手順で進めていくと、新サブネットが選択可能となっています。
変更を保存しようとすると、以下のメッセージが。
そして、移動はなんと・・・・5時間後に正常終了しました!!よかった・・・。
③ネットワークセキュリティグループの調整
これで後は停止、開始ができるようになっているんだろうな、と思いながら、まずはアプリケーションや管理ツールからの接続を試してみると、つながりません・・・。
旧サブネットの設定などを見返してみると、ネットワークセキュリティグループ(以降NSG)の調整が必要そうだということに気が付きました。
※ネットワークセキュリティグループ:ざっくり言うと、ファイアウォールの設定をまとめたもの。詳細はこのあたりを参照
SQLMIが存在する新サブネットに対しても旧サブネットと同一のNSGを設定しており、そこで旧サブネットに対して行われている設定を模して追加しました。
内容は以下で、すべて、受信・送信ともに追加しています。
これで無事に接続することができました。
ポート | プロトコル | 対象 |
1433 | TCP | VirtualNetwork(MS SQL) – 10.2.1.0/24 間 |
11000-11999 | TCP | VirtualNetwork – 10.2.1.0/24 間 |
5022 | TCP | VirtualNetwork – 10.2.1.0/24 間 |
最終的なNSGの設定を載せておきます。
④Start/Stopスケジュールの設定
どうにかたどり着きました。Azureポータルで見ると、それっぽい機能へのメニューが追加されています!
上部の手動操作部分はそのままとして、サイドバーメニューの「Start/Stopスケジュール」を開いていきます。
前段でも書きましたが、開始と終了の曜日と時刻を必ずセットで指定する必要があるものの、この画面の操作方法については特になんてこともありません。
ただし、2023年03月20日時点で不具合が有り、一度設定を登録した後GUIでは修正、削除作業ができません。(Microsoftに確認済み)
そのため、作業としてはPowerShellで登録するという形で実施しました。
最終的な設定としては以下で、平日は8時に起動、23時に停止。土日は起動しない。という状態です。
なお、 今回の環境で 手動で試した限りでは、停止は10秒程度、開始は20~30分かかりました。スケジュール設定の開始から使用可能となるまで多少時間がかかると思われるため、そのあたりを見越してスケジューリングするとよさそうです。
まとめ
Azure SQL Managed Instanceで、費用の節約のためのStart/Stopスケジュールを設定するために行ったあれこれについて記載しました。
Start/Stopスケジュールの機能自体は何ら難しいものではないですが、Start/Stopスケジュールの機能が実装される前に構築したSQLMIに対してこの機能を有効化する場合そこそこの手数が必要でしたし、関連するネットワーク周りも併せて調整する必要があるため、少々手間取りました。
同じような境遇の方が少しでも参考になればと思います。
スケジュールを登録したPowerShell
最後に、GUIにバグがあったのでスケジュール設定に使用したPowerShellを簡単に掲載しておきます。
作業としては、Azureポータル上でCloudShellを起動して実行していますので、その前提となります。
# サブスクリプションIDとリソースグループ名、SQLMIの名称を設定
$SubscriptionId = 'yourSubscriptionId'
$RgName = 'yourResourceGroupName'
$SqlMIName = 'yourSqlMIName'
# APIエンドポイント関連
$UriPrefix = "https://management.azure.com/subscriptions/" + $SubscriptionId + "/resourceGroups/" + $RgName + "/providers/Microsoft.Sql/managedInstances/"
$UriSuffix = "?api-version=2021-08-01-preview"
# ログイン
Select-AzSubscription -SubscriptionName $SubscriptionID
$azContext = Get-AzContext
$azProfile = [Microsoft.Azure.Commands.Common.Authentication.Abstractions.AzureRmProfileProvider]::Instance.Profile
$profileClient = New-Object -TypeName Microsoft.Azure.Commands.ResourceManager.Common.RMProfileClient -ArgumentList ($azProfile)
# トークン取得
$token = $profileClient.AcquireAccessToken($azContext.Subscription.TenantId)
$authHeader = @{'Content-Type'='application/json';'Authorization'='Bearer ' + $token.AccessToken}
# URI
$instanceGetUri = $UriPrefix + $SqlMIName + $UriSuffix
$instanceCreateScheduleUri = $UriPrefix + $SqlMIName + "/startStopSchedules/default" + $UriSuffix
########参考########
#Invoke-WebRequest -Method Get -Headers $authHeader -Uri $instanceCreateScheduleUri # 既存スケジュール取得
#Invoke-WebRequest -Method Delete -Headers $authHeader -Uri $instanceCreateScheduleUri # 既存スケジュール削除(すべて)
# 登録リクエスト内容構築
$requestBody = [pscustomobject]@{
properties = [pscustomobject]@{
timeZoneId = "Tokyo Standard Time"
description = "This is a schedule for our Dev/Test environment."
scheduleList = @(
@{startDay='Monday'; startTime='08:00 AM';stopDay='Monday'; stopTime='11:00 PM'}
@{startDay='Tuesday'; startTime='08:00 AM';stopDay='Tuesday'; stopTime='11:00 PM'}
@{startDay='Wednesday';startTime='08:00 AM';stopDay='Wednesday';stopTime='11:00 PM'}
@{startDay='Thursday'; startTime='08:00 AM';stopDay='Thursday'; stopTime='11:00 PM'}
@{startDay='Friday'; startTime='08:00 AM';stopDay='Friday'; stopTime='11:00 PM'}
)
}
}
$instanceScheduleBody = ConvertTo-Json -InputObject $requestBody -Depth 3
# 登録実行
Invoke-WebRequest -Method Put -Headers $authHeader -Uri $instanceCreateScheduleUri -Body $instanceScheduleBody