DNSの仕組み:開発者とDevOpsエンジニアのための完全ガイド

Networking tutorial - IT technology blog
Networking tutorial - IT technology blog

深夜2時に「サイトに接続できない」エラーを追いかけた経験があるなら、DNSがいかに重要で、そして何かが壊れるまでいかに見えない存在かがよくわかるはずだ。何ヶ月も静かに動き続けるインフラでありながら、突然それがデプロイと正常稼働の間に立ちはだかる唯一の壁になる。実際のシステムを管理するエンジニアにとって、DNSの知識は選択肢ではなく必須だ。深く理解すればするほど、謎のダウンタイムで眠れぬ夜を過ごす回数が減る。

クイックスタート:5分でわかるDNS

深く掘り下げる前に、まず手を動かしてみよう。ターミナルを開いて以下のコマンドを試してほしい:

# 基本的なDNSルックアップ
nslookup google.com

# より詳細 — DNS解決の完全な情報を表示
dig google.com

# ルートサーバーから完全な解決チェーンをトレース
dig +trace google.com

# 特定のDNSレコードタイプを照会
dig google.com MX        # メール交換レコード
dig google.com A         # IPv4アドレスレコード
dig google.com AAAA      # IPv6アドレスレコード
dig google.com TXT       # テキストレコード(SPF、DKIMはここに格納)

# 特定のDNSサーバーを使用(例:CloudflareのDNS 1.1.1.1)
dig @1.1.1.1 google.com

今すぐdig +trace google.comを実行してみよう。出力は約20行で、DNS全体のストーリーを物語っている。各セクションが読めるようになれば、デバッグが当てずっぽうでなくなる。

詳細解説:DNS名前解決の実際の仕組み

関係する4種類のサーバー

DNS名前解決は4種類のサーバーに依存している。それぞれが明確な役割を持つ:

  • DNSリゾルバー(再帰リゾルバー) — 最初の窓口。通常はISPが提供するか、Google(8.8.8.8)やCloudflare(1.1.1.1)などのパブリックサービスを使う。あなたの代わりに答えを探す役割を担う。
  • ルートネームサーバー — 世界中にAからMまで13セット存在する。google.comの場所は知らないが、次に誰に聞けばいいかは正確に知っている。
  • TLDネームサーバー — トップレベルドメインを管理する。.comのTLDサーバーは、google.comを担当する権威ネームサーバーがどれかを知っている。
  • 権威ネームサーバー — 最終的な権限を持つサーバー。ドメインの実際のDNSレコードを保持し、確定的な答えを返す。

名前解決の流れ:ステップバイステップ

ブラウザにgoogle.comと入力したとき、裏側で動くチェーンはこうなっている:

  1. ブラウザがローカルキャッシュを確認する。最近の答えがあればそれを使い、ここで終了。
  2. キャッシュミス — OSが/etc/hosts(Linux/macOS)またはC:\Windows\System32\drivers\etc\hosts(Windows)を確認する。
  3. それでもなければ、設定済みのDNSリゾルバーにリクエストが送られる。
  4. リゾルバーが自身のキャッシュを確認する。さらにキャッシュミスなら、階層をさかのぼり始める。
  5. リゾルバーがルートネームサーバーに問い合わせる:「.comを管理しているのは誰ですか?」
  6. ルートサーバー:「このアドレスの.com TLDサーバーに聞いてください。」
  7. リゾルバーが.com TLDサーバーに問い合わせる:「google.comを管理しているのは誰ですか?」
  8. TLDサーバー:「Googleの権威ネームサーバーに聞いてください。」
  9. リゾルバーがGoogleの権威サーバーに問い合わせる:「google.comのIPアドレスは何ですか?」
  10. 権威サーバーがAレコードで答える:142.250.80.46
  11. リゾルバーが結果をキャッシュし、あなたに返す。
  12. ブラウザがそのIPに接続する。ページが読み込まれる。

一連のチェーン全体は通常100ms未満で完了する。各レイヤーでのキャッシュにより、繰り返しのクエリは即時に感じられる——ウォームキャッシュからなら1ms未満のことも多い。

毎日使うDNSレコードタイプ

  • A — ホスト名をIPv4アドレスにマッピングする。圧倒的に最も一般的なレコード。
  • AAAA — ホスト名をIPv6アドレスにマッピングする。
  • CNAME — エイリアス。あるホスト名を別のホスト名に向ける(www.example.comexample.com)。
  • MX — メール交換。あなたのドメイン宛のメールをどこに配送するかをメールサーバーに伝える。
  • TXT — 自由形式のテキスト。SPFポリシー、DKIM公開鍵、ドメイン認証トークンの置き場。
  • NS — あなたのドメインの権威サーバーがどれかを指定する。
  • PTR — 逆引きDNS。IPをホスト名に逆引きする——メールサーバーのレピュテーションスコアリングに不可欠。
  • SRV — サービスロケーション。Kubernetesのサービスディスカバリー、SIP、XMPPなどのプロトコルで使用される。

応用:実際のインフラでのDNS活用

移行時のTTLとキャッシュ管理

TTL(Time To Live)は、クライアントが再クエリを行うまでDNSレコードをキャッシュできる秒数だ。移行時にこれを誤ると、古いレコードが消えるまで何時間も待つことになる。

# ドメインの現在のTTLを確認
dig google.com | grep -i ttl

