【実務・中級編】 digコマンドによる詳細なDNSレコード照会とトレース機能 – トラブルシューティング&ネットワーク運用監視実践ガイド

夜中の3時、データセンターの静寂を切り裂くアラート音。
「APIのレスポンスが突如としてタイムアウトしている」「マイクロサービス間の名前解決に失敗している」――。障害対応の現場において、インフラエンジニアやWebエンジニアが真っ直ぐに向き合うべき悪夢の始まりです。

こういう時、多くのエンジニアはとりあえず ping を叩き、次にブラウザでアクセスしてみたりします。しかし、百戦錬磨のNOCエンジニアから言わせれば、現代のクラウドネイティブなインフラストラクチャや複雑なWeb APIアーキテクチャにおいて、アプリケーション層の不調の9割は「DNS」に原因があります。そして、そのDNSの迷宮に迷い込んだとき、教科書通りの nslookup や無機質な dig では、真実の姿を捉えることはできません。

今回は、パケットがDNSの海をどのように渡り、どのネームサーバで座礁しているのかを丸裸にする dig コマンドの高度な利用法、特に +trace オプションを用いた再帰的問い合わせの追跡について、現場の泥臭い知見を交えて徹底的に解説します。

—

1. なぜ nslookup では戦えないのか? DNSの裏側で起きていること

実務の現場でトラブルシューティングを行う際、私は若手エンジニアに「nslookup は今すぐアンインストールしろ、あるいは封印しろ」と指導することがあります。言い過ぎかもしれませんが、それくらい nslookup の挙動はブラックボックスであり、OSの resolver ライブラリの挙動に依存するため、デバッグツールとしては不完全なのです。

一方の dig (Domain Information Groper) は、DNSのパケットフォーマットをそのままむき出しでDNSサーバに叩き込む、まさにネットワークエンジニアのためのメスです。

DNSの解決フローを思い出してください。私たちが api.example.com というAPIのエンドポイントを叩いたとき、背後では次のような壮大なリレーが行われています。

1. フルスタブリゾルバ(クライアント) から ローカルDNSキャッシュサーバ(ISPや社内DNS、8.8.8.8 など) への問い合わせ。
2. キャッシュにヒットしなければ、ローカルDNSサーバが「再帰的問い合わせ(Recursive Query)」の代理として立ち上がる。
3. ルートネームサーバ(.)に問い合わせ、TLD(.com)のネームサーバのIPアドレスを手に入れる。
4. TLDネームサーバに問い合わせ、権威DNSサーバ(Authoritative DNS Server)のIPアドレスを手に入れる。
5. 権威DNSサーバに直接「api.example.com のIPは何か?」と問い詰め、最終的なレコード(AやCNAME)を手に入れる。

この一連のバケツリレーのどこかで、TTL(Time To Live)のキャッシュ汚染が起きているのか、あるいは権威DNSのレコード設定が間違っているのかを突き止めるには、キャッシュの介在しない「本当の経路」をトレースする必要があるのです。

—

2. +trace オプションでルートヒントから名前解決を暴く

ローカルのDNSキャッシュ(systemd-resolved や nscd、あるいはパブリックDNSのキャッシュ)に毒された古い情報をいくら眺めていても、障害の根本解決には至りません。そこで登場するのが、dig の必殺技 +trace です。

実際に、私の手元にある検証環境で example.com の名前解決の全貌をトレースしてみましょう。以下のコマンドを実行してください。

# キャッシュを一切バイパスし、ルートヒントから再帰的問い合わせを完全トレースする
dig +trace example.com

このコマンドを実行すると、ターミナルには次のようなログが滝のように流れます(出力はイメージです)。

; <<>> DiG 9.16.1-Ubuntu <<>> +trace example.com
;; global options: +cmd
.                       5h17m48s IN NS  a.root-servers.net.
.                       5h17m48s IN NS  b.root-servers.net.
... (中略: ルートサーバー13基の情報がキャッシュなしで引かれる) ...
;; Received 525 bytes from 127.0.0.1#53(53) in 2 ms

com.                    172800  IN      NS      a.gtld-servers.net.
... (中略: .com TLDサーバーの情報) ...
;; Received 1172 bytes from 198.41.0.4#53(a.root-servers.net) in 42ms

example.com.            172800  IN      NS      a.iana-servers.net.
example.com.            172800  IN      NS      b.iana-servers.net.
;; Received 811 bytes from 192.5.6.30(a.gtld-servers.net) in 15ms

example.com.            86400   IN      A       93.184.216.34
;; Received 56 bytes from 199.43.135.53(a.iana-servers.net) in 12ms

このトレースから何を読み解くべきか?

1. 最初のステップ: dig はあらかじめ持っているルートヒント(世界に13基あるルートサーバのIP群)に対し、一番最初のパケットを投げます。上記の出力では 198.41.0.4 (a.root-servers.net) から .com の権威サーバ群のリストをゲットしています。
2. 次のステップ: 次に .com のTLDサーバ(192.5.6.30)へ直接突撃し、example.com の権威サーバ(a.iana-servers.net)の情報を引きずり出しています。
3. 最終着地: 最後に example.com の権威サーバに対して直接クエリを投げ、目的の Aレコード (93.184.216.34) を獲得しています。

もし途中のステップでタイムアウトしたり、古いIPアドレスが返ってきた場合、「どの階層の権威DNSがゾンビ化しているか」が一目瞭然になります。大規模障害の切り分けにおいて、これほど頼りになる情報はありません。

