Azure Database for MySQLをARMテンプレートからデプロイする手順とコツTech TIPS

Azure上でMySQLサーバが必要な場合、出来合いのサービスである「Azure Database for MySQL」を利用するのが最も簡単な方法だろう。ただ、そのデプロイには幾つか注意すべき点もある。ARMテンプレート(Bicep)に焦点を当てて、その手順とコツを説明する。

» 2024年04月10日 05時00分 公開
[島田広道デジタルアドバンテージ]
「Tech TIPS」のインデックス

連載目次

Azure Database for MySQLを一挙にデプロイ

対象:Azure Database for MySQL、ARMテンプレート(Bicep)


 Azureには「MySQL Server」を比較的容易に構築できる「Azure Database for MySQL」(以下、「Azure MySQL」と略)というサービスがある。仮想マシンやインストーラーなどを用意しなくても、Azureポータルからウィザードで設定していけば、簡単にポート3306で待ち受けるMySQL Serverを構築できる。

 ただ、比較的容易とはいっても設定項目の数は一定数あるため、ウィザードで作成するには手間がかかるし、オプションの指定も間違いやすい。また警告(アラート)や診断など、Azure MySQLのウィザードとは別に設定しなければならない項目もある。

 ARM(Azure Resource Manager)テンプレートでAzure MySQLをデプロイできれば、こうした問題を解決できる。1回の操作で特定の設定のAzure MySQLを構築可能だ。

 そこで本Tech TIPSでは、Bicepで記述したARMテンプレートを使ってAzure MySQLをデプロイする基本的な方法、および「ハマりやすい」注意点を説明する。

 対象は「フレキシブルサーバ」と呼ばれるLinuxベースのサーバとする(廃止が決まっているWindowsベースの「単一サーバ」は対象外)。また、仮想ネットワークやプライベートエンドポイントは使用せず、インターネット経由でアクセスできるようにする。

■執筆時の各種ツール/APIのバージョン

  • Azure CLI: Ver. 2.58.0
  • Bicep CLI: Ver. 0.26.54
  • Bicepでのデプロイ時のAPIバージョン: 2023-10-01-preview(MySQLフレキシブルサーバ)

Azure MySQLのCPUコア数/メモリ容量を指定する

 以下では、見やすくするためにARMテンプレートの単一ソースコードを分割して、それぞれ説明する。

 Azure MySQLのCPUやメモリの性能を指定するには、そのベースとなる仮想マシン(VM)のサイズ名称を以下のように指定する。

param skuName string = 'Standard_B1s' // ベースの仮想マシン(VM)のサイズ名称
var skuTiers = {
  // VMサイズの大枠(階層)を導出するオブジェクト
  Standard_B: 'Burstable' // 「バースト可能」。性能を一時的に高められる。レプリケーション不可など制約あり
  Standard_D: 'GeneralPurpose' // 「汎用(はんよう)」。一般的なワークロード向け
  Standard_E: 'MemoryOptimized' // 「Business Critical」。汎用よりメモリを増量
}
var skuTierKey = substring(skuName, 0, length('Standard_X')) // サイズ名称から↑のキーを導出
var sku = {
  name: skuName
  tier: skuTiers[skuTierKey]
}

【Bicep】Azure MySQLのCPUコア数/メモリ容量を指定する
※Microsoftのレファレンス:サービスレベル/サイズ/サーバの種類skuプロパティ

 パラメーター「skuName」のデフォルト値としている「Standard_B1s」が、VMサイズを表す名称の一種である。VMサイズの名称とそのCPUコア数、メモリ容量は、Microsoft Learnの「サービス レベル、サイズ、サーバの種類」で確認できる。

 オブジェクト「sku」の「tier」(sku.tier)には、下表のようにVMサイズの大枠(階層)を表す文字列を指定する必要がある(上のリストではVMサイズ名称から自動生成している)。

VMサイズ名称(skuName) VMサイズの大枠(階層) sku.tierに指定すべき文字列
Standard_B〜 バースト可能 Burstable
Standard_D〜 汎用(はんよう) GeneralPurpose
Standard_E〜 Business Critical MemoryOptimized
上記リストのsku.tierに指定すべき文字列

 以下のコマンドラインを実行すると、指定のリージョンで実際に作成可能なVMサイズの一覧を確認できる。

az mysql flexible-server list-skus -l <リージョン名> --query "[?zone=='none'].supportedFlexibleServerEditions[].supportedServerVersions[?name=='8.0.21'].supportedSkus[][].name" -o tsv

