Kestrelの冗長化とは?ロードバランサーとWindowsフェイルオーバークラスター¶
最終確認: 2026-10-27
Kestrelとは?に戻る
30秒で復習¶
- Kestrel の冗長化は2通り:アクティブ/アクティブ(ロードバランサーの後ろに複数台)と、アクティブ/スタンバイ(Windowsフェイルオーバークラスター=WSFC で1台ずつ)。
- WSFC では、Kestrel のアプリを Windows サービスにして、汎用サービス(Generic Service)の役割として登録する。利用者はクラスターの名前(仮想の名前とIP)につなぎ、障害時は名前とIPごと別のノードへ移る。
- 切り替えの間(数十秒)は通信が切れる。メモリ上のセッションは消える。
- いちばんの落とし穴は Data Protection の鍵。ノードごとに別の鍵だと、フェイルオーバーした瞬間に全員ログアウトされる。鍵は共有の場所に置く。
- 両方のノードに同じ証明書(クラスターの名前で発行)、同じ設定ファイル、同じ gMSA(両ノードを許可グループに入れる)をそろえる。SPN はクラスターの名前で gMSA に登録する。
- 汎用サービスが見ているのは「サービスが動いているか」だけ。アプリが固まっても気づけないので、ヘルスチェックの仕組みを足す。
- 覚え方:「同じ看板(名前とIP)を、店ごと隣の建物へ引っ越す」
用語の正式名称と読み方¶
| 用語 | 意味 |
|---|---|
| 冗長化 | 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台だけにする |
具体例¶
| 場面 | おすすめ |
|---|---|
| すでに WSFC 基盤があり、社内向けの業務アプリを載せたい | 汎用サービスの役割+共有の Data Protection 鍵+クラスター名の証明書 |
| 夜間に1つだけ動かす集計サービス(二重起動は困る) | WSFC の汎用サービス(同時に1つしか動かない) |
| 利用者が多い Web API | ロードバランサー+Kestrel 複数台(アクティブ/アクティブ) |
| 止まる時間を数秒以内にしたい | アクティブ/アクティブ。WSFC では数十秒止まる |
関連メモ¶
確認したいこと¶
- 今の WSFC の役割は、汎用サービスか。サービスのリソースは IP・ネットワーク名に依存しているか
- Data Protection の鍵はどこに保存されているか(ノードごとになっていないか)。フェイルオーバー後にログアウトされないか試したか
- 証明書はクラスターの名前で発行され、両方のノードに入っているか
- gMSA の許可グループに、全ノードのコンピューターアカウントが入っているか
- アプリが固まったときに気づく仕組み(ヘルスチェックの監視)はあるか
- フェイルオーバーの訓練(手動で役割を移す)を、定期的にしているか