Amazon EKS で DNS の障害をトラブルシューティングするにはどうすればよいですか?
Amazon Elastic Kubernetes Service (Amazon EKS) クラスターで CoreDNS を使用しているアプリケーションまたはポッドが、内部または外部の DNS 名前解決に失敗しています。
簡単な説明
Amazon EKS クラスター内で実行するポッドは、CoreDNS クラスター IP アドレスをネームサーバーとして使用し、内部および外部 DNS レコードをクエリします。CoreDNS ポッド、サービス設定、または接続に問題がある場合、アプリケーションは DNS 解決に失敗することがあります。
CoreDNS ポッドは、kube-dns と呼ばれるサービスオブジェクトによって抽象化されます。CoreDNS ポッドの問題をトラブルシューティングするには、サービスエンドポイントオプションや iptables ルールなど、kube-dns サービスのすべてのコンポーネントが機能していることを確認します。
解決策
次の解決方法は、CoreDNS ClusterIP 10.100.0.10 に適用されます。
次の手順を実行します。
-
CoreDNS サービスのクラスタ IP を取得します。
kubectl get service kube-dns -n kube-system
-
DNS エンドポイントが公開され、CoreDNS ポッドを指していることを確認します。
kubectl -n kube-system get endpoints kube-dns
出力例:
NAME ENDPOINTS AGE kube-dns 192.168.2.218:53,192.168.3.117:53,192.168.2.218:53 + 1 more... 90d
注: エンドポイントリストが空の場合は、CoreDNS ポッドのポッドステータスを確認します。
-
CoreDNS と通信するときに、ポッドがセキュリティグループまたはネットワークアクセスコントロールリスト (ネットワーク ACL) によってブロックされていないことを確認します。
詳細については、「ポッドが Amazon EKS の他のポッドに接続できないのはなぜですか?」を参照してください。
kube-proxy ポッドが機能していることを確認する
ログでコントロールプレーンに対するタイムアウトエラーをチェックして、kube-proxy ポッドがクラスターの API サーバーにアクセスできることを確認します。また、403 不正エラーがないことを確認します。
kube-proxy ログを取得します。
kubectl logs -n kube-system --selector 'k8s-app=kube-proxy'
注: kube-proxy は、コントロールプレーンからエンドポイントを取得し、すべてのノードで iptables ルールを作成します。
問題発生時の CoreDNS ポッドの CPU 使用率を確認する
Amazon EKS CoreDNS アドオンは CoreDNS ポッドのメモリに 170 Mi の制限のみを追加します。CoreDNS ポッドは CPU 制限を定義していないため、コンテナは実行中のノードで使用可能なすべての CPU リソースを使用できます。ノードの CPU 使用率が 100% に達すると、Amazon EKS アプリケーションログに DNS タイムアウトエラーが発生する可能性があります。これは、CoreDNS ポッドにすべての DNS クエリを処理するのに十分な CPU リソースがないためです。
アプリケーションポッドに接続して DNS の問題をトラブルシューティングする
次の手順を実行します。
-
アプリケーションポッド内でコマンドを実行するには、次のコマンドを実行して、実行中のポッド内のシェルにアクセスします。
$ kubectl exec -it your-pod-name -- sh
アプリケーションポッドに利用可能なシェルバイナリがない場合、次の例のようなエラーが表示されます。
「OCI runtime exec failed: exec failed: container_linux.go:348: starting container process caused "exec: \"sh\": executable file not found in $PATH": unknown command terminated with exit code 126
デバッグするには、マニフェストファイルで使用されているイメージを更新して、Docker Web サイトからの busybox イメージなどの別のイメージに更新します。
-
kube-dns サービスのクラスター IP アドレスがポッドの /etc/resolv.conf ファイルにあることを確認するには、ポッド内のシェルで以下のコマンドを実行します。
cat /etc/resolv.conf
次の例 resolv.conf ファイルは、DNS リクエストのために 10.100.0.10 をポイントするように設定されたポッドを示しています。IPアドレスは、kube-dns サービスの ClusterIP と一致する必要があります。
nameserver 10.100.0.10 search default.svc.cluster.local svc.cluster.local cluster.local ec2.internal options ndots:5
注: ポッドの DNS 設定は、ポッド仕様の dnsPolicy フィールドで管理できます。このフィールドにデータが入力されていない場合、デフォルトで ClusterFirst DNS ポリシーが使用されます。ClusterFirst DNS ポリシーの詳細については、Kubernetes の Web サイトの「Pod's DNS policy」を参照してください。
-
ポッドがデフォルトの ClusterIP を使用して内部ドメインを解決できることを確認するには、ポッド内のシェルで次のコマンドを実行します。
nslookup kubernetes.default 10.100.0.10
出力例:
Server: 10.100.0.10 Address: 10.100.0.10#53 Name: kubernetes.default.svc.cluster.local Address: 10.100.0.1
-
ポッドがデフォルトの ClusterIP を使用して外部ドメインを解決できることを確認するには、ポッド内のシェルで次のコマンドを実行します。
nslookup amazon.com 10.100.0.10
出力例:
Server: 10.100.0.10 Address: 10.100.0.10#53 Non-authoritative answer: Name: amazon.com Address: 176.32.98.166 Name: amazon.com Address: 205.251.242.103 Name: amazon.com Address: 176.32.103.205
-
ポッドが CoreDNS ポッドの IP アドレスを使用して直接解決できることを確認します。ポッド内のシェルで次のコマンドを実行します。
nslookup kubernetes COREDNS_POD_IP nslookup amazon.com COREDNS_POD_IP
注: COREDNS_POD_IPを、kubectl から取得したエンドポイント IP の 1 つに置き換えます。
デバッグのために CoreDNS ポッドからより詳細なログを取得する
次の手順を実行します。
-
CoreDNS ポッドのデバッグログを有効にし、ログプラグインを CoreDNS ConfigMap に追加します。
kubectl -n kube-system edit configmap coredns
注: 詳細については、CoreDNS の Web サイトの「log plugin」を参照してください。
-
出力に表示されるエディター画面で、ログ文字列を追加します。
kind: ConfigMap apiVersion: v1 data: Corefile: | .:53 { log # Enabling CoreDNS Logging errors health kubernetes cluster.local in-addr.arpa ip6.arpa { pods insecure upstream fallthrough in-addr.arpa ip6.arpa } ... ...
注: 設定 CoreDNS のリロードには数分かかります。変更をすぐに適用するには、ポッドを 1 つずつ再起動します。
-
CoreDNS ログが失敗するか、アプリケーションポッドからヒットを取得しているかどうかを確認します。
kubectl logs --follow -n kube-system --selector 'k8s-app=kube-dns'
ndots 値を更新する
ndots 値は、最初の絶対クエリが行われる前にクエリを解決するためにドメイン名に表示される必要があるドットの数です。
たとえば、完全修飾されていないドメイン名の ndots オプションをデフォルト値 5に設定できます。その後、内部ドメイン cluster.local に分類されないすべての外部ドメインが、クエリを実行する前に検索ドメインに追加されます。
次の例では、アプリケーションポッドの /etc/resolv.conf ファイル設定を使用しています。
nameserver 10.100.0.10 search default.svc.cluster.local svc.cluster.local cluster.local ec2.internal options ndots:5
CoreDNSは、クエリ対象のドメインで 5 つのドットを探します。ポッドが amazon.comの DNS 解決呼び出しを行う場合、ログは次のようになります。
[INFO] 192.168.3.71:33238 - 36534 "A IN amazon.com.default.svc.cluster.local. udp 54 false 512" NXDOMAIN qr,aa,rd 147 0.000473434s [INFO] 192.168.3.71:57098 - 43241 "A IN amazon.com.svc.cluster.local. udp 46 false 512" NXDOMAIN qr,aa,rd 139 0.000066171s [INFO] 192.168.3.71:51937 - 15588 "A IN amazon.com.cluster.local. udp 42 false 512" NXDOMAIN qr,aa,rd 135 0.000137489s [INFO] 192.168.3.71:52618 - 14916 "A IN amazon.com.ec2.internal. udp 41 false 512" NXDOMAIN qr,rd,ra 41 0.001248388s [INFO] 192.168.3.71:51298 - 65181 "A IN amazon.com. udp 28 false 512" NOERROR qr,rd,ra 106 0.001711104s
注: NXDOMAIN はドメインレコードが見つからなかったことを意味し、NOERROR はドメインレコードが見つかったことを意味します。
すべての検索ドメインの先頭に amazon.com を追加してから、最後にある絶対ドメインで最終呼び出しを行います。最終的なドメイン名には、最後にドット(.) が付加され、完全修飾ドメイン名になります。つまり、すべての外部ドメイン名クエリに対して、4〜5 回の追加の呼び出しがある場合があり、CoreDNS ポッドが処理しきれない可能性があります。
この問題を解決するには、ndots を 1 に変更して、1 つのドットのみを検索します。または、クエリするまたは使用するドメインの末尾にドット (.) を付けます。
nslookup example.com.
VPC リゾルバー (AmazonProvidedDNS) の制限に注意する
Amazon Virtual Private Cloud (Amazon VPC) リゾルバーは、ネットワークインターフェイスごとに 1024 パケット/秒の最大ハード制限のみを受容できます。複数の CoreDNS ポッドが同じノード上にある場合、この制限に達する可能性は、外部ドメインクエリの方が高くなります。
PodAntiAffinity ルールを使用して、別個のインスタンスで CoreDNS ポッドをスケジュールするには、次のオプションを CoreDNS デプロイに追加します。
podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - podAffinityTerm: labelSelector: matchExpressions: - key: k8s-app operator: In values: - kube-dns topologyKey: kubernetes.io/hostname weight: 100
注: PodAntiAffinity の詳細については、Kubernetes の Web サイトの「Inter-pod affinity and anti-affinity」を参照してください。
tcpdump を使用して Amazon EKS ワーカーノードから CoreDNS パケットをキャプチャする
DNS 解決の問題を診断するには、tcpdump ツールを使用してパケットキャプチャを実行します。
-
CoreDNS ポッドが実行されているワーカーノードを探します。
kubectl get pod -n kube-system -l k8s-app=kube-dns -o wide
-
SSH を使用して CoreDNS ポッドが実行されているワーカーノードに接続し、tcpdump ツールをインストールします。
sudo yum install tcpdump –y
-
ワーカーノードで CoreDNS ポッドプロセス ID を探します。
ps ax | grep coredns
-
ワーカーノードから、CoreDNS ポッドネットワークでパケットキャプチャを実行し、UDP ポート 53 のネットワークトラフィックをモニタリングします。
sudo nsenter -n -t PID tcpdump udp port 53
-
別のターミナルから、CoreDNS サービスとポッド IP アドレスを取得します。
kubectl describe svc kube-dns -n kube-system
注: **[IP]**フィールドにあるサービス IP アドレスと [エンドポイント] フィールドにあるポッドの IP アドレスを書き留めておきます。
-
ポッドを起動して DNS サービスをテストします。次の例では、Ubuntu コンテナイメージを使用しています。
kubectl run ubuntu --image=ubuntu sleep 1d kubectl exec -it ubuntu sh
-
nslookup ツールを使用して、amazon.com などのドメインに対して DNS クエリを実行します。
nslookup amazon.com
CoreDNS サービス IP アドレスに対して、同じクエリを明示的に実行します。
nslookup amazon.com COREDNS_SERVICE_IP
各 CoreDNS ポッド IP アドレスに対してクエリを実行します。
nslookup amazon.com COREDNS\_POD\_IP
注: 複数の CoreDNS ポッドを実行している場合は、トラフィックをキャプチャするポッドに少なくとも 1 つのクエリが送信されるように、複数のクエリを実行します。
-
パケットキャプチャの結果を確認します。
モニタリングしている CoreDNS ポッドに対する DNS クエリタイムアウトが発生し、パケットキャプチャにクエリが表示されない場合は、ネットワーク接続を確認します。ワーカーノード間のネットワーク到達可能性を必ず確認してください。
キャプチャしていないポッド IP アドレスに対して DNS クエリのタイムアウトが発生した場合は、関連するワーカーノードで別のパケットキャプチャを実行します。
パケットキャプチャの結果を保存するには、tcpdump コマンドに -w FILE_NAME フラグを追加します。次の例では、capture.pcap という名前のファイルに結果を書き込みます。
tcpdump -w capture.pcap udp port 53
関連情報
CoreDNS GA for Kubernetes cluster DNS
(Kubernetes の Web サイト)
関連するコンテンツ
- 質問済み 1年前lg...
- AWS公式更新しました 1年前