【CLI】作成可能なAzure MySQLの仮想マシンサイズ一覧を取得する
可用性ゾーンを特定したい場合は、「?zone=='none'」の「none」の代わりにゾーン番号を指定する。またMySQL Server 5.7の場合は、「?name=='8.0.21'」の「8.0.21」の代わりに「5.7」を指定すること。
※Microsoftのレファレンス:az mysql flexible-server list-skusAzure CLIの--queryオプション

 「アクセス制限」(後述)がかかっているリージョンの場合、上記コマンドの結果が空になる(一つもリストアップされない)。

Azure MySQLのストレージ容量や性能を指定する

 Azure MySQLのストレージについては、上述のVMサイズとは別に設定する必要がある。具体的には、ストレージの容量と性能(IOPS: 1秒当たりの入出力処理数)を以下のように設定する。

@minValue(20)
@maxValue(16384)
param storageSizeGB int = 20 // ストレージ容量の最大値

@allowed([
  'Enabled'
  'Disabled'
])
param autoIoScaling string = 'Enabled' // ストレージのIOPSの自動スケーリングを有効化

@minValue(360) // 最大値の方は仮想マシンのサイズに左右される
param iops int = 360 // ストレージのIOPS(自動スケーリングしない場合)

var storage = {
  storageSizeGB: storageSizeGB
  autoGrow: 'Enabled' // ストレージの自動拡張
  autoIoScaling: autoIoScaling
  iops: iops
}

【Bicep】Azure MySQLのストレージ容量や性能を指定する
※Microsoftのレファレンス:storageプロパティ

 ストレージの容量については、足りなくなると自動的に容量を増やす機能がデフォルトで有効になっている。つまり、上記のパラメーター「storageSizeGB」で指定する容量は、デプロイ時の初期容量にすぎない点に注意したい。

 容量の自動拡張は以下のルールで実行される。

  • 現容量が100GB以下: 空き容量が10%を下回ると、5GBが加えられる
  • 現容量が100GBを超える: 空き容量が10GBを下回ると、現容量の5%が加えられる

 IOPSの方もデフォルトで自動スケーリングが有効になっている。これは、実際のI/O処理数に応じてIOPSを自動的に増減させる機能だ。この場合、パラメーター「iops」で固定のIOPS値を指定する必要はない。

Azure MySQL(MySQL Server本体)のリソースを生成する

 Azure MySQLの本体(MySQL Server)のリソースを生成するには、以下のように記述する。VMサイズやストレージ以外の設定についても指定している。

param mySQLName string // Azure MySQLのリソース名
param location string = resourceGroup().location // ↑の作成先リージョン

param administratorLogin string // 管理者アカウント名
@secure()
param administratorLoginPassword string // ↑のパスワード

@allowed([
  '5.7'
  '8.0.21'
])
param version string = '8.0.21' // MySQL Serverのバージョン

var network = {
  // ネットワークの設定(ファイアウォールは別途)
  publicNetworkAccess: 'Enabled' // インターネットからのアクセスを許可
}

param backupRetentionDays int = 7 // バックアップ保持日数
var backup = {
  // バックアップの設定
  backupRetentionDays: backupRetentionDays
  geoRedundantBackup: 'Disabled' // リージョンをまたいだバックアップ。無効
}

var highAvailability = {
  // 高可用性の設定
  mode: 'Disabled' // 無効
}

// リソース生成: Azure MySQL(フレキシブルサーバ)
resource mySQLServer 'Microsoft.DBforMySQL/flexibleServers@2023-10-01-preview' = {
  name: mySQLName
  location: location
  sku: sku
  properties: {
    storage: storage
    administratorLogin: administratorLogin
    administratorLoginPassword: administratorLoginPassword
    version: version
    network: network
    backup: backup
    highAvailability: highAvailability
    replicationRole: 'None' // レプリケーションはしない
    createMode: 'Default' // 標準のサーバ作成モード(復元やレプリカではない)

    maintenanceWindow: {
      customWindow: 'Disabled'
    }
  }
}

【Bicep】Azure MySQL(MySQL Server本体)のリソースを生成する
※Microsoftのレファレンス:Microsoft.DBforMySQL flexibleServers

 バックアップは毎日全自動で実行される。パラメーター「backupRetentionDays」では、その履歴をどれくらい保持しているか、日数で指定できる。

デプロイが完了したAzure MySQLをAzureポータルで開いたところ デプロイが完了したAzure MySQLをAzureポータルで開いたところ

