App Service の実行時環境についてのFAQのごく一部を書きます

# この記事について

Azure App Serviceの全体アーキテクチャについてはかなり昔に書かれた[このドキュメント](https://docs.microsoft.com/en-us/archive/msdn-magazine/2017/february/azure-inside-the-azure-app-service-architecture)が参考になります(今とはいろいろ違っていますが、基本は同じです)が、このドキュメントには実行時環境(ランタイム)についてはあまり触れられていません。ずいぶん昔に私が日本で登壇して話したことがあるものの、公式ドキュメントにはあまり説明がないんですよね。そのせいか、ときどきサポートリクエストにランタイムに関する質問が（なぜか日本からが多いらしい）来ているようです。ランタイムの挙動について網羅しようとすると本が一冊書けるくらいになってしまうので、ここでは数点だけに絞って書いておきます。

### 参考ドキュメント

次節以降の説明は、このドキュメントを見ながら読むと理解が進むと思います。

- https://docs.microsoft.com/en-us/archive/msdn-magazine/2017/february/azure-inside-the-azure-app-service-architecture

### Webアプリが動いているマシンが再起動したらどうなるの？

ものすごく簡単に書くと、**ユーザは何もせずに別のマシンが自動的に割り当てられます**。以下もう少し詳しく説明します。

まず前提として、すべてのWebアプリは、**ワーカー**と呼ばれるマシン上で実行されます。各スケールユニット内には多数のWindowsとLinuxのワーカーがあり、App Service Planの種類とインスタンス数に応じて適宜割り当てられています。ワーカーの前段には**フロントエンド**と呼ばれる、いわゆるリバースプロキシがあります。フロントエンドはすべてWindows+IISです。

さて、ワーカー自身は様々な理由から再起動されます。OSの更新とプラットフォームコードの更新が理由であることが多いです。あるワーカー上でWebアプリが実行中に再起動が要求されると、それ以降フロントエンドはHTTPリクエストをそのワーカーには送らなくなります。ただしすでに処理中のリクエストの処理は続行します(いわゆるGraceful shutdownです)。

この後あるタイミングを境目にして、プラットフォームはアイドル状態のワーカーをApp Service Planに新たに割り当て、フロントエンドがそのワーカーにHTTPリクエストを送ります。リクエストを受け取ったワーカーはそのWebアプリ用をホストする環境を動的に構築します（**コールドスタート**）。具体的には、Windows (というかIIS)ではApplication poolを割り当て、各種コンフィグファイルを生成し、ディレクトリをマウントして、w3wp.exeを起動します。ランタイムの種類に応じてさらに子プロセス(例: node.exe)を起動し、ユーザアプリを実行開始します。ここまで完了するまでは、受け取ったHTTPリクエストはhttp.sys内で留め置かれます。何らかの理由でアプリを開始できない、あるいはアプリが一定時間以内にレスポンスを返せない場合、プラットフォームは503のステータスコードを返します。Linuxではnginxとdockerを使っていますが、基本はとても似ています。

というわけなので、マシンがいつ再起動しようと、理想的にはダウンタイムは発生しません。特にアプリが十分速く起動するように書かれている場合はコールドスタートの時間も短くなります。ただし現実にはいろいろな要素が関係してきますので、そこまで簡単ではありませんが。

さらに、マシンが再起動されなくてもw3wp.exeが再起動されることがあります。たとえばストレージ接続が一時的に不安定になったり、App Settingを変更した場合などです。

### 複数インスタンスを使うとき、ディスクは共有される？

はい、共有されます。各Webアプリのディスク領域はワーカーがSMBマウントして提供しています。なので、あるインスタンスがファイルを更新したとき、その最新の内容は他のインスタンスから即座に参照可能です。便利。ただし複数のインスタンスから同時に同じファイルに書き込むと、当然問題が起きます。プラットフォーム側が自動的に作成するファイル、例えばHTTPログなどは衝突しない名前が自動的に付けられますが、アプリ側では適切にファイル名を生成する必要があります。

### Kuduってどうやって動いてる？

Gitからのデプロイやシェルのセッションで多用するKudu (ドメイン名が``*.scm.azurewebsites.net``)は、やや特殊ながらも1個の独立したWebアプリです。特殊なのは、メインのWebアプリの各種設定およびディスク領域を共有していることです。ただしあくまでも1個の独立したWebアプリ(つまり別のw3wp.exe)なので、**Kuduを起動するためには各種リソース(CPU、メモリ、ネットワーク帯域)をメインアプリとは別に消費します**。これは次の項目とも関連していまして、とても重要です。

### 1つのApp Service Plan内のアプリはどうやって配置される？

App Service Planとは、ひたらく言えば使いたいワーカーのスペックと個数です。デフォルトの挙動では、それらのワーカーすべてが、すべてのWebアプリをホストします。このワーカーではこのアプリだけ、という風にはなりません。
さて、Standard以上のSKUであれば、App Service Plan内に配置可能なアプリ数に上限はありません(2019年12月現在)。ただし、それはあくまで上限がないだけであり、何個あっても問題ないという意味ではありません。なぜなら、当たり前ですが、**各マシンにはCPU、メモリ、ネットワーク帯域の上限がある**からです。S1 (Standardの一番小さいVM)上で、Javaで書かれた重いWebアプリが100個同時に問題なく動き続けるでしょうか？無理ですよね。それに加えてKuduが起動されると、ものすごいことになります。

「そんなことするわけないじゃん」と思われるかも知れません。でも実際に30個くらいのアプリがS1にデプロイされているケースは多々あります。しかもそれらのアプリのほぼすべてでKuduが起動していて、実質倍の60個くらいのw3wp.exeが悲鳴を上げていることも稀ではないです。

お勧めは、あまり多数のアプリを1つのApp Service Planに詰め込まず、クリティカルなワークロードを処理するアプリは独立したApp Service Planに移すことで安定性を上げることができます。[ここ](https://docs.microsoft.com/ja-jp/archive/msdn-magazine/2017/february/azure-inside-the-azure-app-service-architecture#controlling-density)にちょろっと書いてあるので、ご一読をお勧めいたします。ちなみに現在は、ポータルから新規にアプリを作成する場合、すでに多数のアプリがApp Service Planにある場合は警告が表示されるようになっています。

## まとめ

年末の休みになったので、思い立ってFAQのごくごく一部を書きました。少しでも参考になれば幸いです。