CoreDNS、ネットワーク、ポリシー、またはカーネルの問題によって引き起こされる ACK クラスターでの DNS 障害を診断し、修正します。
DNS 名前解決の仕組み
アプリケーション Pod が DNS クエリを送信すると、次のパスをたどります。
-
Pod は、
/etc/resolv.conf内のアドレス (通常は kube-dns サービスの IP) に DNS クエリを送信します。 -
kube-dns は、
kube-system名前空間内の CoreDNS Pod にクエリを転送します。 -
.cluster.localで終わる内部ドメイン名の場合、CoreDNS は上流 DNS サーバーに接続せずにキャッシュから解決します。 -
外部ドメイン名の場合、CoreDNS は設定で指定された上流 DNS サーバーにクエリを転送します。デフォルトの上流サーバーは
100.100.2.136と100.100.2.138で、どちらも VPC (仮想プライベートクラウド) にデプロイされています。
NodeLocal DNSCache を使用すると、クエリはまずローカルキャッシュ (169.254.20.10) に送信され、解決されない場合にのみ kube-dns にフォールバックします。
基本概念
| 用語 | 説明 |
|---|---|
| 内部ドメイン名 | .cluster.local で終わるドメイン。CoreDNS は上流サーバーではなく、キャッシュから解決します。 |
| 外部ドメイン名 | .cluster.local で終わらないドメイン。CoreDNS は上流 DNS サーバーに転送します。 |
| アプリケーション Pod | システムコンポーネント以外の Pod。 |
| kube-dns サービス | DNS トラフィックを CoreDNS Pod にルーティングする Kubernetes サービス。その IP は、アプリケーション Pod のデフォルトのネームサーバーです。 |
| NodeLocal DNSCache | 各ノードでローカル DNS キャッシュを実行する DaemonSet。有効にすると、Pod は kube-dns の代わりにローカルキャッシュ (169.254.20.10) にクエリを送信します。 |
| 上流 DNS サーバー | CoreDNS が外部ドメインのために接続する DNS サーバー。デフォルトは 100.100.2.136 と 100.100.2.138 です。 |
ステップ 1:エラーメッセージの特定
エラーメッセージを照合して、考えられる障害カテゴリを特定します。
| クライアント | エラーメッセージ | 考えられる原因 |
|---|---|---|
| ping | ping: xxx.yyy.zzz: Name or service not known |
ドメインが存在しないか、DNS サーバーに到達できません。レイテンシーが 5 秒を超える場合は、サーバーに到達できないことを示します。 |
| curl | curl: (6) Could not resolve host: xxx.yyy.zzz |
上記と同じです。 |
| PHP HTTP client | php_network_getaddresses: getaddrinfo failed: Name or service not known in xxx.php on line yyy |
上記と同じです。 |
| Golang HTTP client | dial tcp: lookup xxx.yyy.zzz on 100.100.2.136:53: no such host |
ドメインが存在しません。 |
| dig | ;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: xxxxx |
ドメインが存在しません。 |
| Golang HTTP client | dial tcp: lookup xxx.yyy.zzz on 100.100.2.139:53: read udp 192.168.0.100:42922->100.100.2.139:53: i/o timeout |
DNS サーバーに到達できません。 |
| dig | ;; connection timed out; no servers could be reached |
DNS サーバーに到達できません。 |
-
ドメインが存在しない → ドメイン名自体が正しいかどうかを確認します。外部ドメインのみが失敗する場合は、「外部ドメイン名が解決できない」をご参照ください。
-
DNS サーバーに到達できない → ステップ 2 に進みます。
ステップ 2:DNS ポリシーとサーバーアドレスの確認
Pod が DNS サーバーとして CoreDNS を使用していることを確認します。
DNS ポリシーと設定を取得します。
# Pod の DNS ポリシーを表示
kubectl get pod <pod-name> -o yaml
# Pod にログインして DNS 設定を確認
kubectl exec -it <pod-name> -- cat /etc/resolv.conf
dnsPolicy フィールドと /etc/resolv.conf の nameserver エントリを確認します。
dnsPolicy の値 |
動作 |
|---|---|
ClusterFirst |
デフォルト。Pod は kube-dns サービスの IP を DNS サーバーとして使用します。 |
ClusterFirstWithHostNet |
ホストネットワーク Pod の場合は ClusterFirst と同じです。 |
Default |
Pod は Elastic Compute Service (ECS) ノードから DNS 設定を継承します。Pod がクラスター内部の名前を解決しない場合にのみ使用します。 |
None |
DNS は dnsConfig を通じて完全に設定されます。NodeLocal DNSCache はこれを使用して、169.254.20.10 と kube-dns の IP をネームサーバーとして挿入します。 |
Pod が CoreDNS を使用していない場合 (ネームサーバーが kube-dns サービスの IP ではない場合)、Pod が過負荷であるか、conntrack テーブルが満杯である可能性があります。「クライアントの過負荷による DNS 名前解決の失敗」および「conntrack テーブルが満杯になる」をご参照ください。
Pod が NodeLocal DNSCache を使用している場合 (ネームサーバーが 169.254.20.10 の場合)、「NodeLocal DNSCache が機能しない」および「Alibaba Cloud DNS PrivateZone の名前が解決できない」をご参照ください。
Pod が CoreDNS を使用している場合は、ステップ 3 に進みます。
ステップ 3:CoreDNS Pod の正常性の確認
CoreDNS Pod を確認します。
# CoreDNS Pod のステータスと配置を表示
kubectl -n kube-system get pod -o wide -l k8s-app=kube-dns
期待される出力:
NAME READY STATUS RESTARTS AGE IP NODE
coredns-xxxxxxxxx-xxxxx 1/1 Running 0 25h 172.20.6.53 cn-hangzhou.192.168.0.198
# リアルタイムの CPU とメモリ使用量を表示
kubectl -n kube-system top pod -l k8s-app=kube-dns
期待される出力:
NAME CPU(cores) MEMORY(bytes)
coredns-xxxxxxxxx-xxxxx 3m 18Mi
-
Pod が実行中の状態ではない →
kubectl -n kube-system describe pod <CoreDNS-pod-name>を実行して原因を特定します。「CoreDNS Pod が正常に実行されない」をご参照ください。 -
CPU またはメモリが上限に近い → 「CoreDNS Pod の過負荷」をご参照ください。
-
Pod 間で CPU 使用率が不均一 → 「DNS クエリが CoreDNS Pod 間で均等に分散されない」をご参照ください。
ステップ 4:CoreDNS 運用ログの確認
kubectl -n kube-system logs -f --tail=500 --timestamps <coredns-pod-name>
| フラグ | 説明 |
|---|---|
-f |
ログ出力をストリーミングします。 |
--tail=500 |
最後の 500 行を表示します。 |
--timestamps |
各ログ行にタイムスタンプを含めます。 |
既知の問題に一致するエラーパターンを探します。DNS クエリレベルのログについては、まず CoreDNS ログプラグインを有効にします。「DNS 名前解決の設定」をご参照ください。
ログプラグインを有効にすると、解決された各クエリは次のようなエントリを生成します。
[INFO] 172.20.2.25:44525 - 36259 "A IN redis-master.default.svc.cluster.local. udp 56 false 512" NOERROR qr,aa,rd 110 0.000116946s
一般的なレスポンスコード:
| レスポンスコード | 意味 | 対処法 |
|---|---|---|
NOERROR |
正常に解決されました。 | 対応は不要です。 |
NXDOMAIN |
上流サーバーにドメインが存在しません。 | ドメイン名に解決されない検索サフィックスが含まれていないか確認します。 |
SERVFAIL |
上流 DNS サーバーがエラーを返しました。 | CoreDNS から上流サーバーへの接続性を確認します。 |
REFUSED |
上流サーバーがクエリを拒否しました。 | CoreDNS の Corefile 設定とノードの /etc/resolv.conf を確認します。 |
DNS レスポンスコードは RFC 1035 で定義されています。
ステップ 5:エラーの再現と原因の切り分け
エラーが常に発生する場合:
-
DNS クエリログでエラーレスポンスコードを確認します。「外部ドメイン名が解決できない」をご参照ください。
-
アプリケーション Pod と CoreDNS 間のネットワーク接続性をテストします。「アプリケーション Pod と CoreDNS 間のネットワーク接続性のテスト」をご参照ください。
-
コンテナネットワークを診断します。「コンテナネットワークの診断」をご参照ください。
エラーが断続的に発生する場合:
パケットをキャプチャして証拠を収集します。「パケットキャプチャ」をご参照ください。
解決しない場合は、チケットを送信してください。
診断方法
アプリケーション Pod と CoreDNS 間のネットワーク接続性のテスト
次のいずれかの方法を使用して、アプリケーション Pod のネットワーク名前空間に入ります。
-
方法 1 (推奨):
kubectl exec -it <pod-name> -- bashを実行して Pod に入ります。 -
方法 2:ノードにログインし、
ps aux | grep <application-process-name>でプロセス ID を見つけてから、nsenter -t <pid> -n bashでネットワーク名前空間に入ります。 -
方法 3 (頻繁に再起動する Pod の場合):
-
ノードにログインします。
-
docker ps -a | grep <application-container-name>を実行してサンドボックスコンテナ ID (名前がk8s_POD_で始まる) を見つけます。 -
docker inspect <sandboxed-container-ID> | grep netnsを実行して/var/run/docker/netns/xxxx内のネットワーク名前空間パスを見つけます。 -
nsenter -n<netns-path> bash</netns-path>を実行して名前空間に入ります。> 注意:-nと<netns-path>の間にスペースを追加しないでください。
-
Pod のネットワーク名前空間から、接続性をテストします。
# kube-dns サービスへの接続性をテスト
dig <domain> @<kube-dns-svc-ip>
# CoreDNS Pod へのインターネット制御メッセージプロトコル (ICMP) 接続性をテスト
ping <coredns-pod-ip>
# CoreDNS Pod への DNS クエリを直接テスト
dig <domain> @<coredns-pod-ip>
<kube-dns-svc-ip> を kube-system 名前空間の kube-dns サービス IP に、<coredns-pod-ip> を CoreDNS Pod の IP に置き換えます。
| 症状 | 考えられる原因 | 次のステップ |
|---|---|---|
| kube-dns サービスに到達できない | ノードの過負荷、kube-proxy の停止、またはセキュリティグループによるユーザーデータグラムプロトコル (UDP) ポート 53 のブロック | セキュリティグループルールが UDP ポート 53 を許可していることを確認します。許可している場合は、チケットを送信してください。 |
| CoreDNS Pod に到達できない (ICMP) | コンテナネットワークエラーまたはセキュリティグループによる ICMP のブロック | コンテナネットワークを診断します。 |
| CoreDNS Pod に到達できない (DNS) | ノードの過負荷またはセキュリティグループによる UDP ポート 53 のブロック | セキュリティグループルールが UDP ポート 53 を許可していることを確認します。許可している場合は、チケットを送信してください。 |
CoreDNS のネットワーク接続性のテスト
-
CoreDNS Pod が実行されているノードにログインします。
-
ps aux | grep corednsを実行して CoreDNS プロセス ID を取得します。 -
nsenter -t <pid> -n bashを実行して CoreDNS ネットワーク名前空間に入ります。 -
接続性をテストします。
# Kubernetes API サーバーへの接続性をテスト telnet <apiserver_clusterip> 6443 # apiserver_clusterip は、default 名前空間の kubernetes サービスの ClusterIP です。 # 上流 DNS サーバーへの接続性をテスト dig <domain> @100.100.2.136 dig <domain> @100.100.2.138
| 症状 | 考えられる原因 | 次のステップ |
|---|---|---|
| Kubernetes API サーバーに到達できない | API サーバーエラー、ノードの過負荷、または kube-proxy の停止 | チケットを送信チケットを送信チケットを送信チケットを送信チケットを送信チケットを送信チケットを送信チケットを送信チケットを送信チケットを送信してください。 |
| 上流 DNS サーバーに到達できない | ノードの過負荷、CoreDNS の設定ミス、または Express Connect のルーティングエラー | チケットを起票チケットを起票チケットを起票チケットを起票チケットを起票チケットを起票チケットを起票チケットを起票チケットを起票チケットを起票。 |
コンテナネットワークの診断
-
[クラスター] ページで、対象クラスターの名前をクリックするか、[操作] 列の [詳細] をクリックします。
-
左側のナビゲーションウィンドウで、[オペレーション] > [クラスター診断] を選択します。
-
コンテナインテリジェンスサービスページで、[クラスターチェック] > [診断] を選択します。
-
[診断] ページで、[ネットワーク診断] タブをクリックします。
-
[送信元アドレス] をアプリケーション Pod の IP に、[宛先アドレス] を kube-dns サービスの IP に、宛先ポートを
53に設定します。[パケットトレースを有効にする] と [上記内容を理解し、同意します] を選択し、[診断の作成] をクリックします。 -
診断リストで、対象レコードの [診断詳細] をクリックします。
結果には、特定されたエラー原因とともに、[診断結果]、[パケットパス]、[すべての可能なパス] が表示されます。詳細については、「クラスター診断機能を使用してクラスターの問題をトラブルシューティングする」をご参照ください。
パケットキャプチャ
エラーが断続的で再現が困難な場合は、パケットキャプチャを使用します。
-
アプリケーション Pod と CoreDNS Pod が実行されているノードにログインします。
-
各 ECS インスタンスで DNS トラフィックをキャプチャします。
tcpdump -i any port 53 -C 20 -W 200 -w /tmp/client_dns.pcapこれにより、ポート 53 のすべてのトラフィックがキャプチャされ、それぞれ 20 MB の最大 200 ファイルにローテーションされます。
-
エラーを再現し、障害発生時間帯のパケットを分析します。正確なタイムスタンプについては、アプリケーションログを確認してください。
パケットキャプチャによるサービスへの影響はごくわずかです。CPU 使用率とディスク I/O がわずかに増加するだけです。
既知の問題
詳細な調査を行う前に、これらの環境固有の問題を確認してください。
| 問題 | 影響を受ける環境 | 簡単な特定方法 |
|---|---|---|
| A レコードと AAAA レコードの同時クエリ | すべて (特に Alpine ベースのイメージと PHP アプリ) | 断続的な障害。パケットキャプチャでは、同じポートで A/AAAA クエリが同時に発生していることが示されます |
| IPVS UDP 送信元ポートの競合 | IP Virtual Server (IPVS) モードの kube-proxy。カーネルが 4.19.91-25.1.al7.x86_64 |
ノードのスケーリングまたは CoreDNS のスケーリング中に、障害が約 5 分間続きます |
| conntrack テーブルが満杯 | 高トラフィックのノード | dmesg -H に conntrack full と表示される。ピーク時に障害が発生する |
| NodeLocal DNSCache を使用した Alibaba Cloud DNS PrivateZone | NodeLocal DNSCache と DNS PrivateZone の両方を使用するクラスター | PrivateZone または vpc-proxy ドメイン名の解決に失敗するか、間違ったアドレスに解決される |
| autopath プラグインのバグ | 高頻度でコンテナを作成するクラスター | 外部名が断続的に失敗するか、間違った IP に解決される。内部名は通常正常に解決されるが、高頻度でコンテナを作成するクラスターでは、内部サービス名も間違った IP に解決されることがある |
| DNS PrivateZone と vpc-proxy の名前 | 内部ドメイン名と外部ドメイン名の両方が失敗するクラスター | Alibaba Cloud DNS PrivateZone に追加されたドメイン名と vpc-proxy を含むドメイン名でのみ解決エラーが発生する |
よくある質問
外部ドメイン名が解決できない
CoreDNS クエリログでレスポンスコードを確認します。ログプラグインがまだ有効でない場合は有効にし (「DNS 名前解決の設定」をご参照ください)、失敗したドメインを検索します。NXDOMAIN は、上流にドメインが存在しないことを意味します。これは多くの場合、検索サフィックスが追加されて無効な FQDN (完全修飾ドメイン名) が作成されたことが原因です。SERVFAIL または REFUSED は、上流サーバーに問題があることを意味します。CoreDNS の設定と 100.100.2.136 および 100.100.2.138 への接続性を確認してください。
ヘッドレスサービスのドメイン名が解決できない
1.7.0 より前の CoreDNS では、API サーバーのネットワークジッターにより CoreDNS が終了し、ヘッドレスサービスのレコード更新が停止する可能性があります。1.7.0 以降に更新してください。詳細については、「[コンポーネントの更新] CoreDNS の更新」をご参照ください。
StatefulSet Pod のドメイン名が解決できない
StatefulSet Pod テンプレートでは、serviceName をヘッドレスサービスの名前に設定する必要があります。これがないと、サービスレベルの名前 (例:headless-svc.ns.svc.cluster.local) は機能しますが、Pod ごとの DNS 名 (例:pod.headless-svc.ns.svc.cluster.local) は解決できません。StatefulSet の spec で serviceName を設定してください。
セキュリティグループルールまたはネットワーク ACL によって DNS クエリがブロックされる
セキュリティグループルールまたはネットワークアクセスコントロールリスト (ACL) が UDP ポート 53 をブロックしているため、影響を受けるノードで DNS 障害が発生しています。インバウンドおよびアウトバウンドの UDP ポート 53 トラフィックを許可してください。
コンテナネットワークの接続エラーによる DNS 障害
コンテナネットワークのエラーが UDP ポート 53 をブロックしています。ネットワーク診断機能を使用して、破損したパスと根本原因を特定してください。
CoreDNS Pod の過負荷
クエリ量が CoreDNS レプリカの容量を超えると、レイテンシーが上昇し、障害が発生します。CPU とメモリの使用量が上限に近づいていないか確認してください (kubectl -n kube-system top pod -l k8s-app=kube-dns を実行)。
2 つの修正方法があります。
-
NodeLocal DNSCache をデプロイしてクエリをローカルで吸収し、CoreDNS の負荷を軽減します。「NodeLocal DNSCache の設定」をご参照ください。
-
CoreDNS レプリカをスケールアウトして、Pod あたりのピーク CPU 使用率がノードの利用可能な CPU を大幅に下回るようにします。
DNS クエリが CoreDNS Pod 間で均等に分散されない
Pod のスケジューリングの不均衡や kube-dns の sessionAffinity 設定が、クエリの不均等な分散を引き起こす可能性があります。症状:CoreDNS Pod 間で CPU 使用率に顕著な差が見られます。
2 つの修正方法があります。
-
CoreDNS Pod をスケールアウトし、異なるノードに分散させます。
-
kube-dns サービスから
sessionAffinity設定を削除します。「kube-dns サービスの設定」をご参照ください。
CoreDNS Pod が正常に実行されない
YAML または ConfigMap の設定ミスにより、CoreDNS が起動しなかったり、クラッシュしたりすることがあります。症状:Pod が実行中でない、再起動回数が増加する、またはログエラーが発生する。
CoreDNS ログで、これらの一般的なエラーを確認してください。
| エラー | 原因 | 修正 |
|---|---|---|
/etc/coredns/Corefile:4 - Error during parsing: Unknown directive 'ready' |
CoreDNS ConfigMap に、現在のバージョンでサポートされていないプラグインが含まれています。 | kube-system 名前空間の ConfigMap から、サポートされていないプラグイン (例:ready) を削除します。エラー内の他のプラグインについても繰り返します。 |
Failed to watch *v1.Pod: ... connect: connection refused |
ログが生成されたときに API サーバーへの接続が中断されました。 | DNS 障害が発生しなかった場合、これが根本原因ではありません。そうでない場合は、CoreDNS の接続性をテストしてください。「CoreDNS のネットワーク接続性のテスト」をご参照ください。 |
[ERROR] plugin/errors: 2 www.aliyun.com. A: read udp ...->100.100.2.136:53: i/o timeout |
CoreDNS が上流 DNS サーバーに到達できませんでした。 | CoreDNS Pod から 100.100.2.136 および 100.100.2.138 への接続性をテストします。 |
クライアントの過負荷による DNS 名前解決の失敗
ECS インスタンスが完全にロードされると、UDP パケットが CoreDNS に到達する前にドロップされることがあります。モニタリングデータで、ネットワークインターフェイスコントローラー (NIC) の異常な再送レートと高い CPU 使用率を探してください。
2 つの選択肢があります。
conntrack テーブルが満杯になる
conntrack テーブルが満杯になると、新しい UDP および TCP 接続がドロップします。これは通常、ピーク時の DNS 障害を引き起こし、オフピーク時に回復します。確認するには、影響を受けるノードで dmesg -H を実行し、障害発生時間帯に conntrack full が表示されるかを探します。
conntrack テーブルの最大エントリ数を増やします。「Linux カーネルの conntrack テーブルで追跡される接続の最大数を増やすにはどうすればよいですか?」をご参照ください。
autopath プラグインが正常に動作しない
既知の autopath プラグインの欠陥により、外部ドメインの解決が時折失敗したり、間違った IP に解決されたりすることがあります。内部ドメインは正しく解決されます。この問題は、コンテナの作成頻度が高いクラスターで悪化します。
autopath プラグインを無効にします。
-
kubectl -n kube-system edit configmap corednsを使用して CoreDNS ConfigMap を編集します。 -
autopath @kubernetesの行を削除し、保存して終了します。 -
CoreDNS ログで
reloadを確認して、設定がロードされたことを確認します。
A レコードと AAAA レコードの同時クエリによる DNS 名前解決の失敗
一部の Linux ディストリビューションでは、同じポートで A クエリと AAAA クエリを同時に送信するため、conntrack の競合が発生し、UDP パケットがドロップされます。
症状:断続的な名前解決の失敗。パケットキャプチャでは、同じ送信元ポートからの A クエリと AAAA クエリが同時に表示されます。
修正方法は、ベースイメージによって異なります。
-
CentOS または Ubuntu:DNS リゾルバーの設定に
options timeout:2 attempts:3 rotate single-request-reopenを追加します。 -
Alpine Linux:Alpine ベースのイメージを別の OS ベースのイメージに置き換えます。「Alpine の注意点」をご参照ください。
-
PHP と cURL:
CURL_IPRESOLVE_V4を追加して、IPv4 のみの解決を強制します。「cURL 関数」をご参照ください。 -
すべての環境:競合状態を緩和する NodeLocal DNSCache をデプロイします。「NodeLocal DNSCache の設定」をご参照ください。
IPVS エラーによる DNS 名前解決の失敗
CentOS または Alibaba Cloud Linux 2 (カーネルが 4.19.91-25.1.al7.x86_64 より前) の IPVS モードでは、UDP バックエンド Pod を削除すると、送信元ポートの競合が発生し、パケットがドロップします。DNS 障害は、ノードまたは CoreDNS のスケーリングイベント中に約 5 分間続きます。
2 つの修正方法があります。
-
NodeLocal DNSCache をデプロイして、DNS クエリの IPVS パスをバイパスします。「NodeLocal DNSCache の設定」をご参照ください。
-
IPVS モードで UDP セッションのタイムアウトを短縮します。「IPVS モードで UDP のタイムアウト期間を変更する」をご参照ください。
NodeLocal DNSCache が機能しない
次のいずれかの条件が適用される場合、DNS クエリは NodeLocal DNSCache をバイパスします。
-
dnsConfigがアプリケーション Pod に挿入されなかったため、それらはまだ kube-dns サービスの IP を指しています。 -
Pod は Alpine Linux ベースのイメージを使用しており、CoreDNS を直接含むすべてのネームサーバーに同時にクエリを送信します。
最初のケースでは、自動 dnsConfig 挿入を有効にします。「NodeLocal DNSCache の設定」をご参照ください。Alpine イメージの場合は、別の OS 上に構築されたイメージを使用してください。「Alpine の注意点」をご参照ください。
Alibaba Cloud DNS PrivateZone の名前が解決できない
Alibaba Cloud DNS PrivateZone は TCP ではなく UDP を必要とします。NodeLocal DNSCache を使用すると、PrivateZone ドメイン、vpc-proxy API エンドポイント、またはその他のドメイン名が解決に失敗したり、間違った IP に解決されたりする可能性があります。
CoreDNS 設定に prefer_udp を追加して、上流クエリに UDP を強制します。「CoreDNS の設定」をご参照ください。