web-dev-qa-db-ja.com

ゼロダウンタイムでASP.NETアプリケーションを展開する方法

Webサイトの新しいバージョンを展開するには、次の手順を実行します。

  1. 新しいコードを圧縮して、サーバーにアップロードします。
  2. ライブサーバーで、IIS Webサイトディレクトリからすべてのライブコードを削除します。
  3. 新しいコードzipファイルを空のIISディレクトリに解凍します

このプロセスはすべてスクリプト化されており、非常に迅速に行われますが、古いファイルが削除され、新しいファイルが展開されると、10〜20秒のダウンタイムが発生する可能性があります。

0秒のダウンタイム方法に関する提案はありますか?

126
Karl Glennon

2台のサーバーとロードバランサーが必要です。手順は次のとおりです。

  1. サーバー2のすべてのトラフィックを有効にする
  2. サーバー1に展開する
  3. テストサーバー1
  4. サーバー1のすべてのトラフィックを有効にします
  5. サーバー2に展開する
  6. テストサーバー2
  7. 両方のサーバーでトラフィックを有効にする

この場合でも、「スティッキーセッション」を使用している場合は、アプリケーションの再起動とセッションの損失が発生します。データベースセッションまたは状態サーバーがある場合は、すべて正常です。

79
Sklivvz

Microsoft Web Deployment Tool はこれをある程度サポートしています:

Windows Transactional File System(TxF)サポートを有効にします。 TxFサポートが有効な場合、ファイル操作はアトミックです。つまり、成功するか、完全に失敗します。これにより、データの整合性が確保され、データまたはファイルが「途中」または破損した状態で存在することが防止されます。 MS Deployでは、TxFはデフォルトで無効になっています。

トランザクションは同期全体のようです。また、TxFはWindows Server 2008の機能であるため、このトランザクション機能は以前のバージョンでは機能しません。

フォルダーをバージョンとして使用し、IISメタベース:0ダウンタイムのスクリプトを変更することは可能だと思います。

  • 既存のパス/ URLの場合:
  • 新しい(または変更された)Webサイトをの下のサーバーにコピーします。
    • \ web\app\v2.1 \
  • IISメタベースを変更してWebサイトのパスを変更します
    • from\ web\app\2.0 \
    • to\ web\app\v2.1 \

この方法には次の利点があります。

  • 新しいバージョンに問題がある場合は、v2.0に簡単にロールバックできます
  • 複数の物理サーバーまたは仮想サーバーに展開するには、ファイル展開用のスクリプトを使用できます。すべてのサーバーに新しいバージョンをインストールしたら、Microsoft Web Deployment Toolを使用して、すべてのサーバーのメタベースを同時に変更できます。
60
George Tsiokos

IIS異なるポート上の2つのローカルIISサイト間のソフトウェアロードバランサーとしてApplication Request Routingを利用することにより、単一サーバーでゼロダウンタイムの展開を実現できます。 blue greenデプロイメント戦略として知られ、2つのサイトのうち1つだけがロードバランサーで常に利用可能です。 「ダウン」し、ウォームアップし、ロードバランサーに持ち込んで(通常はApplication Request Routingヘルスチェックに合格して)、稼働していた元のサイトを「プール」から取り出します(ヘルスチェックを失敗させます) )。

完全なチュートリアルはここにあります。

10
kavun

私は最近これを経験しましたが、私が思いついた解決策は、IISに2つのサイトを設定し、それらを切り替えることでした。

私の構成では、AおよびBサイトごとに次のようなWebディレクトリがありました。c:\ Intranet\Live A\Interface c:\ Intranet\Live B\Interface

IISには、それぞれ独自のアプリケーションプールを持つ2つの同一のサイト(同じポート、認証など)があります。一方のサイトが実行され(A)、もう一方のサイトが停止されます(B)。ライブヘッダーには、ライブホストヘッダーもあります。

ライブにデプロイする場合は、STOPPEDサイトの場所に公開するだけです。ポートを使用してBサイトにアクセスできるため、最初のユーザーがアプリケーションを起動させないようにサイトを事前に暖めることができます。次に、バッチファイルを使用して、ライブホストヘッダーをBにコピーし、Aを停止してBを開始します。

7
Rob King

Microsoft.Web.AdministrationのServerManagerクラスを使用して、独自の展開エージェントを開発できます。

秘Theは、VirtualDirectoryのPhysicalPathを変更することです。これにより、古いWebアプリと新しいWebアプリがオンラインでアトミックに切り替わります。

これにより、古いAppDomainと新しいAppDomainが並行して実行される可能性があることに注意してください!

問題は、データベースなどへの変更を同期する方法です。

古いまたは新しいPhysicalPathsでAppDomainsの存在をポーリングすることにより、古いAppDomainが終了したとき、および新しいAppDomainが起動したかどうかを検出できます。

AppDomainを強制的に起動するには、HTTPリクエストを行う必要があります(IIS 7.5は自動起動機能をサポートしています)

次に、新しいAppDomainのリクエストをブロックする方法が必要です。名前付きミューテックスを使用します。これは、展開エージェントによって作成および所有され、新しいWebアプリのApplication_Startによって待機され、データベースの更新が行われると展開エージェントによってリリースされます。