デプロイ時にMySQLのサーバパラメーター(システム変数)を変更する

 Azure MySQLでは、デプロイ時にサーバパラメーター(システム変数)を変更できる。以下では、サーバレベルの文字コードと照合順序、スロークエリログ、SQLモードを変更する例を記してみた。

param characterSetServer string = 'utf8mb4' // Azure MySQLの文字コード
param collationServer string = 'utf8mb4_0900_ai_ci' // ↑の照合順序
param slowQueryLog bool = false // スロークエリログを取得するか否か
param longQueryTime int = 10 // スロークエリかどうかのしきい値(秒)
param sqlModes array = [
  // SQL Modeの一覧
  'ONLY_FULL_GROUP_BY'
  'STRICT_TRANS_TABLES'
  'NO_ZERO_IN_DATE'
  'NO_ZERO_DATE'
  'ERROR_FOR_DIVISION_BY_ZERO'
]
var configs = [
  {
    name: 'character_set_server'
    value: characterSetServer
  }
  {
    name: 'collation_server'
    value: collationServer
  }
  {
    name: 'slow_query_log'
    value: slowQueryLog ? 'ON' : 'OFF'
  }
  {
    name: 'log_slow_admin_statements'
    value: slowQueryLog ? 'ON' : 'OFF'
  }
  {
    name: 'long_query_time'
    value: string(longQueryTime)
  }
  {
    name: 'sql_mode'
    value: join(sqlModes, ',')
  }
]

// リソース生成: サーバパラメーター(システム変数)の変更
resource configuration 'Microsoft.DBforMySQL/flexibleServers/configurations@2023-06-30' = [
  for config in configs: {
    parent: mySQLServer // ひも付けるAzure MySQLのリソース
    name: config.name
    properties: {
      value: config.value
    }
  }
]

【Bicep】MySQLのサーバパラメーター(システム変数)を変更する
※Microsoftのレファレンス:Microsoft.DBforMySQL flexibleServers/configurations

 システム変数を変更するにはそれぞれ、「Microsoft.DBforMySQL/flexibleServers/configurations」のリソースを生成する必要がある。上記リストでは複数のシステム変数をforループで変更している。

デプロイ時にファイアウォールルールを設定する

 インターネット経由での着信(パブリックエンドポイントを介したアクセス)を有効にしている場合、不正アクセスを防ぐために、「ファイアウォールルール」を設定すべきだ。

 ここでいうファイアウォールルールとは、ソースIPアドレスによるアクセス制限を指す。例えば、組織内のオンプレミスのシステムからAzure MySQLにアクセスする場合は、そのインターネット接続の発信元グローバルIPアドレスをファイアウォールルールとして登録する。このように登録したIPアドレスは許可される一方、未登録のIPアドレスからのアクセスは拒否される。

 ファイアウォールルールも、以下のようにリソースとして1つずつ生成する。

param firewallRules array = [
  {
    // 任意のAzureサービスからのアクセスを許可(パブリックエンドポイント経由)
    name: 'AllowAllAzureServicesAndResourcesWithinAzureIps' // ルール名
    startIpAddress: '0.0.0.0'
    endIpAddress: '0.0.0.0'
  }
  {
    name: 'headquarters' // ルール名
    startIpAddress: '192.0.2.17' // 始まりのIPアドレス
    endIpAddress: '192.0.2.31' // 終わりのIPアドレス
  }
  {
    name: 'branch1'
    startIpAddress: '203.0.113.65'
    endIpAddress: '203.0.113.65' // 範囲ではなく単一の場合は同一IPアドレスを指定
  }
]

// リソース生成: ファイアウォールルールの追加
@batchSize(1) // 1つずつ生成する
resource firewallRule 'Microsoft.DBforMySQL/flexibleServers/firewallRules@2023-06-30' = [
  for fwRule in firewallRules: {
    parent: mySQLServer // ひも付けるAzure MySQLのリソース
    name: fwRule.name
    properties: {
      startIpAddress: fwRule.startIpAddress
      endIpAddress: fwRule.endIpAddress
    }
  }
]

【Bicep】ファイアウォールルールを設定する
※Microsoftのレファレンス:Microsoft.DBforMySQL flexibleServers/firewallRules

 また、Azure内のAzureサービス(App Serviceや仮想マシンなど)からのアクセスを全面的に許可するなら、IPアドレス「0.0.0.0」をファイアウォールルールに設定すればよい。変更されることもあるAzureサービスのソースIPアドレスをいちいち指定しなくて済む。その一方で、全く無関係の第三者が生成したAzureリソースからアクセスされる危険性がある。

