深夜3時、鳴り響くアラート音。
「APIサーバーから外部決済ゲートウェイへの疎通が突然途絶えました。HTTP 502 Bad Gatewayが多発しています」
こういう修羅場をくぐり抜けてきた私たちインフラエンジニアやWebバックエンドエンジニアにとって、障害発生時の初動はまさに時間との戦いだ。アプリケーションログを覗き、次に叩くべきコマンドは何だろうか? curl か? いや、ちょっと待て。そのURL、本当に正しいIPを指しているか? そもそもDNSの名前解決は正常に行われているか?
Web APIの設計やインフラ構築において、DNSはすべての通信の「起点」だ。ここが沈黙していれば、どれほど強靭なロードバランサーを組んでいこうが、アプリケーションコードを美しく書こうが、パケットは一歩も外へ出ない。
今回は、日々の運用監視やトラブルシューティングで確実に手札に入れておかなければならない nslookup コマンド、そしてその真骨頂である「対話モード」について、現場の泥臭い知見を交えて徹底的に解説しよう。
—
1. なぜ今 nslookup なのか?(dig との使い分け)
現代のネットワークエンジニアやインフラ運用者の間では、詳細なDNS情報を引き出せる dig コマンドが好まれる傾向にある。フルリゾルバとのやり取りを生々しく暴く dig は確かに強力だ。
しかし、あえて言おう。「スピードと手軽さ、そして対話的アプローチの直感性においては、今なお nslookup が最強の相棒である」 と。
特に、Windows環境であれLinux環境であれ、追加のパッケージインストールなしでほぼ標準搭載されている点、そして1つのセッションを維持したまま連続して異なるレコードタイプやネームサーバーへクエリを投げ続けられる「対話モード」の存在は、緊急時の精神的負荷を劇的に下げてくれる。
標準的なDNSクエリの通信フロー
まず、裏側で何が起きているかを整理しておこう。RFC 1034および1035に規定されている通り、DNSクエリの基本はUDP(フォールバック時はTCP)のポート53番を使用したリクエスト/レスポンスだ。
1. クライアント (nslookup) から、設定されたフルリゾルバ(例: 8.8.8.8 や社内DNS)へUDPで問い合わせパケットが飛ぶ。
2. フルリゾルバはキャッシュを確認するか、ルートサーバーから順に辿る(反復クエリ)ことで目的のIPアドレスを割り出す。
3. レスポンスがクライアントに戻り、ターミナルに結果が表示される。
この一連の流れの中で、「どのDNSサーバーが」「どのレコードを返してきたか」をその場で即座に切り替えながら調査できるのが nslookup の真骨頂だ。
—
2. nslookup の基本構文と非対話モード
まずは基本の「非対話モード」のおさらいだ。日常のちょっとした確認にはこれで十分だが、実務ではオプションの組み合わせが命運を分ける。
# 最もシンプルな問い合わせ(デフォルトのフルリゾルバを使用)
nslookup api.example.com
# 問い合わせるDNSサーバー(フルリゾルバ)を明示的に指定する
nslookup api.example.com 8.8.8.8
もし、ある特定のプライベートDNS(社内ニッチな環境など)が意図したレコードを返しているか確認したい場合、第2引数に 8.8.8.8 のようなIPアドレスを渡すテクニックは、マルチクラウド環境やオンプレミスとのハイブリッド環境で頻繁に使う。
—
3. 現場で役立つ「対話モード」の活用手順
ここからが本題だ。障害調査の最中、次から次へとドメインやレコードタイプを変えて確認したいとき、毎回 nslookup コマンドを打ち直すのは時間のロスであり、タイポの元だ。
引数なしで nslookup を実行すると、対話型シェル(プロンプトが > に変わる)に移行する。
対話モードへの突入と基本操作
$ nslookup
>
この状態で、様々なサブコマンドを叩くことができる。実務で絶対に覚えておくべき主要なサブコマンドを以下にまとめた。
| サブコマンド | 意味・用途 | 具体例 |
| :— | :— | :— |
| server [IP/ホスト名] | 問い合わせ先のDNSサーバーを動的に切り替える | server 1.1.1.1 |
| set type=[タイプ] | 取得するレコードの種類(A, AAAA, CNAME, TXT, MXなど)を変更する | set type=TXT |
| set debug | パケットの詳細なやり取り(フラグやTTLなど)を表示するデバッグモードを有効化 | set debug |
| exit | 対話モードを終了する | exit |
実践:対話モードで段階的にデバッグするシナリオ
例えば、「あるWeb APIのエンドポイント api.payment.internal が、なぜか古いIPアドレスに向いてしまっている(DNSキャッシュ汚染やレコードのTTL切れ忘れが疑われる)」という障害を想定しよう。
以下の手順で対話モードを立ち上げ、真犯人を追い詰める。
# 1. 対話モードを起動
$ nslookup
Default Server: 192.168.1.1
Address: 192.168.1.1#53
# 2. まずは社内デフォルトのDNSサーバーに聞いてみる
> api.payment.internal
Server: 192.168.1.1
Address: 192.168.1.1#53
Name: api.payment.internal
Address: 192.168.10.50 # => あれ? 古いIPのまま...?
# 3. 権威DNS(フルリゾルバではなく、直接ゾーンを持っているサーバー)を直撃してみる
> server ns1.payment.internal
Default Server: ns1.payment.internal
Address: 203.0.113.10#53
# 4. レコードタイプをCNAMEやTXTも含めて総確認するためにタイプを変更
> set type=ANY
> api.payment.internal
Server: ns1.payment.internal
Address: 203.0.113.10#53
api.payment.internal text = "v=spf1 include:_spf.example.com ~all"
api.payment.internal internet address = 192.168.10.99 # => 権威サーバー側ではすでに新しいIPになっている!
この瞬間、「あ、社内フルリゾルバのキャッシュがTTLのせいで残っているだけだ。パージ(キャッシュクリア)を叩けば直るな」という次のアクションが秒速で導き出せる。これが nslookup の対話モードが持つ圧倒的なアドバンテージだ。
—
4. アプリケーションコード側からのDNS挙動の理解
インフラ担当者がDNSを調査している裏で、Web APIを叩くアプリケーション(PythonやNode.js、あるいはcurl)もまた、OSのレゾルバライブラリ(getaddrinfo など)を通じてDNSの名前解決を行っている。
ここでインフラとアプリの境界線でハマりがちなのが、「TTL(Time To Live)とコネクションプールの罠」だ。
Python (requests / urllib) でのDNSキャッシュの挙動
Pythonスクリプトから外部APIを頻繁に叩く際、DNSの変更が即座に反映されないトラブルによく遭遇する。これはPythonのHTTPライブラリやランタイムが独自にDNSをキャッシュしている、あるいはOSレベルでのキャッシュが効いているためだ。
以下のコードは、Pythonでリクエストを送りつつ、必要に応じてカスタムのDNS解決を行ったり、挙動を検証するためのスニペットだ。
import socket
import requests
from urllib3.util.connection import create_connection
# 【実務Tips】
# デフォルトのコネクション作成処理をオーバーライドし、
# 特定のドメインに対して特定のIPアドレスを強制してテストしたい場合のハック
original_create_connection = create_connection
def patched_create_connection(address, timeout=None, source_address=None, socket_options=None):
host, port = address
# 例: テスト環境向けに特定のホスト名を強制的に別IPに向ける
if host == "api.example.com":
host = "203.0.113.99" # nslookupで突き止めた新しいIP
return original_create_connection((host, port), timeout, source_address, socket_options=None)
# urllib3の接続関数をパッチ(一時的な検証用)
# urllib3.util.connection.create_connection = patched_create_connection
try:
# 通常のAPIリクエスト(内部でDNS名前解決が走る)
response = requests.get("https://api.example.com/v1/health", timeout=5)
print(f"ステータスコード: {response.status_code}")
print(f"レスポンスヘッダー (X-Request-ID等): {response.headers.get('X-Request-ID')}")
except requests.exceptions.RequestException as e:
print(f"APIリクエスト失敗: {e}")
# このようなエラーが出た際、真っ先に `nslookup` で名前解決を疑うべき
curl でDNSの挙動をハックする実用コマンド
インフラのデバッグ中、「本番リリース前の新しいIPを持つDNSサーバー(またはロードバランサー)に対して、APIが正常に応答するかどうか」を、DNSレコードを書き換える前に単体でテストしたいことがある。
そんなときは curl の --resolve オプションが極めて強力だ。
# ドメイン名、ポート、接続先IPを直接指定してリクエストを強制する
# (DNSサーバーに問い合わせず、指定したIPへ直接TLSハンドシェイクを行う)
curl -v --resolve api.example.com:443:203.0.113.99 https://api.example.com/v1/status
このコマンドを使えば、「DNSレコードの伝播を待たずに、新しいサーバー単体の健康状態(Health Check)を確認する」という離れ業が可能になる。nslookup で新しいIPを特定し、curl --resolve で実機検証する。このコンビネーションはインフラ・SREの黄金律だ。
—
5. シニアエンジニアからの教訓:トラブルシューティングの作法
数々の障害対応現場を踏んできた私から、最後に一つアドバイスを送りたい。
ネットワークの障害対応において、最もやってはいけないのは「なんとなくあちこちの設定ファイルをいじること」だ。そして、アプリケーションのエラー画面(502や504)を見て、すぐにアプリコードのバグだと決めつけることだ。
レイヤーモデルを意識しよう。
1. Physical / Link / Network (IP疎通、ルーティング)
2. DNS (nslookup で名前解決の正当性を確認)
3. Transport / TLS (ポート開放、証明書有効期限)
4. Application (HTTPステータス、APIロジック)
障害が起きたら、まず nslookup を対話モードで開き、今見ているドメインが本当に正しい宛先を指しているか、自分の目で確かめること。その静かで確実な一歩が、パニックに陥った現場を最も早く静寂へと導く特効薬となる。
さあ、ターミナルを開こう。DNSのパケットたちが、今日も君のコマンドを待っている。
コメント