Kestrelの冗長化とは?ロードバランサーとWindowsフェイルオーバークラスター¶
最終確認: 2026-10-27
Kestrelとは?に戻る
30秒で復習¶
- Kestrel の冗長化は2通り:アクティブ/アクティブ(ロードバランサーの後ろに複数台)と、アクティブ/スタンバイ(Windowsフェイルオーバークラスター=WSFC で1台ずつ)。
- WSFC では、Kestrel のアプリを Windows サービスにして、汎用サービス(Generic Service)の役割として登録する。利用者はクラスターの名前(仮想の名前とIP)につなぎ、障害時は名前とIPごと別のノードへ移る。
- 切り替えの間(数十秒)は通信が切れる。メモリ上のセッションは消える。
- いちばんの落とし穴は Data Protection の鍵。ノードごとに別の鍵だと、フェイルオーバーした瞬間に全員ログアウトされる。鍵は共有の場所に置く。
- 両方のノードに同じ証明書(クラスターの名前で発行)、同じ設定ファイル、同じ gMSA(両ノードを許可グループに入れる)をそろえる。SPN はクラスターの名前で gMSA に登録する。
- 汎用サービスが見ているのは「サービスが動いているか」だけ。アプリが固まっても気づけないので、ヘルスチェックの仕組みを足す。
- ロードバランサーはヘルスチェックで各台を監視する。見ているのは「ネットワーク越しに応答するか」で、HTTP チェック(
/healthz)なら、アプリが固まったことにも気づける。ただし、DB まで確かめると、DB が止まったときに全台外れる。 - IIS と Kestrel のどちらが冗長化に向いているかは、方式しだい。ロードバランサーならどちらも向いている。WSFC なら、アプリごとに Windows サービスにできる Kestrel のほうが相性がいい。
- 覚え方:「同じ看板(名前とIP)を、店ごと隣の建物へ引っ越す」
こんな場面で出会う¶
- 社内 Web アプリを 2台構成にしたい、または WSFC で切り替えられるようにしたい
- 切り替えたらログインし直しになった・Cookie が読めなくなった
用語の正式名称と読み方¶
| 用語 | 意味 |
|---|---|
| 冗長化 | 1台が壊れても止まらないように、予備を用意しておくこと |
| アクティブ/アクティブ | 全部の台が同時に働く。ロードバランサーで振り分ける |
| アクティブ/スタンバイ | 1台だけが働き、ほかは待機。障害時に入れ替わる |
| WSFC | Windows Server Failover Clustering。Windowsフェイルオーバークラスター |
| ノード | クラスターに参加しているサーバー1台1台 |
| 役割(ロール) | クラスターで守る単位。ここでは「汎用サービス」 |
| クライアントアクセスポイント | 利用者がつなぐ、クラスターの名前とIP(ネットワーク名+IPアドレスのリソース) |
| フェイルオーバー | 障害時に、役割を別のノードへ移すこと |
| クォーラム | クラスターが「自分たちは過半数そろっている」と判断する仕組み。監視(ウィットネス)を使う |
| Data Protection | ASP.NET Core がログインの Cookie などを暗号化するための仕組みと、その鍵 |
質問:Kestrelの冗長化には、どんな方式がある?¶
答え: 「全部の台を同時に動かす」か「1台を動かして、もう1台は待たせる」かの2通り。
| 観点 | アクティブ/アクティブ(ロードバランサー) | アクティブ/スタンバイ(WSFC) |
|---|---|---|
| 動いている台数 | 全台 | 1台だけ(ほかは待機) |
| 前に置くもの | ロードバランサー・リバースプロキシ(→プロキシとリバースプロキシ) | クラスターの名前とIP(クライアントアクセスポイント) |
| 障害時 | ロードバランサーが壊れた台を外す。ほぼ止まらない | 役割ごと別ノードへ移る。数十秒止まる |
| 性能 | 台数を増やせば上がる | 1台分のまま |
| アプリに求めること | 状態を持たない(セッションや一時ファイルを各台に置かない) | 同時に1つしか動かないことを前提にできる |
| 向いているもの | 普通のWebアプリ・API | 同時に1つだけ動かしたい処理(スケジューラー、順番に処理するキュー)、同じ名前・IPで待ち受け続けたいもの |
- 普通の Webアプリなら、アクティブ/アクティブのほうが止まりにくく、台数も増やせる。
- WSFC は、「2つ同時に動くと困る」アプリや、すでに WSFC の基盤があってそこに載せたい場合に選ばれる。
質問:WSFCでKestrelを動かすには?¶
答え: Kestrel のアプリを Windows サービスとして作り、クラスターに汎用サービスの役割として登録する。役割の中には、IPアドレス・ネットワーク名・サービスの3つのリソースが入る。
1. アプリを Windows サービスにする¶
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseWindowsService(); // Windows サービスとして動かす
// ログイン Cookie などの鍵を、両ノードから見える共有の場所に置く(→ 落とし穴1)
builder.Services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\fileserver\dpkeys\myapp"))
.SetApplicationName("myapp");
builder.Services.AddHealthChecks(); // 生きているかを外から確かめる口
var app = builder.Build();
app.MapHealthChecks("/healthz");
app.Run();
2. 両方のノードに、同じものを用意する¶
# 各ノードで:サービスを登録(起動はクラスターに任せるので「手動」にする)
New-Service -Name "MyKestrelApp" -BinaryPathName "C:\apps\myapp\MyApp.exe" -StartupType Manual
# 各ノードで:実行アカウントを gMSA にする(パスワード欄は空)
sc.exe config MyKestrelApp obj= "CORP\svc-web$"
3. クラスターに汎用サービスの役割を作る¶
# どれか1台で:役割を作る(ネットワーク名 web-app と、仮想IPを付ける)
Add-ClusterGenericServiceRole -ServiceName "MyKestrelApp" -Name "web-app" -StaticAddress 10.0.0.50
# Windows 認証(Kerberos)を使うなら、クラスターの名前で SPN を gMSA に登録する
setspn -S HTTP/web-app.corp.example.com CORP\svc-web$
- 利用者は
https://web-app.corp.example.comのように、クラスターの名前でつなぐ。ノードの名前(node1など)は使わない。 - サービスのリソースが、IPアドレスとネットワーク名のリソースに依存するようにしておく(作った直後の既定でそうなっていることが多い)。IPが付く前にサービスが起動して、待ち受けに失敗するのを防ぐ。
- 汎用サービスの設定にある「ネットワーク名をコンピューター名として使用する」を有効にすると、アプリから見たコンピューター名がクラスターの名前になる。
質問:WSFCで気をつけることは?(落とし穴)¶
落とし穴1:フェイルオーバーしたら全員ログアウトされる(Data Protection の鍵)¶
ASP.NET Core は、ログインの Cookie や CSRF 対策のトークンを Data Protection の鍵で暗号化している。何も設定しないと、鍵はノードごと・実行アカウントごとのローカルに作られる。
- ノード1の鍵で作った Cookie は、ノード2では読めない → フェイルオーバーした瞬間に全員ログアウト、送信途中のフォームもエラーになる。
- 対策:鍵を両ノードから見える共有フォルダ(またはDB・Azure Blob など)に置き、
SetApplicationNameをそろえる。鍵の保存場所は、gMSA だけが読めるようにアクセス権を絞る。
落とし穴2:証明書が片方のノードにしかない¶
- HTTPS の証明書は、両方のノードの「コンピューター(LocalMachine)の個人」ストアに入れる。
- 証明書の名前(SAN)は、クラスターの名前(
web-app.corp.example.com)で発行する。ノード名で発行すると、利用者のブラウザで証明書エラーになる。 - gMSA が秘密鍵を読めるようにアクセス権を付ける(両ノードで)。
落とし穴3:gMSA が片方のノードで使えない¶
- gMSAの「パスワードを取り出してよいグループ」に、両方のノードのコンピューターアカウントを入れる。
- 新しくノードを足したときも、グループへの追加を忘れない。
落とし穴4:アプリが固まっても、切り替わらない¶
- 汎用サービスのリソースが見ているのは、サービスが「実行中」かどうかだけ。アプリの中が固まって応答しなくても、サービスが動いていれば正常とみなされる。
- 対策の例:
/healthzを定期的に確かめる監視を置き、応答がなければサービスを再起動する・アラートを出す。アプリ側で、固まったことに気づいたら自分で終了する作りにする(終了すればクラスターが検知して、再起動やフェイルオーバーをする)。
落とし穴5:設定ファイルやログが、ノードごとにバラバラ¶
appsettings.jsonやアプリ本体は、両ノードに同じものを配置する。配置の手順に「両方のノードへ」を入れる。- ログをノードのローカルに書くと、フェイルオーバーの前後でログが2か所に分かれる。中央のログ基盤(SIEM など)へ送る。
- アプリがファイルを保存するなら、共有ディスク(クラスターのディスク)や共有フォルダを使う。
落とし穴6:その他¶
| 項目 | 内容 |
|---|---|
| 切り替えにかかる時間 | 数十秒くらい通信が切れる。利用者側(呼び出す側のプログラム)にリトライを入れる |
| 再起動とフェイルオーバーの回数 | 「同じノードで何回再起動を試すか」「何回失敗したら別ノードへ移るか」をクラスターの設定で決める |
| フェイルバック | 元のノードが直ったとき、自動で戻すか。業務時間外だけ戻すなどにできる |
| クォーラム | 2台構成なら、ファイル共有やクラウドの監視(ウィットネス)を必ず置く |
| NLB との同居 | Windows の NLB(ネットワーク負荷分散)と WSFC は、同じサーバーで一緒に使えない |
| データベース | DB 側も冗長化しているなら、接続先はリスナー名にする。EF Core なら接続のリトライ(EnableRetryOnFailure)を有効にする |
質問:アクティブ/アクティブにするなら?¶
答え: 前にロードバランサー(またはリバースプロキシ)を置き、Kestrel を2台以上並べる。アプリが状態を持たないことが条件。
| やること | 内容 |
|---|---|
| ヘルスチェック | ロードバランサーから /healthz を確かめ、応答しない台を外す |
| セッション | メモリではなく、Redis や SQL Server の分散キャッシュに置く |
| Data Protection の鍵 | WSFC と同じく、全台で共有する |
| Forwarded Headers | ロードバランサーの後ろなので、本当の接続元IPと https を受け取る設定をする(→Kestrelとは) |
| 一度に1つだけ動かしたい処理 | 夜間バッチなどは、全台で動くと二重に実行される。別のサービスに分けるか、DB のロックで1台だけにする |
質問:ロードバランサーは、サービスの稼働状況を監視している?¶
答え: 監視している(ヘルスチェック)。 ただし見ているのは「ネットワーク越しに応答があるか」で、Windows のサービスが「実行中」かどうかを直接見ているわけではない。
| 種類 | 何を見るか | 分かること | 分からないこと |
|---|---|---|---|
| TCP(ポート)チェック | ポート(443など)につながるか | サーバーやプロセスが落ちた | アプリの中が固まっている、エラーばかり返している |
| HTTP チェック | GET /healthz を送って 200 が返るか |
アプリがちゃんと応答できるかまで分かる | (ヘルスチェックの作り方しだい) |
動き方の例:5秒ごとに /healthz を確かめ、3回続けて失敗したら振り分けから外し、2回続けて成功したら戻す。
- HTTP チェックがおすすめ。 WSFC の汎用サービスは「サービスが実行中か」しか見ないので、アプリが固まっても気づけない。HTTP チェックなら、固まったことにも気づける。ここがロードバランサーの強み。
落とし穴:ヘルスチェックで DB まで確かめると、全台が外れる¶
/healthz の中で DB への接続まで確かめると、DB が止まったときに全台が「異常」と判定されて、全部振り分けから外れる。結果、エラー画面すら返せずにサービス全体が止まる。
- 「プロセスが生きているか(liveness)」と「仕事を受けられるか(readiness)」を分ける。ロードバランサーには liveness を見せるのが定番。
- DB の状態は readiness や監視ツールで見て、アラートを出す。
builder.Services.AddHealthChecks()
.AddCheck<DbHealthCheck>("db", tags: new[] { "ready" }); // DB の確認には ready の札を付ける
// ロードバランサー用:アプリが応答できるかだけ(DB の確認は含めない)
app.MapHealthChecks("/healthz/live", new HealthCheckOptions { Predicate = _ => false });
// 監視ツール用:DB なども含めて、仕事を受けられるか
app.MapHealthChecks("/healthz/ready", new HealthCheckOptions { Predicate = c => c.Tags.Contains("ready") });
- ロードバランサー自体も1台だと、そこが止まれば終わり。2台構成にするか、クラウドのロードバランサーを使う。
質問:IISとKestrel、冗長化に向いているのはどっち?¶
答え: Webサーバーではなく「冗長化の方式」で決まる。 冗長化は「複数台+切り替えの仕組み」で実現するもので、Kestrel も IIS も作り方しだいでどちらも冗長化できる。ただし、方式との相性には差がある。
| 方式 | IIS | Kestrel(Windowsサービス) |
|---|---|---|
| ロードバランサーでアクティブ/アクティブ | ◎ 定番。共有構成や Web Deploy で、複数台に同じ設定を配れる | ◎ 同じくらい向いている |
| WSFC でアクティブ/スタンバイ | △ 向いていない。IIS はクラスター対応ではなく、IIS のサービス(W3SVC)は全サイトで1つなので、アプリごとに切り替えられない | ◎ アプリごとに1つの Windows サービスなので、汎用サービスの役割にそのまま載せられる |
| 落ちたときの自動復旧(同じサーバーの中で) | ◎ アプリプールが、落ちた作業プロセスを自動で起動し直す(ラピッドフェール保護・定期リサイクルもある) | ○ Windows サービスの「回復」設定や、クラスターの再起動の設定で補う |
| Windows 認証・証明書の管理 | ◎ IIS の画面でまとめて設定できる | ○ コードや設定ファイルで行う |
- WSFC を使っている環境なら、Kestrel を Windows サービスにする形のほうが相性がいい。アプリ単位で役割を作ってフェイルオーバーできる。
- ロードバランサーで全台を動かすなら、IIS でも Kestrel でも差は小さい。運用に慣れている方を選ぶ。
- 「2つ同時に動くと困るアプリ」なら WSFC+Kestrel、「状態を持たない普通のWebアプリ」ならロードバランサー+(IIS か Kestrel)。
具体例¶
| 場面 | おすすめ |
|---|---|
| すでに WSFC 基盤があり、社内向けの業務アプリを載せたい | 汎用サービスの役割+共有の Data Protection 鍵+クラスター名の証明書 |
| 夜間に1つだけ動かす集計サービス(二重起動は困る) | WSFC の汎用サービス(同時に1つしか動かない) |
| 利用者が多い Web API | ロードバランサー+Kestrel 複数台(アクティブ/アクティブ) |
| 止まる時間を数秒以内にしたい | アクティブ/アクティブ。WSFC では数十秒止まる |
関連メモ¶
確認したいこと¶
- 今の WSFC の役割は、汎用サービスか。サービスのリソースは IP・ネットワーク名に依存しているか
- Data Protection の鍵はどこに保存されているか(ノードごとになっていないか)。フェイルオーバー後にログアウトされないか試したか
- 証明書はクラスターの名前で発行され、両方のノードに入っているか
- gMSA の許可グループに、全ノードのコンピューターアカウントが入っているか
- アプリが固まったときに気づく仕組み(ヘルスチェックの監視)はあるか
- フェイルオーバーの訓練(手動で役割を移す)を、定期的にしているか
- ロードバランサーのヘルスチェックは TCP か HTTP か。
/healthzの中で DB まで確かめていないか