- Authors
- Name
- 1. DNSとは何か
- 2. DNS名前解決プロセス
- 3. よくあるDNS問題
- 4. DNSデバッグツール
- 5. DNSキャッシュの問題
- 6. resolv.confとnsswitch.confの設定
- 7. KubernetesにおけるCoreDNSトラブルシューティング
- 8. ndots設定とSearch Domain
- 9. 実践デバッグシナリオ
- 10. 便利なDNSデバッグワンライナー集
- 11. まとめとチェックリスト
1. DNSとは何か
DNS(Domain Name System)は、人間が読めるドメイン名(例:example.com)を、コンピュータが通信に使用するIPアドレス(例:93.184.216.34)に変換する分散階層型ネーミングシステムです。インターネットの電話帳とも呼ばれ、ほぼすべてのネットワーク通信の最初のステップを担っています。
1.1 DNSが重要な理由
- Webブラウザの HTTP リクエスト、API呼び出し、メール送信など、ほぼすべてのネットワーク操作がDNSルックアップから始まります。
- DNSの障害はサービス全体の障害に波及する可能性があります。
- マイクロサービス環境では、サービスディスカバリの中核的な役割を果たします。
2. DNS名前解決プロセス
クライアントがドメイン名を入力すると、以下のステップでIPアドレスを取得します。
2.1 全体の流れ
1. クライアント → ローカルDNSキャッシュ確認(/etc/hostsを含む)
2. ローカルキャッシュミス → 再帰リゾルバ(ISPまたは設定されたDNSサーバ)に問い合わせ
3. 再帰リゾルバ → ルートネームサーバ(.)に問い合わせ
4. ルートNS → TLDネームサーバ(.com、.netなど)を応答
5. TLD NS → 権威ネームサーバを応答
6. 権威NS → 最終的なIPアドレスを応答
7. 再帰リゾルバ → 結果をキャッシュしてクライアントに応答
2.2 再帰的(Recursive)vs 反復的(Iterative)問い合わせ
# dig +traceで再帰的な解決を追跡
$ dig +trace example.com
; <<>> DiG 9.18.18 <<>> +trace example.com
;; global options: +cmd
. 518400 IN NS a.root-servers.net.
. 518400 IN NS b.root-servers.net.
;; Received 239 bytes from 127.0.0.53#53(127.0.0.53) in 1 ms
com. 172800 IN NS a.gtld-servers.net.
com. 172800 IN NS b.gtld-servers.net.
;; Received 1170 bytes from 198.41.0.4#53(a.root-servers.net) in 23 ms
example.com. 172800 IN NS a.iana-servers.net.
example.com. 172800 IN NS b.iana-servers.net.
;; Received 356 bytes from 192.5.6.30#53(a.gtld-servers.net) in 15 ms
example.com. 86400 IN A 93.184.216.34
;; Received 56 bytes from 199.43.135.53#53(a.iana-servers.net) in 78 ms
2.3 DNSレコードの種類
| レコード | 説明 | 例 |
|---|---|---|
| A | IPv4アドレスマッピング | example.com → 93.184.216.34 |
| AAAA | IPv6アドレスマッピング | example.com → 2606:2800:220:1:... |
| CNAME | 正規名(エイリアス) | www.example.com → example.com |
| MX | メールサーバ | example.com → mail.example.com |
| NS | ネームサーバ委任 | example.com → ns1.example.com |
| TXT | テキストレコード(SPF、DKIMなど) | v=spf1 include:... |
| SRV | サービスロケータ | _http._tcp.example.com |
| PTR | 逆引き(IP→ドメイン) | 34.216.184.93 → example.com |
| SOA | 権威開始 | ゾーン管理メタデータ |
3. よくあるDNS問題
3.1 NXDOMAIN(存在しないドメイン)
問い合わせたドメインが存在しない場合に返される応答です。
$ dig nonexistent.example.com
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 12345
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1
;; QUESTION SECTION:
;nonexistent.example.com. IN A
;; AUTHORITY SECTION:
example.com. 900 IN SOA ns1.example.com. admin.example.com. 2024010101 3600 900 604800 86400
原因分析:
- ドメイン名のタイプミス
- DNSレコードがまだ作成されていない
- ドメイン登録の有効期限切れ
- DNS伝播(propagation)が完了していない
3.2 DNSタイムアウト
$ dig @10.0.0.1 example.com +timeout=5
; <<>> DiG 9.18.18 <<>> @10.0.0.1 example.com +timeout=5
; (1 server found)
;; global options: +cmd
;; connection timed out; no servers could be reached
原因分析:
- DNSサーバがダウンまたはアクセス不可
- ファイアウォールがUDP/TCPポート53をブロック
- ネットワーク接続の問題
- DNSサーバの過負荷
3.3 古い・誤ったレコード(Stale/Wrong Records)
# 期待と異なるIPアドレスが返される場合
$ dig api.myservice.com +short
192.168.1.100 # 期待値: 10.0.1.50
# 複数のDNSサーバで比較確認
$ dig @8.8.8.8 api.myservice.com +short
10.0.1.50
$ dig @1.1.1.1 api.myservice.com +short
10.0.1.50
$ dig @192.168.1.1 api.myservice.com +short
192.168.1.100 # ローカルDNSキャッシュが古い値を返している
4. DNSデバッグツール
4.1 dig(Domain Information Groper)
最も強力で広く使われているDNSデバッグツールです。
# 基本的な問い合わせ
$ dig example.com
# 特定のレコードタイプを問い合わせ
$ dig example.com MX
$ dig example.com AAAA
$ dig example.com TXT
# 簡潔な出力
$ dig example.com +short
93.184.216.34
# 特定のDNSサーバを指定
$ dig @8.8.8.8 example.com
# 逆引き
$ dig -x 93.184.216.34
# すべてのレコードタイプを問い合わせ
$ dig example.com ANY
# 応答時間の確認(Query time)
$ dig example.com | grep "Query time"
;; Query time: 23 msec
# TCPを使用(UDPの代わりに)
$ dig +tcp example.com
# DNSSEC検証
$ dig +dnssec example.com
4.2 nslookup
対話型モードと非対話型モードの両方をサポートします。
# 基本的な問い合わせ
$ nslookup example.com
Server: 127.0.0.53
Address: 127.0.0.53#53
Non-authoritative answer:
Name: example.com
Address: 93.184.216.34
# 特定のDNSサーバを使用
$ nslookup example.com 8.8.8.8
# 特定のレコードタイプ
$ nslookup -type=MX example.com
# 対話型モード
$ nslookup
> set type=NS
> example.com
Server: 127.0.0.53
Address: 127.0.0.53#53
Non-authoritative answer:
example.com nameserver = a.iana-servers.net.
example.com nameserver = b.iana-servers.net.
> exit
4.3 host
簡潔な出力を提供する軽量ツールです。
# 基本的な問い合わせ
$ host example.com
example.com has address 93.184.216.34
example.com has IPv6 address 2606:2800:220:1:248:1893:25c8:1946
example.com mail is handled by 0 .
# 逆引き
$ host 93.184.216.34
34.216.184.93.in-addr.arpa domain name pointer example.com.
# 特定のレコードタイプ
$ host -t NS example.com
example.com name server a.iana-servers.net.
example.com name server b.iana-servers.net.
# 詳細な出力
$ host -v example.com
4.4 drill
DNSSEC対応が強化されたツールです(ldnsパッケージ)。
# 基本的な問い合わせ
$ drill example.com
;; ->>HEADER<<- opcode: QUERY, rcode: NOERROR, id: 54321
;; QUESTION SECTION:
;; example.com. IN A
;; ANSWER SECTION:
example.com. 86400 IN A 93.184.216.34
# DNSSEC追跡
$ drill -DT example.com
# 特定のサーバに問い合わせ
$ drill @8.8.8.8 example.com
5. DNSキャッシュの問題
5.1 TTL(Time To Live)
# TTL値の確認
$ dig example.com
;; ANSWER SECTION:
example.com. 86400 IN A 93.184.216.34
# ^^^^^ TTL: 86400秒 = 24時間
TTLが長いと、DNSの変更が伝播するまでに時間がかかります。DNSマイグレーション前にはTTLを事前に短くしておくことをお勧めします。
# TTL戦略の例
# 1. マイグレーション24時間前: TTLを300秒(5分)に短縮
# 2. マイグレーション実行: IPアドレスを変更
# 3. 伝播完了を確認後: TTLを元の値に復元
5.2 ネガティブキャッシュ(Negative Caching)
NXDOMAIN応答もキャッシュされます。SOAレコードのMINIMUMフィールドがネガティブキャッシュTTLを決定します。
$ dig example.com SOA
;; ANSWER SECTION:
example.com. 86400 IN SOA ns1.example.com. admin.example.com. (
2024010101 ; Serial
3600 ; Refresh
900 ; Retry
604800 ; Expire
86400 ) ; Minimum TTL(ネガティブキャッシュTTL)
5.3 ローカルDNSキャッシュの管理
# Linux: systemd-resolvedのキャッシュ統計を確認
$ resolvectl statistics
Current Cache Size: 152
Cache Hits: 1234
Cache Misses: 567
# Linux: systemd-resolvedのキャッシュをフラッシュ
$ sudo resolvectl flush-caches
# macOS: DNSキャッシュをフラッシュ
$ sudo dscacheutil -flushcache && sudo killall -HUP mDNSResponder
# Windows: DNSキャッシュをフラッシュ
> ipconfig /flushdns
6. resolv.confとnsswitch.confの設定
6.1 /etc/resolv.conf
$ cat /etc/resolv.conf
# DNSサーバ設定(最大3つ)
nameserver 8.8.8.8
nameserver 8.8.4.4
nameserver 1.1.1.1
# デフォルト検索ドメイン
search mycompany.com prod.mycompany.com
# オプション
options timeout:2 # タイムアウト2秒
options attempts:3 # リトライ3回
options ndots:5 # FQDN判定基準(下記で詳細説明)
options rotate # DNSサーバのラウンドロビン
options edns0 # EDNS0を有効化
主要な設定の説明:
nameserver:使用するDNSサーバ(順番に試行、最大3つ)search:短いホスト名に自動的に付加するドメインのリストdomain:searchと似ているが、1つのドメインのみ指定options ndots:n:ドット(.)がn個未満の名前は、searchドメインを先に試行
6.2 /etc/nsswitch.conf
名前解決の順序を制御します。
$ grep hosts /etc/nsswitch.conf
hosts: files dns myhostname
# files = /etc/hostsファイルを最初に確認
# dns = DNSサーバに問い合わせ
# myhostname = ローカルホスト名を解決(systemd)
# /etc/hostsファイルの例
$ cat /etc/hosts
127.0.0.1 localhost
127.0.1.1 myserver
10.0.1.50 api.internal.mycompany.com api-internal
192.168.1.100 db-master.mycompany.com
6.3 systemd-resolvedの確認
# 現在のDNS設定を確認
$ resolvectl status
Global
Protocols: -LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
resolv.conf mode: stub
Link 2 (eth0)
Current Scopes: DNS
Protocols: +DefaultRoute +LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
Current DNS Server: 8.8.8.8
DNS Servers: 8.8.8.8 8.8.4.4
# 特定のドメインの名前解決テスト
$ resolvectl query example.com
example.com: 93.184.216.34 -- link: eth0
2606:2800:220:1:248:1893:25c8:1946 -- link: eth0
7. KubernetesにおけるCoreDNSトラブルシューティング
7.1 CoreDNSアーキテクチャ
Kubernetesクラスタ内で、CoreDNSはサービスディスカバリを担当します。すべてのPodからのDNS問い合わせはCoreDNSを通じて処理されます。
# CoreDNS Podの状態確認
$ kubectl get pods -n kube-system -l k8s-app=kube-dns
NAME READY STATUS RESTARTS AGE
coredns-5d78c9869d-abc12 1/1 Running 0 7d
coredns-5d78c9869d-def34 1/1 Running 0 7d
# CoreDNSサービスの確認
$ kubectl get svc -n kube-system kube-dns
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 30d
7.2 CoreDNS Corefileの確認
$ kubectl get configmap coredns -n kube-system -o yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: coredns
namespace: kube-system
data:
Corefile: |
.:53 {
errors
health {
lameduck 5s
}
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
prometheus :9153
forward . /etc/resolv.conf {
max_concurrent 1000
}
cache 30
loop
reload
loadbalance
}
7.3 CoreDNSログの確認
# CoreDNSのログを確認
$ kubectl logs -n kube-system -l k8s-app=kube-dns --tail=50
[INFO] 10.244.0.15:45678 - 12345 "A IN my-service.default.svc.cluster.local. udp 54 false 512" NOERROR qr,aa,rd 106 0.000234s
[INFO] 10.244.0.15:45679 - 12346 "A IN external-api.com. udp 34 false 512" NOERROR qr,rd,ra 62 0.023456s
# logプラグインを有効化(Corefileにlogを追加)
# .:53 {
# log
# errors
# ...
# }
7.4 Pod内でのDNSデバッグ
# デバッグ用Podを作成
$ kubectl run dns-debug --image=nicolaka/netshoot --rm -it --restart=Never -- bash
# Pod内でDNS解決をテスト
bash-5.1# nslookup kubernetes.default.svc.cluster.local
Server: 10.96.0.10
Address: 10.96.0.10#53
Name: kubernetes.default.svc.cluster.local
Address: 10.96.0.1
# digで詳細確認
bash-5.1# dig kubernetes.default.svc.cluster.local
;; ANSWER SECTION:
kubernetes.default.svc.cluster.local. 30 IN A 10.96.0.1
;; Query time: 1 msec
;; SERVER: 10.96.0.10#53(10.96.0.10)
# 外部ドメインの名前解決を確認
bash-5.1# dig example.com +short
93.184.216.34
# PodのDNS設定を確認
bash-5.1# cat /etc/resolv.conf
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
8. ndots設定とSearch Domain
8.1 ndotsの動作原理
ndotsオプションは、問い合わせ名に含まれるドット(.)の数がこの値未満の場合、searchドメインを先に付加して問い合わせます。
# Kubernetesのデフォルト設定: ndots:5
# search default.svc.cluster.local svc.cluster.local cluster.local
# "api.example.com" を問い合わせた場合(ドット2個 < ndots 5)
# 実際の問い合わせ順序:
1. api.example.com.default.svc.cluster.local → NXDOMAIN
2. api.example.com.svc.cluster.local → NXDOMAIN
3. api.example.com.cluster.local → NXDOMAIN
4. api.example.com. → 成功!
これにより、外部ドメインの問い合わせ時に不要なDNSクエリが3回追加で発生します。
8.2 ndotsの最適化
# Pod specでdnsConfigからndotsを調整
apiVersion: v1
kind: Pod
metadata:
name: optimized-pod
spec:
containers:
- name: app
image: myapp:latest
dnsConfig:
options:
- name: ndots
value: '2'
# FQDNを使用して不要な問い合わせを回避(末尾にドットを追加)
# 非効率:
$ dig api.example.com # ndotsにより複数回問い合わせ
# 効率的:
$ dig api.example.com. # FQDNとして直接問い合わせ(trailing dot)
8.3 dnsPolicyオプション
# ClusterFirst(デフォルト): CoreDNSを最初に使用
apiVersion: v1
kind: Pod
spec:
dnsPolicy: ClusterFirst
# Default: ノードのDNS設定をそのまま使用
spec:
dnsPolicy: Default
# None: dnsConfigから直接設定
spec:
dnsPolicy: None
dnsConfig:
nameservers:
- 8.8.8.8
- 1.1.1.1
searches:
- my-namespace.svc.cluster.local
- svc.cluster.local
options:
- name: ndots
value: "2"
9. 実践デバッグシナリオ
9.1 シナリオ1: サービス間通信の失敗
# 症状: Pod AからPod Bのサービスへの接続が失敗
$ kubectl exec pod-a -- curl http://my-service:8080
curl: (6) Could not resolve host: my-service
# Step 1: PodのDNS設定を確認
$ kubectl exec pod-a -- cat /etc/resolv.conf
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
# Step 2: CoreDNSに直接問い合わせ
$ kubectl exec pod-a -- dig @10.96.0.10 my-service.default.svc.cluster.local
;; status: NXDOMAIN
# Step 3: サービスの存在を確認
$ kubectl get svc my-service -n default
Error from server (NotFound): services "my-service" not found
# Step 4: 正しいネームスペースを確認
$ kubectl get svc --all-namespaces | grep my-service
production my-service ClusterIP 10.96.45.123 <none> 8080/TCP 5d
# 解決: ネームスペースを含むFQDNを使用
$ kubectl exec pod-a -- curl http://my-service.production.svc.cluster.local:8080
9.2 シナリオ2: 外部ドメイン名前解決の失敗
# 症状: Podから外部API呼び出しが失敗
$ kubectl exec my-pod -- curl https://api.external.com
curl: (6) Could not resolve host: api.external.com
# Step 1: CoreDNSが内部クエリで正常か確認
$ kubectl exec my-pod -- dig @10.96.0.10 kubernetes.default.svc.cluster.local +short
10.96.0.1 # 内部DNSは正常
# Step 2: CoreDNSのアップストリームフォワーディングを確認
$ kubectl exec my-pod -- dig @10.96.0.10 api.external.com
;; status: SERVFAIL
# Step 3: CoreDNSのログを確認
$ kubectl logs -n kube-system -l k8s-app=kube-dns | grep "api.external.com"
[ERROR] plugin/forward: no nameservers found
# Step 4: CoreDNSのforward設定を確認
$ kubectl get configmap coredns -n kube-system -o jsonpath='{.data.Corefile}'
# forward . /etc/resolv.conf を確認
# Step 5: CoreDNS Podのresolv.confを確認
$ kubectl exec -n kube-system coredns-5d78c9869d-abc12 -- cat /etc/resolv.conf
nameserver 169.254.169.253 # クラウドDNSにアクセスできない可能性
# 解決: Corefileでforward先を明示的に指定
# forward . 8.8.8.8 8.8.4.4
9.3 シナリオ3: 間欠的なDNSタイムアウト
# 症状: DNS問い合わせが間欠的に5秒以上かかる
$ time dig @10.96.0.10 example.com
;; Query time: 5003 msec # 5秒タイムアウト後にリトライ
# 原因: Linux conntrackのレースコンディション(DNAT + UDP)
# UDPのDNSパケットがconntrackテーブルで衝突する可能性
# 確認: conntrackテーブルの状態
$ sudo conntrack -S
cpu=0 found=0 invalid=1523 insert=0 insert_failed=156 drop=156
# ^^^^^^^^^^^^^ insert失敗があると問題
# 解決方法1: TCP DNSを使用
# CoreDNS Corefileにforce_tcpオプションを追加
# 解決方法2: NodeLocal DNSCacheをデプロイ
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/kubernetes/master/cluster/addons/dns/nodelocaldns/nodelocaldns.yaml
# 解決方法3: Podでsingle-request-reopenオプションを使用
apiVersion: v1
kind: Pod
spec:
dnsConfig:
options:
- name: single-request-reopen
value: ""
9.4 シナリオ4: DNS伝播遅延の確認
# DNS変更後、複数のサーバで伝播状態を確認
$ for dns in 8.8.8.8 1.1.1.1 9.9.9.9 208.67.222.222; do
echo "=== $dns ==="
dig @$dns api.myservice.com +short +timeout=3
done
=== 8.8.8.8 ===
10.0.1.50
=== 1.1.1.1 ===
10.0.1.50
=== 9.9.9.9 ===
192.168.1.100 # まだ古いレコード
=== 208.67.222.222 ===
192.168.1.100 # まだ古いレコード
# TTLを確認してキャッシュの有効期限を予測
$ dig @9.9.9.9 api.myservice.com | grep -A1 "ANSWER SECTION"
;; ANSWER SECTION:
api.myservice.com. 1423 IN A 192.168.1.100
# ^^^^ 残りTTL: 約24分後にキャッシュ期限切れ
10. 便利なDNSデバッグワンライナー集
# 1. DNS応答時間のベンチマーク
$ for i in $(seq 1 10); do dig example.com | grep "Query time"; done
# 2. 複数ドメインの一括問い合わせ
$ for domain in api.example.com web.example.com db.example.com; do
echo "$domain: $(dig +short $domain)"
done
# 3. DNSレコード変更のモニタリング
$ watch -n 5 "dig +short api.myservice.com @8.8.8.8"
# 4. 逆引きDNSの一括確認
$ for ip in 10.0.1.{1..10}; do
result=$(dig +short -x $ip)
echo "$ip -> ${result:-NO PTR}"
done
# 5. DNSSEC検証状態の確認
$ dig +dnssec +short example.com
93.184.216.34
A 13 2 86400 20240315000000 20240301000000 12345 example.com. <base64_signature>
# 6. Kubernetesの全サービスのDNS解決を確認
$ kubectl get svc --all-namespaces -o jsonpath='{range .items[*]}{.metadata.name}.{.metadata.namespace}.svc.cluster.local{"\n"}{end}' | \
while read fqdn; do
result=$(kubectl exec dns-debug -- dig +short $fqdn 2>/dev/null)
echo "$fqdn -> ${result:-FAILED}"
done
11. まとめとチェックリスト
DNS問題が発生した場合、以下の順序で診断します。
/etc/resolv.confの設定を確認(nameserver、search、ndots)digまたはnslookupで基本的なDNS問い合わせをテスト- 特定のDNSサーバを指定して問い合わせ(
dig @8.8.8.8) +traceオプションで完全な名前解決パスを追跡- TTLを確認してキャッシュの問題かどうかを判断
- Kubernetes環境であればCoreDNS Podの状態とログを確認
ndotsとsearchドメインの設定がパフォーマンスに与える影響を検討- conntrack関連の間欠的な問題はNodeLocal DNSCacheの導入を検討
DNSはネットワーク問題の根本原因であることが非常に多いです。体系的なデバッグの習慣を身につければ、障害対応の時間を大幅に短縮できます。