—

3. 実務で即座に使える dig の高度なパラメーター集

+trace 以外にも、現場のインフラエンジニアが知っておくべき実用的な dig のオプションがあります。これらを組み合わせることで、ほとんどのDNSトラブルは解体可能です。

① 特定の権威DNSサーバを直接指し撃つ (@server)

パブリックDNS(8.8.8.8 や 1.1.1.1)や、特定の社内プライベートDNS(例: 10.0.0.53)に直接クエリを飛ばして、そのサーバがどう応答するかをテストします。

# GoogleのパブリックDNSに対して直接、api.example.comのAレコードを問う
dig @8.8.8.8 api.example.com A

# 自社の社内プライベートDNS(スプリットDNS環境など)の動作確認
dig @10.0.0.53 internal-api.corp.local A

② ゾーン転送の脆弱性を突く(セキュリティ監査) (AXFR)

インフラのセキュリティ監査やペネトレーションテストでは、不適切な設定によって誰でもドメインの全レコードを吸い出せてしまう「ゾーン転送 (AXFR)」の穴がないかをチェックします。

# 権威DNSサーバに対してゾーン転送を要求する
dig @ns1.example.com example.com AXFR

*※もしここで全レコードがダンプされてしまったら、即座にマネージャへエスカレーションしてください。重大なセキュリティインシデントの芽です。*

③ 冗長な出力を削ぎ落とし、純粋な値だけを得る (+short)

スクリプトやCI/CDパイプライン、コンテナの起動スクリプトなどで、IPアドレスだけをサクッと取得したい場合に重宝します。

# 余計なヘッダーやフッターを一切削ぎ落とし、IPアドレスのみを出力
dig +short api.example.com A

—

4. コードからのDNS解決と、トラブル発生時のアプローチ

インフラエンジニアが調査した結果を、アプリケーション層(Web API設計者やバックエンドエンジニア)へフィードバックし、コード側でどのようにハンドリングすべきかも合わせて解説します。

例えば、Pythonの requests や Node.js の fetch を使って外部APIを叩く際、DNSの引き直しやタイムアウトが適切に設定されていないと、DNSサーバの一時的なスローダウンに引きずられてアプリケーション全体がスレッドプール枯渇(ドミノ障害)を起こします。

Pythonによる堅牢なAPIリクエストとDNS挙動の確認

Pythonの requests ライブラリ自体は低レイヤーのDNSキャッシュを持ちませんが、OSの getaddrinfo を呼び出します。TTLの挙動を意識したカスタムセッションの例を示します。

import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

def create_robust_session():
    """
    DNSの不安定さや一時的なネットワーク断に対応するため、
    リトライ戦略とコネクションプールを最適化したセッションを生成する。
    """
    session = requests.Session()
    
    # リトライ戦略の設定(DNS障害や5xxエラーに対する備え)
    retries = Retry(
        total=3,
        backoff_factor=1,  # 1秒, 2秒, 4秒とウェイトを増やす
        status_forcelist=[500, 502, 503, 504],
        raise_on_status=False
    )
    
    adapter = HTTPAdapter(max_retries=retries)
    session.mount("https://", adapter)
    session.mount("http://", adapter)
    
    return session

if __name__ == "__main__":
    api_endpoint = "https://api.example.com/v1/health"
    client = create_robust_session()
    
    try:
        # タイムアウトを明示的に指定(接続に3秒、読み取りに5秒)
        response = client.get(api_endpoint, timeout=(3.0, 5.0))
        print(f"Status Code: {response.status_code}")
        print(f"Response Body: {response.json()}")
    except requests.exceptions.Timeout:
        print("CRITICAL: APIへの接続がタイムアウトしました。DNSの遅延またはルーティング障害の可能性があります。")
    except requests.exceptions.ConnectionError as e:
        print(f"CRITICAL: 接続エラーです。digコマンドでの名前解決を確認してください: {e}")

トラブルシューティングの現場での実践的なフロー

もしあなたが今、APIの接続エラーに直面しているなら、次のステップでデバッグを進めてください。

1. まずは dig +short <domain> で現在の名前解決を確認する。

  • ここでエラーになる、あるいは古いIPが出るなら、ローカルのキャッシュ汚染を疑う。

2. dig @8.8.8.8 <domain> でパブリックDNS上の状態を確認する。

  • パブリック側が正常であれば、社内DNSやISPのDNSキャッシュが古い。

3. 最後に dig +trace <domain> を叩く。

  • 権威DNSの設定ミス、あるいはドメインのレジストラ(お名前.comやRoute53など)でのネームサーバ(NSレコード)の登録不備をあぶり出す。

—

5. おわりに

DNSは、インターネットという巨大な神経網において「住所録」の役割を果たす極めて重要なインフラです。ここが揺らぐと、どれほど洗練されたマイクロサービスアーキテクチャも、美しく設計されたWeb APIも、一瞬にして砂上の楼閣と化します。

dig コマンドの +trace オプションをはじめとする高度な診断手法は、単なるコマンドの暗記ではありません。パケットが世界のどこを旅し、どの権威のバトンリレーで躓いているのかを「頭の中で視覚化する」ための羅針盤です。

障害の夜、パニックになりそうな時こそ、深呼吸をしてターミナルを開き、dig に語りかけてみてください。DNSのパケットは、必ず真実のルートを教えてくれるはずです。さあ、次のアラートに備えましょう。

コメント

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