(Webアプリでmutexの待機動作を有効にするためにマーカーファイルを使用します)新しいWebアプリが実行されたら、マーカーファイルを削除します。

7
Jack

OKだから、私が2008年に書いた答えを誰もが否定しているので...

2014年の現在の方法を説明します。現在ASP.NET MVCを使用しているため、Webサイトは使用していません。

ロードバランサーと2台のサーバーは必要ありません。維持するすべてのWebサイトに3台のサーバーがある場合は問題ありませんが、ほとんどのWebサイトでは完全に過剰です。

また、マイクロソフトの最新のウィザードに依存していません-遅すぎ、隠された魔法が多すぎ、名前を変更しがちです。

方法は次のとおりです。

  1. 生成されたDLLを「bin-pub」フォルダーにコピーするビルド後の手順があります。

  2. Beyond Compare(優れている**)を使用して、変更されたファイル(広くサポートされているFTP経由)を検証し、運用サーバーまで同期します。

  3. Webサイトには、「bin-pub」内のすべてを「bin」にコピーするボタンを含む安全なURLがあります(最初にバックアップを取り、クイックロールバックを有効にします)。この時点で、アプリは自動的に再起動します。次に、ORMは、追加する必要があるテーブルまたは列があるかどうかをチェックし、それらを作成します。

それはわずか数ミリ秒のダウンタイムです。アプリの再起動には1〜2秒かかりますが、再起動中はリクエストがバッファリングされるため、ダウンタイムは事実上ゼロになります。

展開プロセス全体には、変更されるファイルの数とレビューする変更の数に応じて、5秒から30分かかります。

この方法では、Webサイト全体を別のディレクトリにコピーする必要はなく、binフォルダーだけにコピーする必要があります。また、プロセスを完全に制御し、何が変化しているかを正確に把握できます。

**私たちは常に、展開中の変更を素早く確認します-最後の最後のダブルチェックとして、何をテストし、何かが準備できていないかどうかを確認します。 Beyond Compareを使用するのは、FTPを介してファイルを簡単に比較できるためです。私はBCなしではこれを決してしません、あなたはあなたが何を上書きしているのか分かりません。

*下にスクロールして表示してください:展開:マイナーな問題を非常にすばやく修正し、展開しているものを正確に確認できます(もちろん、Beyond Compareを使用している場合-それ以外の場合は忘れてください)。

6
mike nelson

考えられる唯一のゼロダウンタイムメソッドは、少なくとも2台のサーバーでホストすることです。

5
Sam Meldrum

これは私がそれを行う方法です:

絶対最小システム要件:
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
Stefan Steiger

Sklivvzの答えを拡張するには、何らかの種類のロードバランサー(または同じサーバー上の単なるスタンバイコピー)に依存していました。

  1. すべてのトラフィックをサイト/サーバー2に転送します
  2. 必要に応じて、デプロイされたバージョンで保留中のワークフローができる限り少ないユーザーになるように、少し待機します
  3. Site/Server 1にデプロイし、可能な限りウォームアップします
  4. データベースの移行をトランザクションで実行します(これを可能にするために努力します)
  5. すべてのトラフィックをすぐにサイト/サーバー1に転送します
  6. サイト/サーバー2に展開する
  7. 両方のサイト/サーバーにトラフィックを誘導する

データベースのスナップショット/コピーを作成することにより、少しのスモークテストを導入することは可能ですが、それが常に実行可能であるとは限りません。

可能であれば、異なるテナントURL:s(customerX.myapp.net)または異なるユーザーなどの「ルーティングの違い」を使用して、知らないモルモットのグループに最初に展開します。何も失敗しない場合は、全員にリリースします。

データベースの移行が関係しているため、多くの場合、以前のバージョンへのロールバックは不可能です。

これらのシナリオでは、イベントキューや再生メカニズムを使用するなど、アプリケーションをより適切に再生する方法がありますが、使用中の何かに変更を展開することについて話しているため、実際に確実な方法はありません。

1
gliljas

次のように、単一のサーバーについて、ジョージの答えを少し改良します。

  1. Web Deployment Projectを使用して、サイトを単一のDLLにプリコンパイルします
  2. 新しいサイトを圧縮して、サーバーにアップロードします
  3. サイトに適切なアクセス許可を持つフォルダー内にある新しいフォルダーに解凍し、解凍されたファイルがアクセス許可を正しく継承するようにします(おそらくe:\ web、サブフォルダーv20090901、v20090916など)
  4. IIS Managerを使用して、サイトを含むフォルダーの名前を変更します
  5. 古いフォルダーをしばらく保持して、問題が発生した場合にフォールバックできるようにします

手順4では、IISワーカープロセスがリサイクルされます。

InProcセッションを使用していない場合、これはゼロダウンタイムのみです。可能であれば、代わりにSQLモードを使用します(さらに良いのは、セッション状態を完全に回避することです)。

もちろん、複数のサーバーやデータベースの変更がある場合は、もう少し複雑になります。

1
RickNZ