PaaS はいいぞ！～IaaS を使ってる人のための Azure App Service～

# はじめに
[Microsoft Top Partner Engineer's Advent Calender 2023](https://japan.zdnet.com/extra/ms_202311/35211313/
) の記事です。

https://japan.zdnet.com/extra/ms_202311/35211313/

フリーランス時代から現在まで、数々のプロジェクトを通じて企業システムをいくつも見てきましたが、世の中はまだまだ IaaS を活用しているプロジェクトが大多数であるという印象があります。
つい最近もガバメントクラウドへの移行で単純にコストが上がったという記事をみかける機会もあり、オンプレミスの延長線上でクラウドでの選択肢を IaaS としている限りは諸々の制約も引き継いでしまい、どうしてもそうなってしまうよなぁと感じています。
 
しかし、ここで IaaS ではなく PaaS を使うことで少し違った展開が期待できます。
 
インフラやサーバーに関する責任の大部分はクラウド事業者に一任でき、開発者は本質的であるシステム開発に注力することができます。
プロジェクト全体として見ても、OSやミドルウェアに関わるパッチ作業、各ミドルウェアの EOL 対応、バージョンアップ作業など気にしなくても良くなるため、そのような諸々のコストが削減できることの意義は大きいです。

そんな PaaS の中でも、今回は Azure の PaaS で代表的なサービスである Azure App Service について説明します。
※実際には Terraform などの IaC や CI/CD でのデプロイなどありますが今回のスコープ外として割愛します。


# Azure App Service について

[Azure App Service](https://azure.microsoft.com/ja-jp/products/app-service) はフルマネージド PaaS であり、インフラや OS、ミドルウェアに関わる部分のほとんどがメンテナンスフリーとなっています。

OS、ミドルウェア、Runtime などが最新化された一連の環境がわずか数分間で作成できます。



# Azure App Service のここが良い


## メンテナンスフリー
何といっても一番のメリットはここです。
OS や Webサーバーミドルウェア、Runtime のメンテナンスが不要です。
気にするのは OS の種類と Runtime のバージョンだけでよく、パッチバージョンは自動的に更新されます。

このメリットは絶大です。
IaaS で管理しているシステムだとほとんどはリリース後はパッチバージョンすらアップデートされず、
リリース時以降一度もアップデートしていないという現象をよく見てきています。

特に納品するタイプは「作って終わり」なことが多く、この傾向にあります。
聞くところによると、いまだに Windows Server 2000 が動いている環境もあるとか。
※さすがにこれは閉域でインターネットとは一切つながらないらしいですが…。

あまり気にしてはいないですが、App Service の場合は月に1回程度メンテナンスされてるようです。

## 追加費用がない
ちょっと語弊がありますが、App Service 自体には料金がかかりません。
費用がかかるのは、App Service プランのほうになります。

わかりやすくざっくりとイメージで書けば、以下のような感じです。

| Azure 上の名称 | 概念 |
|---|---|
| App Service プラン | 1 つの仮想マシン |
| App Service | サーバー内で動作するコンテナ |

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16817/162dd8c9-a101-3a76-cef6-e21953fb8ab1.png)

そのため、1 つの App Service プランに紐づけている限り、App Service の数が増えても追加コストはかかりません。

もちろん、App Service ごとに CPU やメモリを消費するので、そういった意味では有限です。
App Service プランの SKU ごとの推奨アプリ数は以下に記載されています。

https://learn.microsoft.com/ja-jp/azure/app-service/overview-hosting-plans#should-i-put-an-app-in-a-new-plan-or-an-existing-plan

この「アプリ数」は後述するデプロイスロット数も含めたものですが、この範囲内であれば別システムでも追加コストなしで稼働できます。
AWS の ECS であればコンテナを増やせば増やした分だけ追加コストがかかってしまいますが、こちらはそういうことがないのが気に入っています。
さらに、LoadBalancer に相当する部分も内包されています。
これを意識せずに使えるようになってるのは割とすごいのではないかと感じています。



## 環境の複製が楽

App Service にはデプロイスロットという概念があります。

https://learn.microsoft.com/ja-jp/training/modules/understand-app-service-deployment-slots/

1つの App Service から派生して、プレビュー環境、ステージング環境を簡単に構築可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16817/a26ebd58-f3c3-6c3a-b76b-4d242df3f426.png)

環境変数を引き継ぐかどうかも設定できるので、同じ設定値の環境を簡単に増やすことができます。
また、デプロイスロットにも固有のドメインが割り振られるため、
あとは開発するアプリケーションをデプロイするだけで同じ環境が構築できます。

