【AWS】別AZで起動したWindowsが通信不能に|原因はVPCではなく「OS内のルート情報」だった

AWS

セキュリティグループも見た。
NACLも見た。
VPCルートテーブルも見た。

それでも通信できない。

そんなとき、原因はAWSコンソールの中ではなく、OSの中にあるかもしれません。

今回扱うのは、EC2を別AZで起動した際に、Windows ServerのOS内ルート情報が更新されず、通信できなくなった事象です。

この記事では、単なるルート設定の話ではなく、EC2Launch、User Data、AMI再利用、DR設計で見落としやすい「起動後のOS状態」について整理します。

EC2は起動した。でも通信できない

EC2インスタンスを別AZで起動した。

インスタンスの起動は成功している。
OSも上がっている。
しかし、通信できない。

このような事象が起きると、まずAWS側の設定を疑うと思います。

セキュリティグループがおかしいのか。
NACLで止められているのか。
サブネットのルートテーブルが間違っているのか。

もちろん、それらは確認すべきです。

しかし、今回の原因はそこではありませんでした。

問題は、Windows OS内のルーティング情報が、移動先AZに合わせて更新されていなかったことでした。

AZ移動後、Windowsサーバが通信できない

今回の事象は、AZ障害時の切替を想定した環境で発生しました。

通常時は、あるAZでWindows ServerのEC2インスタンスを稼働させています。

障害時には、別AZでインスタンスを起動し、業務を継続する想定でした。

構成としては、クラウドではよくある考え方です。

画像
別AZでEC2を起動できても、起動後に通信できるとは限らない

ただし、この構成で注意すべきなのは、「別AZでEC2が起動できること」と「起動後に業務通信が成立すること」は別問題だという点です。

今回も、インスタンスの起動自体は成功していました。

OSも起動していました。

ところが、正常なネットワーク通信ができませんでした。

AWS側の設定だけを見れば、サブネット、セキュリティグループ、NACL、VPCルートテーブルを疑いたくなります。

しかし、調査していくと、問題はWindows OS内部のルーティング情報にありました。

移動先AZで必要となるルート情報が、OS起動時に追加されていなかったのです。

ここで重要なのは、VPCのルートテーブルではなく、Windows OS内のルート情報だという点です。

では、なぜOS内にルート情報が必要になるのでしょうか。

たとえば、次のような構成を考えてみます。

通常の業務通信は、デフォルトゲートウェイから出す。
一方で、監視サーバ向けのセグメント 172.16.10.0/24 には、2枚目のNIC、つまり別ENI側の経路を使って通信させる。

この場合、Windows OS内には、

172.16.10.0/24 は、2枚目のNIC側の経路へ向ける
copy

というスタティックルートが必要になります。

VPCルートテーブルが正しくても、Windows OS内にこのルートがなければ、監視サーバ向けの通信は期待した経路に流れません。

EC2はクラウド上の仮想サーバです。

しかし、サーバである以上、OSの中にもネットワーク設定があります。

クラウド側の設定だけでは、通信は完結しません。

さらに、別AZで起動すると、通常は起動先のサブネットも変わります。

サブネットやENI構成が変われば、OS内のスタティックルートで前提にしていたネクストホップ(次に経由するルーターやゲートウェイのIPアドレス)  やインターフェースが、移動先の環境と合わなくなることがあります。

しかし、AMIを取得した時点のOS内ルート情報には、旧環境を前提にした経路が残っている場合があります。

そのまま別AZで起動すると、ルートのエントリは存在しているのに、実際には期待した経路へ到達できない。

これが、

「設定した覚えはあるのに通信できない」

という事象の正体です。

原因はEC2Launchの起動時処理だった

原因は、Windows Serverの起動時に動く初期化処理でした。

Windows Server 2012 R2以前では、EC2Configというサービスが使われていました。

一方、Windows Server 2016 / 2019では、EC2Launch v1が使われる構成があります。

ここで見落としやすいのは、

