App Service のスロットについて理解する

# App Service のスロットとは？

App Service には「スロット」と呼ばれる機能があり、運用中のアプリケーションと並行で新しいバージョンのアプリケーションを展開やテストしたり、入れ替えることが出来ます。

ドキュメントとしては以下のドキュメントに記載されていますが、実践的に使用する上でとっつきにくいのも事実なので、簡単ではありますが、動作をまとめます。<br/>
- [Azure App Service でステージング環境を設定する](https://learn.microsoft.com/ja-jp/azure/app-service/deploy-staging-slots)

# スロットはどのように実装されているのか？

ドキュメントには「デプロイ スロットは、固有のホスト名を持つライブ アプリです。」と書かれていますが、実際の配置としてはどのようになっているのでしょうか？

例えば運用スロットに追加して、stg1 という名前でスロットを作ったとします。
<img alt="デプロイ スロット" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/349915/e647b7a5-1d19-d522-1d9e-5517bdc29d92.jpeg" width=80% />


[Azure Resource Explorer](https://resources.azure.com/) を使用すると確認することが出来ますが、元のアプリケーションの配下に slots という要素があり、その配下にスロットは配置されます。
つまり、リソースとして完全に独立しているわけではないが、元のリソースに依存する、別の構成情報を持った子リソースとして作成されます。
<img alt="Resource Expolorer" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/349915/f8128038-9a78-bd42-22f9-9c797c7c3946.jpeg" width=50% />

App Service プランの観点から見ると、運用スロットは別に "slot" という種類で登録されていることが分かります。

<img alt="App Service プランから見たスロット" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/349915/5870db40-9b49-1ec2-fae2-c66a11d6197a.jpeg" width=80% />


つまり、App Service におけるスロットは「運用スロットに紐付いて作成された、独立したリソース」として見ることが出来ます。

App Service プランでも独立したリソースとして動作するため、それぞれサンドボックス (Windows の場合) やコンテナ (Linux, コンテナの場合) として動作します。
1 つの App Service プランで [複数のアプリケーションを動作させる場合と同様](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) に、スロットに配置や動作させるアプリケーションの数やリソース消費には注意が必要です。


# スロットについて理解を深める

スロットが、App Service プラン上で独立したアプリケーションとして動作している点はお話ししました。
では、スワップでアプリケーションを入れ替える際、どうやって切り替わるのでしょうか？運用スロットを停止してステージングスロットのアプリケーションをコピーしているのでしょうか？

App Service の [アーキテクチャを理解していると](https://learn.microsoft.com/en-us/archive/msdn-magazine/2017/february/azure-inside-the-azure-app-service-architecture) 難しくはないですが、裏では個別にスロットの内容を格納する「器」が用意されており、ホスト名 (~~~.azurewebsites.net) が書き換えられているだけです。

「高度なツール」から ***Environment*** で環境変数を探すと、"WEBSITE_DEPLOYMENT_ID" という項目がありますが、これが「器」を示す名前で、スロットを作成すると 「"__"+ 4桁の英数字」 という形で作成されます。
例えば App Service 作成時に作られる運用スロットでは以下のようになっています。
<img alt="運用スロット" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/349915/86003da4-609b-b2ba-2959-673673f2307c.jpeg" width=60% />

追加でステージングスロットを作成すると以下のように "__bbfb" という記号が追加されて作成されます。
<img alt="ステージングスロット" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/349915/9e403473-71e2-da20-5412-e0a16cb9bd96.jpeg" width=60% />

この「器」が各スロットで動作させるアプリケーションプールやサンドボックス、コンテナの実体です。
アプリケーション設定や \home\ 配下に配置されるファイルシステムなども全て独立しており、スワップを行うと入れ替えが行われます。

例えば、先の 2 つのスロットでスワップを行うと、器 (DEPLOYMENT_ID) は以下のように入れ替わることになります。
| スワップ回数 | 運用スロット | ステージングスロット|
|---|---|---|
|0回目| (無印) | 末尾__bbfb |
|1回目| 末尾__bbfb | (無印) |
|2回目| (無印) | 末尾__bbfb |
|3回目| __bbfb | (無印) |

ステージングスロットが複数あるとジャグリングのように入れ替わりますが、スロットの操作において、どの器の名前 (DEPLOYMENT_ID) を意識する必要はありません。
操作を行う時点で、どのスロットに対して操作を行ったか (あとで調べるなら操作を行った時刻) だけが重要です。


App Service に対してアクセスする場合も、要求先のホスト名に対して、App Service のフロントエンドがどのインスタンスで実行されているどのサンドボックス化を判断してルーティングを行います。
例えば webapps.azurewebsite.net に対する要求であれば、あるインスタンスの "webapps" というアプリケーションプール、サンドボックスに対して要求が転送されます。

<img alt="スワップ前" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/349915/ce8dc4da-2be0-711b-2c63-66c1297813b2.jpeg" width=80% />

スワップを行うと、運用スロットを提供する「器」は "__bbfb" に移行しますが、フロントエンドはスロットが入れ替わったことを認識しており、引き続き運用スロットを提供するサンドボックスに対して要求を転送します。

<img alt="スワップ後" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/349915/eafd312e-cb6e-73a1-617c-08ed31d7048c.jpeg" width=80% />


<!-- 
# スロットスワップについて

スロットスワップを実行すると、アプリケーションは再起動します。
これは、ステージングスロットから運用スロットに移行する際、アプリケーション設定 (環境変数) を始め、様々な構成情報をステージングスロットのものから運用スロットのものに置き換えるために必要な操作です。

旧・運用スロットから新・運用スロットへの切替はフロントエンドからのルーティング変更により実現されます。
アプリケーションの実行プロセス自体が別なので、メモリだけに持っているデータは引き継がれませんので、必要に応じて一般的な Web アプリケーションと同じく、複数アプリケーション間での何らかの永続化手段の使用を検討しましょう。


詳細は以下のドキュメントに記載があるのでご確認ください。
- [スワップ中の動作](https://learn.microsoft.com/ja-jp/azure/app-service/deploy-staging-slots#what-happens-during-a-swap)
-->

# スロットにおけるアプリケーション設定について

[構成] > [アプリケーション設定] では、「デプロイ スロットの設定」というチェックボックスがありますが、ここにチェックを入れるとどんな動作になるのでしょうか？

<img alt="アプリケーション設定、デプロイ スロットの設定" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/349915/f7ec7cd9-8f98-931b-9eb9-b95c8335cc6a.jpeg" width=50% />

「デプロイ スロットの設定」が有効になっている (マークが付いている) 場合、スロットスワップが行われても入れ替えは行わず、そのスロット (運用は運用のまま、ステージングはステージングのまま) 残ります。
表現がイマイチ定まっておらず、スロットに固定、スロットにピン留め等の表現が使用される場合もあります。

実際にスロットスワップを実行してみましょう。
ターゲットとなる、今動いている運用スロットのアプリケーション設定は以下のようになっています。
key1, key2 というアプリケーション設定を追加し、key2 だけ「デプロイ スロットの設定」を有効にしました。
<img alt="アプリケーション設定 運用スロット、スワップ前" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/349915/6484d0a2-d01b-72ed-feee-da06f254cb8b.jpeg" width=80% />

スワップのソースとなるスロット (今のステージングスロット) は以下のような設定になっています。
<img alt="アプリケーション設定 運用スロット、スワップ前" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/349915/b9e79f08-a57e-f8d1-d179-e64a6d062dee.jpeg" width=80% />

スワップを実行し、ステージングスロットを運用スロットに移動 (スワップ) しました。すると、アプリケーション設定は以下のようになりました。
<img alt="アプリケーション設定 運用スロット、スワップ前" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/349915/a88883bb-3128-98c6-3531-1ffed5c79265.jpeg" width=80% />
- WEBSITE_NODE_DEFAULT_VERSION はステージングスロットの「器」に紐付いており、スワップ時に移動してきた設定
- key2 は「デプロイ スロットの設定」が有効なため、スワップでも移動しない設定 (この場合、運用スロットに固定)
- ApplicationInsightsAgent_EXTENSION_VERSION はスワップで対象外とされている設定 ([サフィックス _EXTENSION_VERSION で終わる設定](https://learn.microsoft.com/ja-jp/azure/app-service/deploy-staging-slots#which-settings-are-swapped))

使い分けの例としては以下のようになります。
- 「デプロイ スロットの設定」でチェック ***する*** : 本番データベースへの接続情報のような、本番環境、開発環境固有の設定
- 「デプロイ スロットの設定」でチェック ***しない*** : アプリケーションの動作を決めるパラメータ (アプリの機能を有効化するフラグなど)


アプリケーション設定において、どのように設定するかはアプリケーション次第ですが、スロットに固定する (「デプロイ スロットの設定」でチェックする) ことを禁止しているパラメータもあるので注意が必要です。必ず、同期の動作を踏まえて判断しましょう。<br/>
  例: Azure Functions の [WEBSITE_CONTENTSHARE](https://learn.microsoft.com/ja-jp/azure/azure-functions/functions-app-settings#website_contentshare) : 各スロットのコードを格納するファイル共有名の指定なので、固定された場合コードが入れ替わらなくなる (ステージングスロットにデプロイしたコードをスワップしても、参照しているファイル共有が固定なので切替えできない)

# スロットの入れ替え
ポータルからスロットのスワップ操作を行うと、スワップでの入れ替えソースとターゲットでの変更点で表示されます。

以下が、新しいバージョンのアプリケーションが展開されたソースと、現行バージョンのアプリケーションが動作しているターゲットの入れ替えの例です。ソーススロットが使用していた [NetFrameworkVersion](https://learn.microsoft.com/ja-jp/azure/app-service/configure-language-dotnet-framework#show-current-net-framework-runtime-version) という構成値で古い値 v4.0 から v6.0 に変更される、アプリケーション設定の APPINSIGHTS_INSTRUM や key1 などが新しく設定されることを意味しています(スロット作成時に何もコピーしなかったためスロット間で差分が出てます)。
<img alt="スロットスワップの変更点" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/349915/d0b4eb23-5133-adb8-1fc4-323d89e6362a.jpeg" width=50% />

スワップ中の動作に関しては [ドキュメントに記載があります](https://learn.microsoft.com/ja-jp/azure/app-service/deploy-staging-slots#swap-operation-steps)。要点としては、ソースとして指定した (=新しく運用スロットに配置する) アプリケーションを運用スロットの設定で再起動し、HTTP での応答が開始された段階でルーティングが開始されます。
アプリケーションによっては「HTTP ポートは空いたので応答は開始されているが、アプリケーションはロードされていない (HTTP ステータスコード 404/500/502 応答)」という場合もありますが、そこまでは考慮されません (おそらく、これは「アプリケーションが開始された」という判断は実行するアプリケーションにより異なるため、判断する基準がないため)。

必要に応じて [プレビューでのスワップ (multi phase slot swap)](https://learn.microsoft.com/ja-jp/azure/app-service/deploy-staging-slots#Multi-Phase) を使用して、新しい運用スロットでの公開タイミングを調整しましょう。


# まとめ
上記で書いた内容をまとめると、一般的な利用範囲においては、おおよそ以下のようになります。
<img alt="スロットスワップによる" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/349915/206e88aa-4203-9fc5-ffa9-64ac29ffeed4.jpeg" width=90% />

スロットは活用すると非常に便利な機能ですが、一般的なアプリケーションサーバに標準的に搭載されている機能ではなく、若干とっつきにくい側面があります。
スロットでは「外部から確認できるホスト部分と、内部で実行するアプリケーションの部分で分離しており、スワップの度に入れ替わるという」ことを頭に入れておくと、理解しやすいかも知れません。

もっと細かい動作については記載がありますが、そちらは [ドキュメントに記載がある](https://learn.microsoft.com/ja-jp/azure/app-service/deploy-staging-slots#which-settings-are-swapped) のでそちらを確認してみてください。