なお、スロットごとに環境変数やスタックの設定ができるため、
フレームワークのバージョンアップの際、バージョンアップ時の事前確認用に同じ環境を用意して
確認が終わったら破棄という特定用途確認用環境も楽になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16817/ee895838-dda1-319c-4212-7c578b8e8fd6.png)

これは IaaS だとなかなかに大変な作業かと思います。
インフラに関わる業務のタスクを減らしてくれるのも PaaS の大きなメリットです。

しかも、先述したとおり App Service の数による追加コストはないため、
稟議などの心配をせずとも簡単に増やせるのも大きなメリットです。



## ブルーグリーンデプロイが楽
デプロイスロットの大きな効果ですが、ブルーグリーンデプロイが非常に簡単に実行できます。

本番リリース前はプレビュー環境のデプロイスロットにデプロイし、事前確認を行います。
事前確認が環境すると「スワップ」を行えばゼロダウンタイムでの本番リリースが実現できます。
※ DB スキーマに変更があった場合は気をつけないといけないこともありますが、それは今回の範囲外とします

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16817/4c1f6474-a6cd-6daa-6e01-41354a88ba7a.png)

本番リリース後、問題が発覚した場合は切り戻し対応を行うこともあると思います。
その場合も「スワップ」を行うだけで切り戻し可能です。

「スワップ」による切り戻しの簡単さは本番リリースに対する精神的負荷を下げることができます。
結果、本番リリースのサイクルも短くすることができ、価値の提供につながっていきます。

また、ブルーグリーンデプロイだけではなく、一部のユーザーにのみ新機能を提供する「カナリアリリース」を行うこともできます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16817/fd8f1245-e4e0-2ce7-94dc-254ef320c102.png)


Azure Portal から設定を変更し、「保存」を押すことでカナリアリリースが完了します。
とても簡単ですね。


## アプリケーションの自動バックアップ
特に意識することなく、1時間ごとの自動バックアップがついています。
幸いにして、今までこの機能を利用したことはないのですが、何かあったときにすぐに戻せるのは良いと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16817/5f9b3e7d-86e4-43a1-f395-8c1b6d91884e.png)

しかも、戻すときには新しいデプロイスロットを作ってそちらに復元することも可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16817/a8ebdf4e-d000-6a2a-54aa-046c1e14f116.png)

あの時の挙動どうだったっけ？というような時にサクッと復元して確認して削除というようなこともできそうです。



## デプロイが楽
実際の運用では CI/CD を使うと思いますので自動デプロイをするかと思います。
しかし、簡単なテストプロジェクトではそこまでする必要はないという場面もあります。

そういった時には、Visual Studio、もしくは、Visual Studio Code からデプロイができます。
※ C#（ASP.NET Core） のデプロイ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16817/8ee96fe1-d96b-c548-1fbd-c038fe664dea.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16817/abc2f396-4698-c678-4521-62dbcf83c7b5.png)

GUI からデプロイができるのは楽で、必要なのは Microsoft Entra ID と App Service へのロールのみです。


## クラウドベンダーロックインしない
昨今はクラウドベンダーロックインが話題に上がることが増えています。
App Service も Azure 上で提供されているため、利用する限りはベンダーロックインするのではないかという懸念はあるかと思います。
実際、そういった懸念から IaaS を選択しているケースもあるでしょう。

しかし、App Service は実は Kubernetes の環境さえあれば、オンプレミス環境も含めてどの環境でも利用することができるようになってます。

https://www.publickey1.jp/blog/21/azure_functionsazure_app_serviceawsgoogle_cloudkubernetesmicrosoft_build_2021.html

Microsoft Learn やドキュメントもありますので、やるだけならそんなに難しくはなさそうです。

https://learn.microsoft.com/ja-jp/training/modules/configure-application-kubernetes-arc/

https://learn.microsoft.com/ja-jp/azure/app-service/manage-create-arc-environment?tabs=bash

Kubernetes のメンテナンスをするのは大変なため、初手でわざわざ他の環境で App Service を構築することはありませんが、最悪でもオンプレミスなどに展開できるというのは安心感があります。

結局 Azure Arc は必要なのでそこがロックインするんじゃないかと言われる可能性はありますが、




# はまったところ
書いたついでなので、逆に App Service でハマったポイントも書いておきます。


## RBAC な Key Vault 参照でエラー
App Service には環境変数が設定できますが、これを KeyVault を利用して間接参照する方法があります。

https://learn.microsoft.com/ja-jp/azure/app-service/app-service-key-vault-references?tabs=azure-cli

最近の Key Vault は RBAC が推奨されているため、こちらでアクセス制御を行います。
この時、システムマネージド ID に対して直接ロール付与するのではなく、
Microsoft Entra グループに対してロール付与していた場合、タイミングによっては App Service からの参照時にエラーとなります。

例）
1. 環境変数に Key Vault参照を設定する
1. システムマネージド ID を作成する
1. KeyVault への参照ロールが付与された MEID グループに App Service のシステムマネージド ID を追加する

この時、1. の時点で Key Vault へ問い合わせを行ってしまい、エラーとなっていることがあります。
この状態で 3. まで進むとエラー発生時のトークンが最大 24 時間キャッシュされてしまい、どうやってもエラーのままとなります。
こちらは既にバグ報告済で修正予定となっておりますが、いつ修正されるかは不明です。

取り急ぎの解決策としては **システムマネージド ID に対して直接ロールを付与** です。
正直、同じ手順をやったのに App Service ごとにバグが出たりでなかったりするので厄介です。
問い合わせ時の再現も大変でした。



## NAT Gateway を通じて外部のストレージアカウントに接続できない
他テナントで管理しているストレージアカウントに対し接続させたいという要件が出てきた時のことです。
やりたいことは以下のようなものでした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16817/1d16c033-aca1-8491-727f-22657616f32f.png)

App Service 自体はパブリック IP は変わりうるもので固定化できないため、NAT Gateway の IP アドレスを使って許可しました。
この構成は検証環境では接続がうまくいき、無事にテスト完了しました。

ところが、いざさらに別テナントにあるプレビュー環境にデプロイしてみるとエラーとなって接続ができません。
※弊社は検証環境と本番・プレビュー環境は完全に分離して別テナントとして管理しています

同じ構成なのに挙動が異なる現象に悩まされましたが、ストレージアカウントのログを確認して **プライベート IP で接続されている** ことが原因だということが判明しました。

こちらをサポートに問い合わせしたところ、仮想ネットワーク A 側のサービスエンドポイントを無効化するしかないとのことでした。
Azure 側で割り当てられた物理ホストの環境により NAT Gateway を利用するかサービスエンドポイントを利用するかが分岐するとのこと。
代替案として、サービスエンドポイントを無効化して仮想ネットワーク内へのアクセスを[プライベートリンク](https://learn.microsoft.com/ja-jp/azure/private-link/private-link-overview)にする方法も案内されましたが、追加コストなしで利用できるサービスエンドポイントの代替になるとはとても思えませんでした。


結果的に、仮想ネットワーク B 上の該当ストレージアカウントに対して、仮想ネットワーク A のサブネットを許可設定していただくことで接続可能となりました。

この方法は Azure Portal からは行うことができず、Azure CLI を利用する必要があります。

```
az storage account network-rule add --resource-group "{resource-group-name}" --account-name "{Storage-account-name}" --subnet subscriptions/{subscription-id}/resourceGroups/{resource-group-name}/providers/Microsoft.Network/virtualNetworks/{vnet-name}/subnets/{snet-name}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16817/af92bfb4-bca6-b0d9-81f8-52dbdcf339e5.png)


見た目は変な感じで Warning も出てますが、無事に接続は出来ています。



物理サーバーによって NAT Gateway を利用するかサービスエンドポイントを利用するかが変わるのはつらみがあります。
App Service はメンテナンスによって、定期的に物理サーバーが移動します。
移動のためにどちらの挙動になるかはわからなかったため、NAT Gateway 用の IP アドレス許可、および、仮想ネットワークの接続許可の両方を設定して運用しています。



# さいごに

PaaS は IaaS に比べてインフラ回りや OS、ミドルウェア等のパッチ対応のタスクが削減されます。
単純に利用料を比較するなら IaaS よりも PaaS のほうが高くなる傾向にありますが、
その分インフラエンジニア側のタスクが減るため、インフラエンジニアが 1 人で対応できるシステム数が増えます。
削減できるインフラエンジニアの工数を考えると PaaS のほうが安くなるのではないかと考えています。


結果、少ない人数でも安定したシステムの稼働が可能となり、より本質的な部分に注力することができるようになります。
そして何よりも「考えなければならないことが減る」、言い換えれば「考えなくても良いことが増える」ことの快適さは良いです。

オンプレ → IaaS の時の理解に比べ、IaaS → PaaS はまだあまり理解されていない印象があります。
実際に私も PaaS を使い始めるまではなんとなくでしか理解できていませんでした。

まずは使ってみて PaaS を体感してみるのをおすすめいたします。
PaaS はいいぞ！