Azure MySQLのメトリックアラートを設定する

 Azure MySQLには複数のメトリックアラートが用意されている。ここでは代表的なメトリックとして、接続中断(Aborted Connections)とメモリ使用量に関するアラートをセットアップする例を以下に記す。

param totalAbortConnections int = 0 // 接続中断の回数の上限
param maxMemCapPercent int = 70 // メモリ使用率の上限
var metricAlerts = [
  {
    name: 'Aborted Connections at ${mySQLName}' // 通知メールのサブジェクトになる
    description: '${totalAbortConnections}回/5分 を超える接続中断が発生しました。${mySQLName}です。'
    severity: 2 // 重要度は「警告
    evaluationFrequency: 'PT1M' // 1分ごとに確認
    windowSize: 'PT5M' // 5分間監視
    metricTitle: 'metric_total_aborted_connections_gt_${totalAbortConnections}count_in_5m'
    threshold: totalAbortConnections
    metricName: 'aborted_connections' // Aborted Connectionsのシグナル名
    operator: 'GreaterThan'
    timeAggregation: 'Total'
  }
  {
    name: 'Host Memory Percent increasing at ${mySQLName}'
    description: 'メモリ使用率が ${maxMemCapPercent}% を超えました。${mySQLName}です。'
    severity: 3 // 重要度は「情報
    evaluationFrequency: 'PT1M'
    windowSize: 'PT5M'
    metricTitle: 'metric_max_memory_percent_gt_${maxMemCapPercent}percent_in_5m'
    threshold: maxMemCapPercent
    metricName: 'memory_percent' // Memory Percentのシグナル名
    operator: 'GreaterThan'
    timeAggregation: 'Maximum'
  }
]

// 既存リソース: 通知用アクショングループ
param monitorActionGroupRG string // リソースグループ名
param monitorActionGroupName string

resource monitorActionGroup 'Microsoft.Insights/actionGroups@2023-01-01' existing = {
  name: monitorActionGroupName
  scope: resourceGroup(monitorActionGroupRG)
}

// リソース生成: アラートルール
resource metricAlert 'microsoft.insights/metricalerts@2018-03-01' = [
  for ma in metricAlerts: {
    name: ma.name
    location: 'global'
    properties: {
      description: ma.description
      severity: ma.severity
      enabled: true
      scopes: [mySQLServer.id] // 測定対象のAzure MySQLのリソースID
      evaluationFrequency: ma.evaluationFrequency
      windowSize: ma.windowSize
      criteria: {
        allOf: [
          {
            threshold: ma.threshold
            name: ma.metricTitle
            metricNamespace: mySQLServer.type // 測定対象のAzure MySQLのリソースタイプ
            metricName: ma.metricName
            operator: ma.operator
            timeAggregation: ma.timeAggregation
            criterionType: 'StaticThresholdCriterion'
          }
        ]
        'odata.type': 'Microsoft.Azure.Monitor.SingleResourceMultipleMetricCriteria'
      }
      autoMitigate: true
      targetResourceType: mySQLServer.type // 測定対象のAzure MySQLのリソースタイプ
      actions: [
        {
          actionGroupId: monitorActionGroup.id // 通知用アクショングループのリソースID
        }
      ]
    }
  }
]

【Bicep】Azure MySQLのメトリックアラートを設定する
※Microsoftのレファレンス:Microsoft.Insights metricAlerts

 メトリックアラート作成については、Tech TIPS「【Azure】大量のメトリックアラートを一発で作る方法(リソーステンプレート編)」で説明している。上記リストでも、メトリックの違いを除けば、特に変わっている点はない。そのため、他のメトリックについても、下表を参考にすれば割と簡単にアラートをセットアップできるだろう。

metricNameプロパティ 概要
Slow_queries スロークエリの回数
active_connections アクティブな接続数
io_consumption_percent ストレージI/Oの使用率(%)
storage_percent ストレージ容量の使用率(%)
cpu_percent CPU使用率(%)
Azure MySQLの主要なメトリック(上記リストの分を除く)

Azure MySQLのログをストレージアカウントやLog Analyticsに送信する(診断設定)

 Azure MySQLのスロークエリログと監査ログは、ストレージアカウントやLog Analytics Workspaceに送信できる。それには以下のように拡張リソースを生成する。ストレージアカウントやLog Analytics Workspaceは事前に生成しておくこと。

param diagLogNames array = [
  // 取得可能なログ一覧
  'mysqlslowlogs' // MySQL Slow Logs。スロークエリログ
  //'mysqlauditlogs' // MySQL Audit Logs。監査ログ
]

// 既存リソース: ログ用ストレージアカウント
param logStorageRG string // リソースグループ名
param logStorageName string

