しばやん雑記

ASP.NET Core とメイドさんが大好きなフリーランスのプログラマーのブログ

ARM Template を使って Azure Web Apps / Azure Functions の作成と同時に Zip Deploy まで行う

昔から ARM Template では Web Deploy を使ったトラディショナルなデプロイに対応していましたが、ちょっと前に Windows の Web Apps と Azure Functions では Zip Deploy が使えるようになっていたようです。

ちなみに Web Deploy を使ったデプロイは、昔からちょこちょこドキュメントで出てきます。

例によって Zip Deploy を行う ARM Template のリファレンスは調べた感じでは見つかりませんでしたが、Kudu のコミットログを漁ることで Web Deploy とほぼ同じ書き方で使えることがわかりました。

具体的に Zip Deploy を実行するための定義は以下のようになります。packageUri にはデプロイしたいアプリケーションを zip にしたものを指定します。

{
  "apiVersion": "2019-08-01",
  "type": "extensions",
  "name": "zipdeploy",
  "dependsOn": [
    "[resourceId('Microsoft.Web/sites', variables('webAppPortalName'))]"
  ],
  "properties": {
    "packageUri": "https://shibayan.blob.core.windows.net/AspNetCoreApp.zip"
  }
}

ぱっと見は Run From Package で URL を指定するのと違いが判らないかもしれませんが、この Zip Deploy API を使うと、常にリモートからファイルをダウンロードする前者の方法とは異なり、Visual Studio や Azure Pipelines から行う Zip Deploy と同じになります。

なのでスタートアップ時にリモートからファイルをダウンロードしないので、Run From Package と組み合わせるとコールドスタートの改善が期待できます。ファイル自体も単純な zip で良いので作りやすいです。

デプロイと同時に Zip Deploy を実行

とりあえず Web Apps 向けの ARM Template を用意してデプロイを試してみます。以下のようなテンプレートを作成しましたが、重要なのは Zip Deploy を行う最後のリソースです。

{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "webAppName": {
      "type": "string",
      "metadata": {
        "description": "Base name of the resource such as web app name and app service plan"
      },
      "minLength": 2
    },
    "sku": {
      "type": "string",
      "defaultValue": "S1",
      "metadata": {
        "description": "The SKU of App Service Plan, by default is Standard S1"
      }
    },
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]",
      "metadata": {
        "description": "Location for all resources"
      }
    }
  },
  "variables": {
    "webAppPortalName": "[concat(parameters('webAppName'), '-app')]",
    "appServicePlanName": "[concat('ASP-', parameters('webAppName'))]"
  },
  "resources": [
    {
      "apiVersion": "2019-08-01",
      "type": "Microsoft.Web/serverfarms",
      "kind": "app",
      "name": "[variables('appServicePlanName')]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "[parameters('sku')]"
      }
    },
    {
      "apiVersion": "2019-08-01",
      "type": "Microsoft.Web/sites",
      "kind": "app",
      "name": "[variables('webAppPortalName')]",
      "location": "[parameters('location')]",
      "dependsOn": [
        "[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanName'))]"
      ],
      "properties": {
        "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanName'))]"
      },
      "resources": [
        {
          "apiVersion": "2019-08-01",
          "type": "extensions",
          "name": "zipdeploy",
          "dependsOn": [
            "[resourceId('Microsoft.Web/sites', variables('webAppPortalName'))]"
          ],
          "properties": {
            "packageUri": "https://shibayan.blob.core.windows.net/AspNetCoreApp.zip"
          }
        }
      ]
    }
  ]
}

Azure Portal から Template Deployment を使って実行すると、すんなりデプロイが完了しました。

f:id:shiba-yan:20191101115615p:plain

多少ははまるかなと思っていましたが、あまりにも簡単だったので拍子抜けです。

デプロイ後に Web App にアクセスしてみると、zip に含まれていたアプリケーションが実行されていました。

f:id:shiba-yan:20191101115838p:plain

これで問題なく Zip Deploy が ARM Template でも行えるようになっていることを確認できました。

Run From Package としてデプロイする

単なる Zip Deploy だけでは効果が薄いので、もちろん Run From Package としてデプロイしてみます。テンプレートは省略しますが App Settings に WEBSITE_RUN_FROM_PACKAGE = 1 を追加するだけなので簡単です。

テンプレートのデプロイ後に App Settings を確認すると、ちゃんと設定が追加されています。

f:id:shiba-yan:20191101120355p:plain

これだけだとわからないので、Kudu から Zip Deploy のログを確認します。Project Type が Run-From-Zip となっているので、ちゃんと Run From Package としてデプロイされていることが確認できました。

f:id:shiba-yan:20191101120345p:plain

もちろん Web App にアクセスすると、問題なくアプリケーションが実行されています。

f:id:shiba-yan:20191101120649p:plain

Web Deploy はパッケージを作るのすら面倒だったのと、デプロイが Atomic ではなく不安定になりがちだったので、Zip Deploy が使えるようになったのはとても嬉しいです。

Azure Functions + Run From Package でのデプロイ

最後に Zip Deploy と Run From Package が一番重要となる Azure Functions でも試しておきます。テンプレートは既に何回かブログでも書いてきたので、そっちを参照してください。

重要なのは Zip Deploy を実行する定義なので、それ以外は割とどうでもよい感じです。

一応 ARM Template 全体は Gist に載せておいたので、興味がある方は参照してください。

Azure Functions + Run From Package ARM Template sample · GitHub

このテンプレートを使って Azure Portal からデプロイしてみると、これもすんなり完了しました。

f:id:shiba-yan:20191101122611p:plain

デプロイされた Function を開いてみると、ちゃんと Read Only になっているので Run From Package としてデプロイされています。

適当に追加した HttpTrigger の Function も見えていますし、テスト実行も問題なく行えました。

f:id:shiba-yan:20191101122731p:plain

Consumption Plan の場合はリモートファイルを指定した Run From Package は起動時のオーバーヘッドが大きいので、自動でのアプリ更新が必要ない場合は ARM Template を使った Zip Deploy が良いと思います。

Linux への ARM 経由 Zip Deploy は未サポート

Linux Functions の Consumption Plan では Zip Deploy が必須ですが、まだ ARM Template を使ったデプロイは対応してませんでした。Pull Request はあったので、次のリリース時に対応されるようです。

Run From Package は Linux Functions でも使えるようになっていますが、ちゃんとしたドキュメントがまだ出ていない気もします。Premium Plan でも重要になってくるので、この辺りは改善を期待したいです。