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


127

私たちのウェブサイトの新しいバージョンを導入するために、私たちは次のことを行います:

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

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

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


これはServerFaultにあるべきではありませんか?
ダニエルロドリゲス

49
おそらく、ServerFaultは2008
Karl Glennon

3
IISはsymlinkフォルダーを指すことができますか?シンボリックリンクを変更すると、IISプロセスがリサイクルされますか?
Neil McGuigan、

完全なソースコードスクリプトサンプルを使用した最終的なソリューションはありますか?
Kiquenet

複数のアプリプールを用意して、トラフィックを1つのアプリプールから別のアプリプールに切り替えることはできませんか?
ルーク

回答:


79

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

  1. サーバー2のすべてのトラフィックをオンにする
  2. サーバー1にデプロイ
  3. テストサーバー1
  4. サーバー1のすべてのトラフィックをオンにする
  5. サーバー2にデプロイ
  6. テストサーバー2
  7. 両方のサーバーでトラフィックをオンにする

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


4
ロードバランサーを構成して、特定のサーバーの既存のセッションを処理するが、新しいセッションは受け付けないようにすることもできます。これにより、セッションのドロップを回避できます。ただし、この手法では、セッションが終了するまで待機する必要があり、通常はこれをスクリプト化する必要があります。

35
この方法は、コードロールでデータベースの構造が変更されたときに低下する傾向があります。サーバー1のDBをアップグレードすると、サーバー2が爆発します。これで、サーバー1でテストするためにデータベースをバックアップ/復元できますが、並列コピーの実行中にライブDBで変更されたデータを整理するという問題が発生します。
EBarr 2010

1
@AndreiRinea-これが大量のOLTPシステムで機能するとどう思いますか?システムが同期しなくなり、カットオーバー時にデータが失われるか、一時的なデータを識別して新しいDB構造に移行するためのデータ入力を一時停止してスクリプトを作成する必要があります。
EBarr

9
@EBarr:技術的には、ASP.NETアプリのダウンタイムは技術的にはまだゼロです。問題は、「ダウンタイムなしでSQLサーバーデータベースにデプロイする方法」ではありません。
Sklivvz、2011年

6
彼らの鍵は、SQLの変更が破壊的でない方法で開発することです。次のリリースでは、使用されなくなったSQLの破壊的な変更を行う必要があることがよくあります。練習するのは難しくありません。
Bealer

60

マイクロソフトWeb配置ツールは、ある程度、これをサポートしています。

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

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

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

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

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

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

5
私は、Powershellデプロイメントスクリプトを適応させることにより、このアプローチを実装しました。IISサイトフォルダーを変更するスクリプトの一部をここで確認できます:stackoverflow.com/questions/330608/… ポインターをありがとう
Karl Glennon、

17
残念ながら、この方法はDBの構造的な変更を考慮していません。DBをv2.1にアップグレードすると、v.2.0が爆発します。
EBarr 2010

8
IMO、TxFの使用はここではやりすぎです。ファイルシステムにv2.0とv2.1の両方を同時に使用しても問題はありません。大きな変化は、v2.1がオンラインになり、その時点でTxFトランザクションがコミットされたときに発生します。IISがTxFのためではなく、古いAppPoolから新しいAppPoolに移行する方法が原因で、ダウンタイムがゼロになります。
RickNZ 2010

5
これに関する別の問題は、大量のユーザーデータがアプリフォルダーのサブフォルダーに保存されている場合です。
ケニーエビット2011

4
新しいアプリを起動する必要があるため、これは0秒の展開ではありません。
2015年

12

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

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


7

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

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

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

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


1
これは、ファイルのコピーによるダウンタイムの改善に役立ちますが、@ Sklivvzと同じ問題があります-コードロールがデータベースの構造的な変更を行うとすぐに、サイトはブームになります。
EBarr 2010

これは私にとっても直感的な方法のように思えましたが、なぜこれを行う簡単な組み込みの方法がないのですか?
Petrus Theron

3
@Ebarrは破壊的なSQLの変更をロールアウトしません。あなたが列を削除する必要がある場合、それはもはやAまたはBで使われているとき、例えば、次のリリースでは、そうしない
Bealer

