ゼロダウンタイムでASP.NETアプリケーションを展開する方法
-
02-07-2019 - |
質問
新しいバージョンのWebサイトを展開するには、次の手順を実行します。
- 新しいコードを圧縮して、サーバーにアップロードします。
- ライブサーバーで、IIS Webサイトディレクトリからすべてのライブコードを削除します。
- 新しいコードzipファイルを空のIISディレクトリに抽出します
このプロセスはすべてスクリプト化されており、非常に迅速に行われますが、古いファイルが削除され、新しいファイルが展開されると、10〜20秒のダウンタイムが発生する可能性があります。
0秒のダウンタイム方法に関する提案はありますか?
解決
2台のサーバーとロードバランサーが必要です。手順は次のとおりです。
- サーバー2のすべてのトラフィックを有効にする
- サーバー1にデプロイ
- テストサーバー1
- サーバー1のすべてのトラフィックをオンにします
- サーバー2にデプロイ
- テストサーバー2
- 両方のサーバーでトラフィックを有効にする
「スティッキーセッション」を使用している場合、この場合でもアプリケーションの再起動とセッションの損失が発生します。データベースセッションまたは状態サーバーがある場合は、すべて正常です。
他のヒント
Microsoft Web Deployment Tool はこれをある程度サポートしています:
Windowsトランザクションファイルを有効にします システム(TxF)サポート。 TxFサポート時 有効、ファイル操作は アトミック;つまり、成功するか または完全に失敗します。これによりデータが保証されます 整合性とデータまたはファイルの防止 「中途半端」に存在することからまたは 破損した状態。 MS Deployでは、TxFは デフォルトでは無効になっています。
トランザクションは同期全体に対するもののようです。また、TxFはWindows Server 2008の機能であるため、このトランザクション機能は以前のバージョンでは機能しません。
フォルダーをバージョンとして使用し、IISメタベースを使用して、スクリプトを0ダウンタイムに変更することが可能であると考えています:
- 既存のパス/ URLの場合:
- パス:\ web \ app \ v2.0 \
- url : http:// app
- 新しい(または変更された)Webサイトをサーバーにコピーします
- \ web \ app \ v2.1 \
- IISメタベースを変更してWebサイトのパスを変更する
- from \ web \ app \ 2.0 \
- to \ web \ app \ v2.1 \
この方法には、次の利点があります。
- 新しいバージョンに問題がある場合、v2.0に簡単にロールバックできます
- 複数の物理サーバーまたは仮想サーバーに展開するには、スクリプトを使用してファイルを展開できます。すべてのサーバーが新しいバージョンになったら、Microsoft Web Deployment Toolを使用してすべてのサーバーのメタベースを同時に変更できます。
異なるポート上の2つのローカルIISサイト間のソフトウェアロードバランサーとしてIISのApplication Request Routingを利用することにより、単一サーバー上でゼロダウンタイムの展開を実現できます。これは、ブルーグリーン展開戦略として知られ、ロードバランサーでは常に2つのサイトのうち1つのみが利用可能です。 「ダウン」したサイトにデプロイし、ウォームアップし、ロードバランサーに(通常はApplication Request Routingヘルスチェックに合格することにより)持ってきて、「プール」から稼働していた元のサイトを取り出します。 (再びヘルスチェックを失敗させることにより)。
最近これを経験しましたが、私が思いついた解決策は、IISに2つのサイトをセットアップし、それらを切り替えることでした。
私の構成では、AおよびBサイトごとに次のようなWebディレクトリがありました。 c:\ Intranet \ Live A \ Interface c:\ Intranet \ Live B \ Interface
IISには、独自のアプリケーションプールを持つ2つの同一サイト(同じポート、認証など)があります。一方のサイトが実行され(A)、もう一方のサイトが停止されます(B)。ライブヘッダーにはライブホストヘッダーもあります。
ライブへのデプロイに関しては、STOPPEDサイトの場所に公開するだけです。ポートを使用してBサイトにアクセスできるため、最初のユーザーがアプリケーションを起動させないように、サイトを事前に暖めることができます。次に、バッチファイルを使用して、ライブホストヘッダーをBにコピーし、Aを停止してBを開始します。
Microsoft.Web.AdministrationのServerManagerクラスを使用すると、独自の展開エージェントを開発できます。
トリックは、VirtualDirectoryのPhysicalPathを変更することです。これにより、古いWebアプリと新しいWebアプリがオンラインでアトミックに切り替わります。
これにより、古いAppDomainと新しいAppDomainが並行して実行される可能性があることに注意してください!
問題は、データベースなどへの変更を同期する方法です
古いまたは新しいPhysicalPathsでAppDomainsの存在をポーリングすることにより、古いAppDomainが終了したとき、および新しいAppDomainが起動したかどうかを検出できます。
AppDomainを強制的に起動するには、HTTPリクエストを行う必要があります(IIS 7.5は自動起動機能をサポートしています)
ここで、新しいAppDomainのリクエストをブロックする方法が必要です。 名前付きミューテックスを使用します。これは、展開エージェントによって作成および所有され、新しいWebアプリのApplication_Startによって待機され、データベースの更新が行われると展開エージェントによってリリースされます。
(Webアプリでマーカーファイルを使用して、ミューテックス待機動作を有効にします) 新しいWebアプリが実行されたら、マーカーファイルを削除します。
OKですので、2008年に私が書いた答えを誰もが否定しているので...
2014年の現在の方法について説明します。現在ASP.NET MVCを使用しているため、Webサイトは使用していません。
ロードバランサーと2台のサーバーは必要ありません。維持するすべてのWebサイトに3台のサーバーがあれば大丈夫ですが、ほとんどのWebサイトでは完全に過剰です。
また、マイクロソフトの最新のウィザードに依存していません-遅すぎ、隠された魔法が多すぎ、名前を変更しがちです。
次のようにします:
-
生成されたDLLを「bin-pub」フォルダーにコピーするビルド後の手順があります。
-
Beyond Compare(優れた**)を使用して、変更されたファイル(広くサポートされているFTP経由)を検証し、運用サーバーまで同期します
-
「bin-pub」内のすべてを「bin」にコピーするボタンを含む安全なURLがWebサイトにあります(最初にバックアップを取り、クイックロールバックを有効にします)。この時点で、アプリは自動的に再起動します。次に、ORMは、追加する必要があるテーブルまたは列があるかどうかをチェックし、それらを作成します。
それはミリ秒単位のダウンタイムです。アプリの再起動には1〜2秒かかりますが、再起動中は要求がバッファリングされるため、ダウンタイムが事実上ゼロになります。
展開プロセス全体には、変更されるファイルの数とレビューする変更の数に応じて、5秒から30分かかります。
この方法では、ウェブサイト全体を別のディレクトリにコピーする必要はなく、binフォルダーにコピーするだけです。また、プロセスを完全に制御し、何が変化しているかを正確に把握できます。
**私たちは常に展開中の変更を素早く確認します-最後の最後のダブルチェックとして、何をテストするか、何か問題があれば準備ができているかを確認します。 Beyond Compareを使用する理由は、FTP経由でファイルを簡単に比較できるためです。私はBCなしではこれを決してしません。あなたが何を上書きしているのか分かりません。
*一番下までスクロールして確認してください:(ところで、Webサイトは構築が遅く、半分コンパイルされた一時ファイルでひどくクラッシュする可能性があるため、Webサイトはお勧めしません。ファイルごとの展開:マイナーな問題を非常にすばやく修正し、展開しているものを正確に確認できます(もちろん、Beyond Compareを使用している場合-それ以外の場合は忘れてください)。
私が考えることができる唯一のゼロダウンタイムの方法は、少なくとも2台のサーバーでホストすることです。
単一のサーバーについて、ジョージの答えを次のように少し改良します。
- Web Deployment Projectを使用して、サイトを単一のDLLにプリコンパイルします
- 新しいサイトを圧縮して、サーバーにアップロードします
- サイトに適切な権限を持つフォルダーにある新しいフォルダーに解凍します。解凍されたファイルは権限を正しく継承します(サブフォルダーv20090901、v20090916などを含むe:\ webなど)。
- IISマネージャーを使用して、サイトを含むフォルダーの名前を変更します
- 古いフォルダをしばらく保持して、問題が発生した場合にフォールバックできるようにします
ステップ4により、IISワーカープロセスがリサイクルされます。
InProcセッションを使用していない場合、これはゼロダウンタイムのみです。可能であれば、代わりにSQLモードを使用します(さらに良いのは、セッション状態を完全に避けることです)。
もちろん、複数のサーバーやデータベースの変更がある場合は、もう少し複雑になります。...
sklivvzの答えを拡張するには、何らかの種類のロードバランサー(または同じサーバー上のスタンバイコピー)に依存していました
- すべてのトラフィックをサイト/サーバー2に転送します
- オプションで少し待機し、展開されたバージョンで保留中のワークフローができる限り少ないユーザーになるようにします
- サイト/サーバー1にデプロイし、可能な限りウォームアップします
- トランザクションでデータベース移行を実行します(これを可能にするために努力します)
- すべてのトラフィックを直ちにサイト/サーバー1に転送します
- サイト/サーバー2にデプロイ
- トラフィックを両方のサイト/サーバーに転送する
データベースのスナップショット/コピーを作成することで、少しの煙テストを導入することは可能ですが、それは常に実行可能ではありません。
可能であれば、異なるテナントURL:(customerX.myapp.net)や異なるユーザーなどの「ルーティングの違い」を使用して、知らないモルモットのグループに最初に展開します。何も失敗しない場合は、全員にリリースします。
データベースの移行が関係するため、以前のバージョンへのロールバックは不可能な場合がよくあります。
これらのシナリオでは、イベントキューや再生メカニズムを使用するなど、アプリケーションをより適切に再生する方法がありますが、使用中の何かに変更を展開することについて話しているため、実際に確実な方法はありません。
これは私がやる方法です:
絶対最小システム要件:
1台のサーバー
- ポート80で実行されている1つのロードバランサー/リバースプロキシ(nginxなど)
- 2つの異なるTCPポートでリッスンする2つのASP.NET-Core / mono reverse-proxy / fastcgi chroot-jailsまたはdocker-containers
(または、サンドボックスなしの2つの異なるTCPポートで2つのリバースプロキシアプリケーションでさえ)
ワークフロー:
トランザクションmyupdateを開始
try
Web-Service: Tell all applications on all web-servers to go into primary read-only mode
Application switch to primary read-only mode, and responds
Web sockets begin notifying all clients
Wait for all applications to respond
wait (custom short interval)
Web-Service: Tell all applications on all web-servers to go into secondary read-only mode
Application switch to secondary read-only mode (data-entry fuse)
Updatedb - secondary read-only mode (switches database to read-only)
Web-Service: Create backup of database
Web-Service: Restore backup to new database
Web-Service: Update new database with new schema
Deploy new application to apt-repository
(for windows, you will have to write your own custom deployment web-service)
ssh into every machine in array_of_new_webapps
run apt-get update
then either
apt-get dist-upgrade
OR
apt-get install <packagename>
OR
apt-get install --only-upgrade <packagename>
depending on what you need
-- This deploys the new application to all new chroots (or servers/VMs)
Test: Test new application under test.domain.xxx
-- everything that fails should throw an exception here
commit myupdate;
Web-Service: Tell all applications to send web-socket request to reload the pages to all clients at time x (+/- random number)
@client: notify of reload and that this causes loss of unsafed data, with option to abort
@ time x: Switch load balancer from array_of_old_webapps to array_of_new_webapps
Decomission/Recycle array_of_old_webapps, etc.
catch
rollback myupdate
switch to read-write mode
Web-Service: Tell all applications to send web-socket request to unblock read-only mode
end try
古いファイルはそのままにして、単に上書きすることをお勧めします。これにより、ダウンタイムは単一ファイルの上書き時間に制限され、一度に1つのファイルしか失われなくなります。
これが&quot;ウェブアプリケーション&quot;に役立つかどうかわからないしかし(私はあなたがそれを使用していると言っていると思います)、それが私たちが常に「ウェブサイト」を使用する理由です。また、「ウェブサイト」でもデプロイしてもサイトが再起動されず、すべてのユーザーセッションが削除されません。