「Windows Serverなら、起動時に毎回同じ初期化処理が走る」

とは限らないことです。

今回のポイントはここです。

AMIを取得する前のインスタンスで、すでに初回起動時の処理が終わっている。
その状態をAMIとして固める。
そのAMIから別AZで起動する。
しかし、OSや初期化エージェントの状態としては、必要な処理が「初回起動時のみ実行済み」と扱われる。
その結果、別AZで起動したときに、ルート追加処理が走らない。

このような流れになると、EC2自体は起動しているのに、OS内のルート情報が移動先AZに合わないまま残ります。

その結果、サーバは起動したのに通信できない、という状態になります。

若手SEがここで学ぶべきなのは、OSの設定そのものだけではありません。

「その設定は、いつ、どの仕組みによって入るのか」

を見る必要があるということです。

EC2Config、EC2Launch v1、EC2Launch v2をざっくり押さえる

細かい仕様をすべて暗記する必要はありません。

ただ、Windows EC2の初期化エージェントには世代差があることは押さえておくべきです。

Windows Server 2012 R2以前
  → EC2Config

Windows Server 2016 / 2019の一部AMI
  → EC2Launch v1

Windows Server 2022 / 2025、
一部のWindows Server 2016 / 2019 AMI
  → EC2Launch v2
copy

現在は、EC2Launch v2への移行が進んでいます。

EC2Launch v2では、「どのタスクを、どのステージで、どの頻度で実行するか」を管理する考え方になります。

見るべきポイントは、バージョン名そのものではありません。

実務では、以下を確認します。

・対象OSは何か
・EC2Config、EC2Launch v1、EC2Launch v2のどれか
・User Dataは初回だけか、毎回か
・起動時タスクは有効か
・タスクの実行頻度は once か always か
・初期化処理のログにエラーは出ていないか
copy

特にEC2Launch v2では、User Dataもタスクとして扱われるため、実行頻度が once なのか always なのかを確認する必要があります。

ここを確認しないままDR設計や移行設計を進めると、机上では成立しているのに、切替時に通信できないサーバが立ち上がることがあります。

なお、EC2Launch v2には agent-config.yml などの設定ファイルがありますが、この記事では詳細な設定手順までは踏み込みません。

ここで重要なのは、ファイル名を暗記することではなく、起動時に実行されるタスクと実行頻度を確認する、という考え方です。

なぜ永続ルートではなく、起動ごとの処理なのか

ここで、こう思う人もいるかもしれません。

「Windowsなら route add -p で永続ルートにすればよいのでは?」

たしかに、固定的な経路であれば、それで済む場合もあります。

route add -p は、Windowsで再起動後も残るルートを登録する方法です。

しかし、クラウド移行やAZ切替では、単純な永続ルートだけでは不十分な場合があります。

なぜなら、起動先のAZ、サブネット、ENI構成、ゲートウェイ、経路設計によって、追加すべきルートが変わることがあるからです。

AMIに固定ルートを焼き込んでしまうと、元のAZでは正しくても、別AZでは古い経路を引きずる可能性があります。

たとえば、元の環境では `10.0.1.1` 側を通る前提でOS内にルートを持っていたとします。

しかし、別AZで起動した後は、サブネットやENI構成が変わり、`10.0.2.1` 側を通すべき構成になっているかもしれません。

このとき、OS内に旧環境のルートが残ったままだと、設定は存在しているのに、移動先環境では正しい経路に通信が流れません。

一方、起動ごとのスクリプトでルートを追加する方式なら、起動先の環境に合わせて必要なルートを入れ直す設計にできます。

もちろん、その分だけスクリプト設計は慎重に行う必要があります。

特に重要なのが、冪等性です。

冪等性とは「同じ処理を何度実行しても、結果が壊れず同じ状態に収まる性質のこと」です。

起動のたびに実行される処理は、何度実行しても壊れないように作る必要があります。

たとえば、同じルートを毎回追加しようとしてエラーになる。
既存設定を無条件で上書きしてしまう。
途中で失敗したときに中途半端な状態が残る。

