サーバーが再起動し、OpenVPN が起動し、依存するアダプターやルートがまだ存在しないうちに RRAS が立ち上がります。一分後に手動で RRAS を再起動すると直るため、問題は解決したように見え、本当の問題が隠れます。ここでは二つの異なる条件、つまり前提サービスが実行中であることと、RRAS が実際に必要とするネットワークリソースが使用可能になったことが混同されています。Windows のサービス依存関係は前者を表現できても後者を決して表現できないため、リソースを定義せずに依存関係を追加すると、見た目だけ整った起動と同じ障害が手に入ります。

コールドブートで症状はどう見えるか

手がかりはコールドスタートと再起動の違いです。コールドスタートでは、トンネルアダプターが存在しない、ルートがない、ピアアドレスがまだ解決しないうちに、RRAS は実行中だと報告します。手動の再起動がその後成功するのは、その時点ではリソースが存在し、サービスは一分前には見えなかった世界をただ読み直すからです。サービスのログはどちらの場合もきれいな起動を示すので、イベントビューアーだけではこれを説明できないことがほとんどです。

何かを変える前に、起動時に RRAS が何を報告するか、手動の再起動が成功した瞬間に何が存在するかの両方の状態を記録します。この二つの観察が同一なら、起動順は説明になっておらず、依存関係は役に立ちません。この比較は十分間で済み、一週間の推測を節約します。

「再起動後に動く」という根拠で追加された依存関係は、前提サービスが RUNNING を報告するまでの分だけ同じ障害を遅らせるだけです。順序の制約が説明のように見えるため、起動を考えるのも難しくします。依存関係がどのオブジェクトを保証するのか、そのオブジェクトが RRAS に見えなかったものなのかを問うてください。

リソースを名指しし、サービスだけにしない

欠けている具体的なものを書き出します。アドレスを持つトンネルアダプター、ピアサブネットへのルート、DNS の応答、まだ発行中の証明書かもしれません。「VPN サービスが動いている」はリソースの説明ではなく、クライアントの緑のアイコンも同様です。オブジェクトとそれを示すコマンドを名指しできるまで、待とうとしている条件を定義したことにはなりません。

この OpenVPN インスタンスがどう起動されるかも確認します。GUI 管理のトンネルとサービス管理のトンネルでは起動のライフサイクルが異なり、サービス名は目の前のマシンから取るべきで、別のインストーラー向けに書かれた例から取るべきではありません。覚えている名前を信じず、候補を列挙してください。

Get-Service | Where-Object Name -match 'vpn|openvpn' | Select-Object Name, Status, StartType

追加する前に依存関係の連鎖を読む

サービス コントロール マネージャーは START_PENDING や RUNNING といった状態を報告し、SERVICE_STATUS reference は各フィールドの意味を正確に定義しています。これらの状態のどれも、ピア、DNS 名、下流のアプリケーションに到達できることを約束しません。この隙間こそが、正しく構成された依存関係でもこの障害が残る理由のすべてです。

Get-Service -Name RemoteAccess | Select-Object Status, StartType
sc.exe qc RemoteAccess
Get-Service -Name RemoteAccess | Select-Object -ExpandProperty DependentServices

sc.exe qc の DEPENDENCIES 行は、sc.exe config RemoteAccess depend= がリスト全体を置き換えるのであって追加するのではないため、保持すべきリストです。VPN サービスを追加する際に関係のない前提条件を落とすと、別の起動で現れる第二の障害を作り、元の障害よりはるかに診断が難しくなります。触る前に既存のリストを変更記録にコピーしてください。

依存関係は、前提条件を止めるとそれに依存するサービスも止まるため、シャットダウンの挙動も変えます。頻繁に再起動するものに RRAS を結び付ける前に、保守時に何が起きるかを確認してください。

再起動をタイマーではなく条件に条件付ける

固定のスリープは、証明書が遅い起動やリンクが切れている起動で失敗する、その時間内に必ずトンネルが準備できるという仮定です。リソースそのものを期限付きで確認し、再起動が本当に必要かを確認に決めさせてください。

Get-NetAdapter | Where-Object Status -eq 'Up'
Get-NetRoute -DestinationPrefix 0.0.0.0/0
Get-WinEvent -LogName System -MaxEvents 40 |
  Where-Object ProviderName -eq 'Service Control Manager'

起動時のスケジュールされたタスクがこれらの確認を実行し、アダプターやルートがまだ欠けている場合にだけ RRAS を再起動するなら、範囲が限られ、監査でき、削除も簡単です。代わりに再接続のたびに RRAS を再起動すると、健全なセッションを中断し、不安定なリンクを再起動ループに変えます。そのループは元の障害より悪く、今度は問題なかった利用者に影響します。

確認には、ハードウェア上でトンネルが妥当にかかる時間に合った最大待ち時間を与え、諦めたときは非ゼロの状態でタスクを終了させます。試すのをやめるだけの沈黙したタスクは、成功したタスクと区別できません。

遷移を記録し、次の起動が自らを説明できるようにする

同じ行に、依存サービスの RUNNING 到達時刻、必要なリソースが現れた時刻、RRAS が最終的に受け入れた時刻という三つのタイムスタンプを記録します。その一行が次の技術者の問いに答え、作るのにほとんど費用はかかりません。それがなければ、次の調査は今回と同じ推測から始まります。

決めた回数の試行で自動化を止め、永遠に再試行するのではなく失敗を報告します。「リソースはついに現れなかった」という明確なメッセージで終わる起動は、暗闇でサービスを再起動し続ける起動より価値があります。そのメッセージが現れたとき、第二節に書いたリソース名こそ次の人が探すものです。

関連記事