@Bealer-同意(警告あり)。「コードの役割中のダウンタイム」に関する一連の質問がすべてあります。私は、DBスキーマの進化の現実を本当に論じているものをまだ見つけていません。警告-スキーマに対する2段階の変更に伴い、さまざまな複雑な問題が発生します。1つの例-テーブルの定義が理解している定義(新しい列または欠落している列)と異なる場合、ORMの多くが無効になります。
EBarr 2013

2
@Rob停止しているサイトをどのように「事前ウォーム」することができますか?
Andrew Gee

7

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

トリックは、VirtualDirectoryのPhysicalPathを変更することです。これにより、古いWebアプリと新しいWebアプリの間でオンラインのアトミックスイッチが発生します。

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

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

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

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

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

(Webアプリでマーカーファイルを使用して、ミューテックス待機動作を有効にします)新しいWebアプリが実行されたら、マーカーファイルを削除します。


6

だれもが答えを反対投票しているので、私は2008年に書き戻しました* ...

今は2014年にその方法を説明します。現在ASP.NET MVCを使用しているため、Webサイトは使用しなくなりました。

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

また、マイクロソフトの最新のウィザードには依存していません。速度が遅く、隠された魔法が多すぎて、名前を変更する傾向があります。

以下がその方法です。

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

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

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

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

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

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

**私たちは常に、展開している変更をすばやく目で確認します-土壇場でのダブルチェックとして、何をテストすべきか、何か問題がある場合は準備ができているかどうかを知っています。FTP経由でファイルを簡単に比較できるので、Beyond Compareを使用します。私はBCなしではこれを行うことはありません。あなたは何を上書きしているのか分かりません。

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


ただし、アプリプールがリサイクルされるため、ダウンタイムが発生します。
テストパターン2016年

いいえ、アプリの再起動中にIISによってリクエストが自動的にバッファリングされるため、ダウンタイムはありません
Mike nelson


1

次のように、単一のサーバーに対してジョージの回答を少し洗練させます。

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

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

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

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


1
@Sklivvzと同じ問題-この方法は、コードロールでデータベースの構造が変更されるとすぐに失敗します。
EBarr 2010

3
そのため、DBの変更がある場合には、より複雑であると述べました... DBの構造的な変更を伴うコードのロールアウトは、デプロイメントの問題だけではありません。コード、そしておそらくDBでもサポートが必要です。
RickNZ 2010

1

何らかの種類のロードバランサー(または同じサーバー上のスタンバイコピーのみ)に依存するsklivvzの答えを拡張する

  1. すべてのトラフィックをサイト/サーバー2に転送する
  2. オプションで少し待機して、デプロイされたバージョンで保留中のワークフローを持っているユーザーをできるだけ少なくする
  3. サイト/サーバー1にデプロイし、可能な限りウォームアップします
  4. データベースの移行をトランザクションで実行する(これを可能にするために努力する)
  5. すべてのトラフィックをサイト/サーバー1に直ちに転送します。
  6. サイト/サーバー2に配置
  7. 両方のサイト/サーバーに直接トラフィック

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

可能で必要な場合は、さまざまなテナントURL(customerX.myapp.net)またはさまざまなユーザーなどの「ルーティングの違い」を使用して、最初に無知のモルモットのグループに展開します。何も失敗しない場合は、全員に解放します。

データベースの移行が含まれるため、以前のバージョンにロールバックすることは、多くの場合不可能です。

イベントキューや再生メカニズムを使用するなど、これらのシナリオでアプリケーションをより快適に再生する方法はありますが、使用中のものへの変更のデプロイについて説明しているため、実際に間違いのない方法はありません。


1

これが私のやり方です:

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

-7

古いファイルはそのままにして、単に上書きすることをお勧めします。このようにして、ダウンタイムは単一ファイルの上書き時間に制限され、一度に1つのファイルしか失われません。

ただし、これが「Webアプリケーション」に役立つかどうかはわかりません(あなたが使用していると言っていると思います)。そのため、私たちは常に「Webサイト」を使用しています。また、「Webサイト」では、デプロイしてもサイトが再起動されず、すべてのユーザーセッションがドロップされません。


こんにちはマイク、あなたはこの答えを削除したいかもしれません。
ソハイルアーメド
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.