ARM Template の書き方 その8 condition 従量課金対策

  • SQLServer
  • AzureDataBase
  • PowerShell
  • AzureResourceManager
  • AzurePowerShell
  • 前書き

    前回の記事「ARM Template の書き方 その7 SQL Database①」で SQL Database を構築しました。

    SQL Database を構築してから、気づいたら ¥20,000 近く課金されていて焦りました。やはり、データベースサービスは使ってるとグイグイ課金されていきますね。

    やりたいこと

    SQL Database は従量課金制で使った分だけ課金される仕組みですが、停止することができません。そのため、個人で使う場合、検証作業等が終わったら削除しておかないと無駄な費用が掛かってしまいます。

    そこで、今回は "condition" を使って、パラメータの true/false を切り替えるだけで SQL Database を作成したり削除したりできるテンプレートとデプロイ方法を考えてみました。

    やってみた

    それでは、作成したテンプレートファイルの内容を簡単に紹介したいと思います。

    パラメータファイル

    下記のようなパラメータを用意して、true/false を書き換えるだけでリソースの作成・削除を指示できるようにします。

    {
        "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
        "contentVersion": "1.0.0.0",
        "parameters": {
        "sqlDatabase01Flag":{
            "value": false
          }
        }
    }

    上記のパラメーターでは、false としているので、SQL Database が作成されないフラグとなっています。

    テンプレートファイル

    SQL Server と SQL Database の部分にフォーカスして紹介します。

    {
      "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
      "contentVersion": "1.6.0.0",
      "parameters": {
        "sqlDatabase01Flag": {
          "type": "bool",
          "defaultValue": false,
          "metadata": {
            "descroption": "Do you deploy The Database?"
          }
        }
      },
      "resources": [
        {
          "name": "[variables('sqlServers').sqlServer01.name]",
          "type": "Microsoft.Sql/servers",
          "apiVersion": "2019-06-01-preview",
          "location": "[variables('location')]",
          "tags": "[variables('tags')]",
          "properties": {
            "administratorLogin": "[variables('sqlServers').sqlServer01.administratorLogin]",
            "administratorLoginPassword": "[parameters('adminPassword')]",
            "version": "12.0",
            "minimalTlsVersion": "1.2",
            "publicNetworkAccess": "Enabled"
          },
          "resources": [
            {
              "name": "[concat(variables('sqlServers').sqlServer01.name,'/rule00')]",
              "type": "Microsoft.Sql/servers/firewallRules",
              "apiVersion": "2015-05-01-preview",
              "properties": {
                "startIpAddress": "0.0.0.0",
                "endIpAddress": "0.0.0.0"
              },
              "dependsOn": [
                "[variables('resourceID').sqlsv01]"
              ]
            },
            {
              "condition": "[parameters('sqlDatabase01Flag')]",
              "name": "[concat(variables('sqlServers').sqlServer01.name,'/',variables('sqlDatabases').sqlDatabase01.name)]",
              "type": "Microsoft.Sql/servers/databases",
              "apiVersion": "2020-08-01-preview",
              "location": "[variables('location')]",
              "tags": "[variables('tags')]",
              "sku": {
                "name": "Standard",
                "tier": "Standard",
                "capacity": 20
              },
              "properties": {
                "collation": "SQL_Latin1_General_CP1_CI_AS",
                "sampleName": "AdventureWorksLT",
                "requestedServiceObjectiveName": "S1"
              },
              "dependsOn": [
                "[variables('resourceID').sqlsv01]"
              ]
            }
          ]
        }
      ]
    }

    デプロイ

    パラメータで false となっていた場合は、リソースを消すように動かしたいです。そのためには、完全モードでのデプロイを行う必要があります。

    完全モードとは、テンプレートで定義していないリソースは削除するオプションのことです。詳しくは過去の記事「ARM Template の Deploy」でも解説しておりますので、ご参照ください。

    New-AzResourceGroupDeployment ` -Name rgdeploy-202101281850 ` -ResourceGroupName sample-rg ` -Mode Complete ` -Force ` -TemplateFile azuredeploy.json ` -TemplateParameterFile dev.parameters.json | ` Out-File -Append deploy.log

    上記のようにモードを Complet でコマンドを実行することで、condition が false のリソースは削除されません。(もともと対象のリソースが作成されていない場合は無視されます。)

    おまけ

    親リソースと子リソースの関係

    condition でリソースの作成するしないをテンプレートで管理する時、親リソースと子リソースの関係について、理解しておく必要があります。

    例えば、上記のテンプレートでいえば、"Microsoft.Sql/servers" が親リソースで、"Microsoft.Sql/servers/firewallRules" と "Microsoft.Sql/servers/databases" が子リソースです。

    仮に親リソースだけ conditon 設定してしまうと、ARM では親リソースがいなくても、子リソースを作成しようとするのでエラーが返ってきてしまいます。

    そのため、親リソースである "Microsoft.Sql/servers" を condition でコントロールする場合には、子リソースの全てに対して同じ condition を設定しておく必要があります。例えば、下記のようにです。

    {
      "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
      "contentVersion": "1.6.0.0",
      "parameters": {
        "sqlDatabase01Flag": {
          "type": "bool",
          "defaultValue": false,
          "metadata": {
            "descroption": "Do you deploy The Database?"
          }
        }
      },
      "resources": [
        {
          "condition": "[parameters('sqlDatabase01Flag')]",
          "name": "[variables('sqlServers').sqlServer01.name]",
          "type": "Microsoft.Sql/servers",
          "apiVersion": "2019-06-01-preview",
          "location": "[variables('location')]",
          "tags": "[variables('tags')]",
          "properties": {
            "administratorLogin": "[variables('sqlServers').sqlServer01.administratorLogin]",
            "administratorLoginPassword": "[parameters('adminPassword')]",
            "version": "12.0",
            "minimalTlsVersion": "1.2",
            "publicNetworkAccess": "Enabled"
          },
          "resources": [
            {
              "condition": "[parameters('sqlDatabase01Flag')]",
              "name": "[concat(variables('sqlServers').sqlServer01.name,'/rule00')]",
              "type": "Microsoft.Sql/servers/firewallRules",
              "apiVersion": "2015-05-01-preview",
              "properties": {
                "startIpAddress": "0.0.0.0",
                "endIpAddress": "0.0.0.0"
              },
              "dependsOn": [
                "[variables('resourceID').sqlsv01]"
              ]
            },
            {
              "condition": "[parameters('sqlDatabase01Flag')]",
              "name": "[concat(variables('sqlServers').sqlServer01.name,'/',variables('sqlDatabases').sqlDatabase01.name)]",
              "type": "Microsoft.Sql/servers/databases",
              "apiVersion": "2020-08-01-preview",
              "location": "[variables('location')]",
              "tags": "[variables('tags')]",
              "sku": {
                "name": "Standard",
                "tier": "Standard",
                "capacity": 20
              },
              "properties": {
                "collation": "SQL_Latin1_General_CP1_CI_AS",
                "sampleName": "AdventureWorksLT",
                "requestedServiceObjectiveName": "S1"
              },
              "dependsOn": [
                "[variables('resourceID').sqlsv01]"
              ]
            }
          ]
        }
      ]
    }

    さらに、output も定義しているなら output にも condition を定義しておかないと、デプロイ時にエラーが返ってきてしまいます。

    比較演算子

    単純に true/false をパラメータで指定するのではなく、比較演算子も用いる方法もあります。

    {
      "condition": "[equals(parameters('flag01'),'abc')]"
    }

    とすれば、"fag01" のパラメータが "abc" であれば true となります。他にも様々な比較演算子が用意されていますので、用途に合わせて使えますね。

    • greater
    • greaterOrEquals
    • less
    • lessOrEquals

    最後に

    今回は、パラメータファイルでリソースを上手にコントロールできる方法がないかなと思い、試しに condition を使ってみました。

    デプロイの際に完全モードを採用しているので、リンクテンプレートなどの機能が使えないという制約があります。この辺りも、ARM template の機能拡張によって柔軟に対応できるようになれば、もっと便利になるのかなと思います。

    以上です。

  • SQLServer
  • AzureDataBase
  • PowerShell
  • AzureResourceManager
  • AzurePowerShell