resource logStgAccount 'Microsoft.Storage/storageAccounts@2022-09-01' existing = {
  name: logStorageName
  scope: resourceGroup(logStorageRG)
}

// 既存リソース: Log Analytics Workspace
param logAnalyticsRG string // リソースグループ名
param logAnalyticsName string

resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2022-10-01' existing = {
  name: logAnalyticsName
  scope: resourceGroup(logAnalyticsRG)
}

// 拡張リソース生成: 診断設定の追加
resource diagSetting 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = {
  name: 'diag-storage-log-${mySQLName}' // この診断設定の名前
  scope: mySQLServer // ひも付けるAzure MySQLのリソース
  properties: {
    storageAccountId: logStgAccount.id // ログ用ストレージアカウントのID
    workspaceId: logAnalytics.id // Log Analytics WorkspaceのID
    logs: [
      for logName in diagLogNames: {
        // 保存するログをループで1つずつ指定
        category: logName // ログ名称
        enabled: true
      }
    ]
  }
}

【Bicep】Azure MySQLのログをストレージアカウントやLog Analyticsに送信する(診断設定)
※Microsoftのレファレンス:Microsoft.Insights diagnosticSettings

【注意】メンテナンスウィンドウを指定するとデプロイに失敗する!?

 Azure MySQLでは、更新プログラムの適用といった「メンテナンス」をいつ実施するか、特定の曜日と時間帯(60分)で指定できる。未指定の場合は、ランダムに選ばれた曜日の23時〜翌7時(Azure MySQLのあるリージョンのタイムゾーン)にメンテナンスが実行される。この機能の詳細は、Microsoft Learn「Azure Database for MySQL - フレキシブル サーバの予定メンテナンスの設定を管理する」を参照していただきたい。

 ARMテンプレートにも、このメンテナンスの時間帯を指定するためのプロパティ「maintenanceWindow」が定義されている。しかし実際に指定すると、筆者の環境では確実に「The server '<リソース名>' does not exist or in unexpected status.」というエラーが発生してデプロイに失敗してしまう。

 もしARMテンプレートにメンテナンスウィンドウについて記述していて、同じエラーに遭遇した場合は、その記述をコメントアウトして再デプロイを試してみるとよいだろう。

 デプロイ後でも、以下のコマンドラインのようにAzure CLIでメンテナンスウィンドウを設定できる。

az mysql flexible-server update -g <リソースグループ名> -n <リソース名> --maintenance-window <曜日を表す3文字の英字>:<時>:<分>

【CLI】Azure MySQLのメンテナンス時間帯をカスタマイズする
<曜日を表す3文字の英字>:<時>:<分>は「Thu:17:00」のように指定する。時刻はUTCで表す必要がある(「17:00」と指定した場合、日本時間の午前2時になる)。
※Microsoftのレファレンス:az mysql flexible-server update

【注意】ファイアウォールルールを設定すると数分単位でデプロイ時間が延びていく

 デプロイ時にファイアウォールルールを設定すると、分単位で時間がかかる。筆者の環境では、1ルール当たり1〜4分程度の時間が必要だった。たくさんのルールを設定しようとすると、デプロイに1時間以上かかりかねない。

 そのため、開発中は最低限のルールだけにとどめておく、あるいはデプロイ後にAzure CLIなどで別途設定する、といった回避策を考えておくべきだろう。

【注意】リージョンによっては「制限」のためAzure MySQLを作成できないことがある

 リソースがひっ迫している(データセンターでサーバなどが不足している)リージョンでは、MicrosoftによってMySQL Serverやその他のリソースの作成に「制限」がかけられている場合がある。

 こうしたリージョンでは、Azure MySQLは生成できないけど、他のリソースなら作れるといった症状が発生する。また、前述したVMサイズの指定可能リストを出力するコマンド「az mysql flexible-server list-skus」を、対象のリージョンに対して実行すると、1つもVMサイズが返されない。

 以前に同じリソースを作ったことがあり、現在運用中でも、新規作成では前述のエラーが生じることがある。さらに、サブスクリプションによって作成できたりできなかったりする。

 このような症状に遭遇したらMicrosoftのサポートに相談して、Azure MySQLの作成に制限がかかっているかどうか確認するとよいだろう(筆者の場合は、西日本と韓国南、シンガポールの各リージョンで制限されていた)。

「制限」によって特定リージョンにAzure MySQLが作成できなかった例 「制限」によって特定リージョンにAzure MySQLが作成できなかった例

「Tech TIPS」のインデックス

Tech TIPS

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。