こうした作りになっていると、初期化処理そのものが新しい障害原因になります。

対策は「OS起動ごとに必要な処理を実行させる」こと

今回の対策は、OS起動ごとに必要なルート追加処理が実行されるようにすることでした。

EC2Launch v1の場合、単に「起動すれば自動で全部整う」と考えるのではなく、起動時に必要な処理が実行される状態になっているかを確認する必要があります。

たとえば、今回のようなルート追加であれば、User DataからEC2Launchのモジュールを読み込み、`Add-Routes` を呼び出す方法があります。

Import-Module (Join-Path $env:ProgramData 'Amazon\EC2-Windows\Launch\Module\Ec2Launch.psd1')
Add-Routes
copy

さらに、User Dataを起動ごとに実行したい場合は、persist を有効にします。

<persist>true</persist>
copy

これにより、インスタンス起動時にUser Dataの処理が繰り返し実行され、移動先環境に合わせたルート追加処理を走らせることができます。

重要なのは、コマンドそのものを暗記することではありません。

タスクスケジューラ、User Data、EC2Launchのどの仕組みによって、起動時の処理を実行させているのかを理解することです。

EC2Launch v2では、この種の起動時タスクの扱いが整理されており、同じ問題が起きにくい構成になっています。

ただし、実際の挙動は、AMIの世代、EC2Launchのバージョン、User Data、タスクの実行頻度に依存します。

そのため、v2だから確認不要、とは考えない方が安全です。

環境によって確認ポイントは変わります。

しかし、共通する考え方は同じです。

「起動時に、必要なOS設定が、確実に反映される状態になっているか」

ここを確認する必要があります。

AWS側の設定だけ見ても足りない

若手SEにとって、EC2の通信不可というと、どうしてもAWS側の設定に目が行きます。

それ自体は間違いではありません。

実際、通信不可の原因として、セキュリティグループ、NACL、VPCルートテーブル、サブネット、ENI、DNS設定などはよくあります。

しかし、それだけでは足りません。

今回のように、OS内部の設定が原因になることもあります。

今回の切り分けは、3つの層で見ると整理しやすくなります。

AWSインフラ層
  → セキュリティグループ、NACL、VPCルートテーブルを見る

初期化エージェント層
  → EC2LaunchやUser Dataが期待どおり実行されたかを見る

OS設定層
  → Windowsのルーティングテーブルが移動先環境に合っているかを見る
copy

今回の原因は、AWSインフラ層ではなく、初期化エージェント層とOS設定層の間にありました。

EC2の通信確認では、AWS側の設定、クラウド初期化処理、OS内部の設定を一連の流れとして見る必要があります。

画像

この図で言いたいのは、EC2が起動した時点で確認が終わるわけではない、ということです。

AWS側の設定が正しく、インスタンスが起動していても、その後に動く初期化処理やOS内部の設定が想定どおりでなければ、業務通信は成立しません。

サーバが起動していることと、業務通信が成立していることは別です。

ここを混同すると、DRテストや移行リハーサルで痛い目を見ます。

これはルーティングだけの話ではない

今回の事象は、Windows Serverのルーティング情報が更新されなかった、という個別トラブルに見えます。

しかし、これはルーティングだけの話ではありません。

以前扱ったような、MTU設定が戻る、SSHでログインできない、OS起動後に想定した設定になっていない、といった事象にも共通する構造があります。

共通しているのは、初期化エージェントがOS設定を書き換える、または書き換えないことで、起動後のOS状態が想定とずれる点です。

ある設定は、初期化エージェントによって上書きされます。

別の設定は、初期化エージェントが実行されないために更新されません。

つまり、

「書き換えられて困る」

場合もあれば、

「書き換えてほしいのに書き換わらない」

場合もあります。

どちらも、クラウド初期化処理がOS設定に関与していることを理解していないと、原因にたどり着きにくくなります。

なぜクラウドはOS設定を書き換えるのか