# LinuxのDNSキャッシュをフラッシュ(systemd-resolved)
sudo systemd-resolve --flush-caches

# macOSのDNSキャッシュをフラッシュ
sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder

# Windows
ipconfig /flushdns

多くのチームがやってしまうミス:TTLを先に下げずにDNSレコードを変更すること。デフォルトのTTL 3600秒(1時間)では、変更後も一部のユーザーが1時間丸ごと古いIPにアクセスし続ける。移行の少なくとも24時間前にTTLを300秒に下げておこう。そのうえで変更を加える。何か問題が起きても、60分ではなく5分でロールバックできる。

開発環境用のローカルDNSオーバーライド

# ローカルオーバーライドを追加 — DNSクエリが外部に出ない
echo "127.0.0.1 myapp.local" | sudo tee -a /etc/hosts

# 正しく解決されることを確認
ping myapp.local
curl http://myapp.local

DockerでローカルDNSリゾルバーを実行する

/etc/hostsを手動編集して5つ以上のサービスを管理するのはすぐに限界が来る。Dockerでコンテナとして動かすローカルDNSリゾルバーの方がすっきりする:

# DockerでDNSmasqを実行
docker run -d \
  --name dnsmasq \
  -p 53:53/udp \
  -p 53:53/tcp \
  -v $(pwd)/dnsmasq.conf:/etc/dnsmasq.conf \
  andyshinn/dnsmasq

# dnsmasq.confの設定例:
# address=/myapp.local/127.0.0.1
# address=/api.local/192.168.1.100

PythonでのDNSクエリ

アプリケーションコード内でDNSルックアップが必要?dnspythonライブラリがきれいに処理してくれる:

pip install dnspython
import dns.resolver

# Aレコードを解決
answers = dns.resolver.resolve('google.com', 'A')
for rdata in answers:
    print(f"IP: {rdata.address}")

# MXレコードを解決
mx_records = dns.resolver.resolve('gmail.com', 'MX')
for rdata in mx_records:
    print(f"優先度: {rdata.preference}, メールサーバー: {rdata.exchange}")

# ドメインの存在を確認
try:
    dns.resolver.resolve('nonexistent.example.com', 'A')
except dns.resolver.NXDOMAIN:
    print("ドメインが存在しません")
except dns.resolver.NoAnswer:
    print("Aレコードが見つかりません")

DNSデバッグ:実際に効くアプローチ

遅い、または壊れた名前解決を特定する

# DNSクエリ時間を計測
time dig google.com

# システムが使用しているDNSサーバーを確認
cat /etc/resolv.conf          # Linux
scutil --dns | head -20       # macOS

# 複数のリゾルバーからテストして問題の所在を絞り込む
dig @8.8.8.8 yoursite.com     # Google
dig @1.1.1.1 yoursite.com     # Cloudflare
dig @9.9.9.9 yoursite.com     # Quad9

# リゾルバーをループして素早く比較
for server in 8.8.8.8 1.1.1.1 208.67.222.222; do
  echo "=== $server ==="
  dig @$server yoursite.com +short
done

DNSハイジャックを検出する

DNSハイジャックは思っている以上によく起きる——意図的に行うISPもあれば、攻撃者が機会をうかがって仕掛けることもある。どちらも目に見える警告なしにクエリをリダイレクトする。Nmapでネットワーク上の異常なポートや挙動を確認するのも有効な手段だが、まず2秒でできるDNS確認から始めよう:

# ISPのリゾルバーとパブリックDNSを比較
dig google.com +short
dig @8.8.8.8 google.com +short

# 結果が違う?何かがクエリを傍受している。

DNSSEC:暗号による検証

DNSSECは公開鍵暗号方式でDNSレコードに署名する。悪意あるリゾルバーが偽のレコードを注入するキャッシュポイズニング攻撃を、レコードの正当性をリゾルバーが検証できるようにすることで防ぐ。サーバーレベルの攻撃防御としては、Fail2Banによるブルートフォース攻撃の自動遮断と組み合わせると多層防御が実現できる。ドメインがDNSSECを使っているか確認するには:

# DNSSECのステータスを確認
dig +dnssec google.com

# レスポンスヘッダーの"ad"フラグを確認("authenticated data"=認証済みデータ)
# answerセクションのRRSIGレコードも確認

ワンライナーでドメインのヘルスチェック

DOMAIN="yourdomain.com"
echo "=== Aレコード ===" && dig $DOMAIN A +short
echo "=== MXレコード ===" && dig $DOMAIN MX +short
echo "=== TXTレコード ===" && dig $DOMAIN TXT +short
echo "=== NSレコード ===" && dig $DOMAIN NS +short
echo "=== TTL ===" && dig $DOMAIN A | grep -i "$DOMAIN" | awk '{print "TTL:", $2, "秒"}'

DNSは投資が報われるインフラだ。深く理解しているエンジニアは、インシデント対応の時間を本当の問題解決に使える。そうでないエンジニアは、ステージング環境で動いていたデプロイがなぜ本番で失敗するのかと首をひねりながらダッシュボードを眺め続ける。

digを筋肉に刻み込もう。ここで紹介したコマンドは、誤った移行から壊れたメールサーバーまで、現実のDNSシナリオの大部分をカバーしている。何かが炎上しているとき、どこを見ればいいかを実際に知っているのがあなたになる。

Share: