プライベートサブネットの「見えざる壁」:DNS名前解決の深淵と実務的トラブルシューティング
こんにちは。現場で泥をすすりながらパケットの行方を追っているSREです。
AWSのインフラ設計において、パブリックサブネットとプライベートサブネットを分けるのは基本中の基本。しかし、いざ「プライベートサブネット上のインスタンスからインターネット上のAPIを叩く」といった構成を組んだ際、なぜか接続エラーでハマる。その原因の多くが「DNS名前解決」のメカニズムを理解していないことにあります。
今回は、VPC内のDNSリゾルバーである AmazonProvidedDNS と、プライベートサブネットのルーティングが織りなす「見えざる通信」について、現場の知見を交えて紐解いていきましょう。
—
1. AmazonProvidedDNSの正体と「魔法のIP」
まず、VPC内にあるインスタンスが google.com などのドメインを解決しようとするとき、どこに問い合わせているかご存知でしょうか?
VPCのCIDRブロックが 10.0.0.0/16 だとすると、DNSリゾルバーは 10.0.0.2 に配置されています。これがAWSの提供する AmazonProvidedDNS です。
なぜプライベートサブネットでも解決できるのか?
ここが初心者の躓きポイントです。プライベートサブネットにはインターネットゲートウェイ(IGW)へのルートがありませんよね。それなのに、なぜ外部のドメインを解決できるのか。
答えはシンプルで、「VPC内のDNSリゾルバー(10.0.0.2)自体が、AWSのバックボーンネットワーク経由で外部の権威DNSサーバーへ再帰的に問い合わせを行っているから」です。
つまり、インスタンスから 10.0.0.2 への通信は、ルーティングテーブルに 0.0.0.0/0 があろうとなかろうと、AWSのネットワーク基盤がよしなに処理してくれます。ここはプライベートサブネットであっても、「DNSクエリだけは特別扱い」される聖域なのです。
—
2. 実務で遭遇する「通信の断絶」とNATゲートウェイ
名前解決はできても、その後の「実際のパケット通信」でコケるのが典型的なパターンです。
- DNS解決: インスタンス → (10.0.0.2) → インターネット上のDNSサーバー(成功)
- API通信: インスタンス → (NATゲートウェイ) → インターネット上のAPIサーバー(ここが遮断される)
プライベートサブネット上のインスタンスにはパブリックIPが存在しません。そのため、インターネット上の外部APIにアクセスするには、NATゲートウェイが必須となります。もしNATゲートウェイの設定を忘れていれば、名前解決はできるのに curl や Fetch API がタイムアウトで落ちるという、一見不可解な現象に悩まされることになります。
デバッグのためのCLIコマンド例
まずは、名前解決ができているか、通信ができているかを切り分けましょう。
# 1. DNS解決ができるか確認(名前解決の疎通確認)
dig google.com @10.0.0.2
# 2. 実際のHTTP通信が通るか確認(パケットの疎通確認)
# -v オプションで詳細なハンドシェイクの過程を見るのがコツです
curl -v https://api.github.com
—
3. Pythonでの実装:タイムアウト設定の重要性
アプリケーション層で外部APIを叩く際、ネットワークの遅延やリゾルバーの不調を考慮した実装が必要です。特に requests ライブラリなどを使う場合、タイムアウトをデフォルトのままにしておくと、ネットワークトラブル時にスレッドがスタックし、システム全体が共倒れします。
import requests
def fetch_api_data(url):
try:
# ネットワークの不安定さを考慮し、タイムアウトを明示的に設定する
# connect: 接続確立までの時間, read: データ受信までの時間
response = requests.get(url, timeout=(3.05, 10))
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
# ここでログをしっかり吐くのがSREの流儀。
# DNSエラーか、ルートがないためのタイムアウトかを切り分ける
print(f"Network error occurred: {e}")
return None
# 実行例
data = fetch_api_data("https://api.example.com/data")
—
4. 現場のシニアエンジニアからのTips:トラブルシューティングの心得
もしあなたがプライベートサブネットでネットワーク障害に遭遇したら、以下の手順で「切り分け」を行ってください。
1. Security Group (SG) の確認:
NATゲートウェイに向かうアウトバウンドの TCP/443 が許可されているか?意外とここが抜けています。
2. Network ACL (NACL) の確認:
サブネットレベルのNACLで、エフェメラルポート(1024-65535)のインバウンド通信を許可していますか?NACLはステートレスなので、リクエストだけでなくレスポンスの戻りポートも考慮が必要です。
3. VPCエンドポイントの確認:
S3やDynamoDBへの通信なら、NATゲートウェイを通す必要はありません。「ゲートウェイ型VPCエンドポイント」を使えばコストも抑えられ、ルーティングもシンプルになります。
最後に
「プライベートサブネットだから外部と繋がらない」と決めつけるのではなく、「DNSは特別枠で解決できるが、データプレーンの通信には出口(ゲートウェイ)が必要」という構造をパケットレベルでイメージしてください。
ネットワークは魔法ではありません。すべてはルーティングテーブルとステートフルなファイアウォールの挙動に支配されています。次に障害が起きたとき、慌ててコードをいじる前に、まず traceroute や tcpdump で「パケットがどこで死んでいるか」を特定する冷静さを持ってくださいね。
それが、一人前のクラウドエンジニアへの第一歩です。
コメント