では、なぜクラウド環境では、起動時にOS設定へ手を入れるのでしょうか。

理由は大きく3つあります。

1つ目は、セキュリティです。

クラウド環境では、インターネットや社内ネットワークから到達可能なサーバを短時間で作成できます。

そのため、初期状態をできるだけ安全側に寄せる必要があります。

SSHのパスワード認証を無効にし、公開鍵認証を前提にするような考え方は、その典型です。

パスワード総当たり攻撃の入口を減らすためです。

これは、クラウド環境におけるベストプラクティスに寄せた挙動と考えると理解しやすいです。

2つ目は、クラウド環境に合わせてOSを自動適応させるためです。

EC2インスタンスは、起動時にインスタンスメタデータ、User Data、ネットワーク情報などを利用します。

OSは、起動した場所、割り当てられたIP、ホスト名、初期化スクリプトなどをもとに、クラウド上で動ける状態に整えられます。

3つ目は、AMIを再利用するためです。

AMIは、ある時点のOS状態を固めたものです。

しかし、そのAMIから起動されるインスタンスは、元の環境と同じとは限りません。

別AZかもしれません。
別サブネットかもしれません。
別IPかもしれません。
別用途のサーバとして起動されるかもしれません。

そのため、AMIに残っているOS設定をそのまま信じるだけでは危険です。

クラウドでは、起動時にメタデータやUser Dataを参照し、起動先の環境に合わせて初期化する仕組みが用意されています。

ただし、その初期化処理が「いつ」「どの条件で」「何を」実行するかは、OS、エージェント、設定によって変わります。

ここを理解していないと、

設定したはずなのに戻った
自動で入ると思っていたのに入らなかった
AMIから起動したら前の状態を引きずった
copy

という事象が起こります。

DR設計では「起動できる」だけでは足りない

今回の話は、DR設計やAZ障害時の切替設計にも直結します。

DR設計では、次のような確認をしがちです。

・別AZでEC2が起動できる
・AMIからインスタンスを作成できる
・EBSを付け替えられる
・IPやDNSを切り替えられる
copy

もちろん、これらは重要です。

しかし、これだけでは不十分です。

本当に確認すべきなのは、起動後に業務通信が成立するかです。

実務では、少なくとも以下を確認した方がよいです。

・OS内のルート情報は正しいか
・DNS名前解決はできるか
・ADや認証基盤へ到達できるか
・業務アプリの接続先へ通信できるか
・監視、バックアップ、ジョブ管理エージェントは動くか
・User Dataや起動時スクリプトは期待どおり実行されたか
・初期化処理のログにエラーは出ていないか
copy

DRテストで見るべきなのは、インスタンスの起動成功ではありません。

業務として使える状態になったかどうかです。

ここを間違えると、テストでは成功したように見えても、本番障害時に通信できないサーバが立ち上がることになります。

まとめ

今回は、EC2を別AZで起動した際に、Windows Serverのルーティング情報が更新されず、通信できなくなった事象を扱いました。

原因は、AWS側のセキュリティグループやVPCルートテーブルではなく、OS内部のルート情報でした。

そして、その背景には、EC2Config、EC2Launch、EC2Launch v2といったクラウド初期化エージェントの挙動差がありました。

クラウドでは、サーバを起動するだけなら簡単です。

しかし、起動したサーバが業務として使える状態になっているかは、別の問題です。

若手SEは、EC2が起動したかどうかだけで安心してはいけません。

見るべきなのは、起動後に、どの設定が、どのタイミングで、どの仕組みによって反映されるのかです。

サーバは起動した。
でも通信できない。

その原因は、AWS側ではなく、OSの中にあるかもしれません。


関連記事

この考え方については、以下の記事でも整理しています。

【前編】詳細設計で決めること|基本設計を「構築・テスト・運用できる形」に落とし込む工程

シリーズ全体は「実務で使えるシステム開発方法論」マガジンにまとめています。

コメント

タイトルとURLをコピーしました