Amazon EKS で DNS の障害をトラブルシューティングするにはどうすればよいですか。

最終更新日: 2021 年 11 月 9 日

Amazon Elastic Kubernetes Service (Amazon EKS) クラスターで CoreDNS を使用しているアプリケーションまたはポッドが、内部または外部の DNS 名前解決に失敗しています。

簡単な説明

Amazon EKS クラスター内で実行するポッドは、CoreDNS サービスのクラスター IP をデフォルトのネームサーバーとして使用し、内部および外部 DNS レコードをクエリします。CoreDNS ポッド、サービス設定、または接続に問題がある場合、アプリケーションは DNS 解決に失敗することがあります。

CoreDNS ポッドは、kube-dns と呼ばれるサービスオブジェクトによって抽象化されます。CoreDNS ポッドの問題をトラブルシューティングするには、kube-dns サービスのすべてのコンポーネントが機能していることを確認します。これらのコンポーネントには、サービスエンドポイントオプションと iptables ルールが含まれますが、これらに限定されません。

解決方法

次の解決方法は、CoreDNS ClusterIP 10.100.0.10 に適用されます。

1.    CoreDNS サービスの ClusterIP を取得します。

kubectl get service kube-dns -n kube-system

2.    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 ポッドのポッドステータスを確認します

3.    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 ルールを作成します。

アプリケーションポッドに接続して、DNS の問題をトラブルシューティングする

1.    アプリケーションポッド内でコマンドを実行するには、次のコマンドを実行して、実行中のポッド内のシェルにアクセスします。

$ 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 ウェブサイトからの) busybox イメージなどの別のイメージを使用します。

2.    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 ポリシーが使用されます。

3.    ポッドがデフォルトの ClusterIP を使用して内部ドメインを解決できることを確認するには、ポッド内のシェルで次のコマンドを実行します。

nslookup kubernetes 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

4.    ポッドがデフォルトの 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

5.    CoreDNS ポッドの IP アドレスを使用してポッドが直接解決できることを確認するには、ポッド内のシェルで次のコマンドを実行します。

nslookup kubernetes COREDNS_POD_IP

nslookup amazon.com COREDNS_POD_IP

注: COREDNS_POD_IP を、以前に使用した kubectl から取得したエンドポイント IP の 1 つに置き換えます。

デバッグのために coreDNS ポッドからより詳細なログを取得する

1.    CoreDNS ポッドのデバッグログを有効にし、log plugin を CoreDNS ConfigMap に追加するには、次のコマンドを実行します。

kubectl -n kube-system edit configmap coredns

2.    出力に表示されるエディタ画面で、ログ文字列を追加します。以下に例を示します。

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 つずつ再起動して、変更をすぐに適用できます。

3.    CoreDNS ログが失敗しているか、アプリケーションポッドからヒットを取得しているかどうかを確認するには、次のコマンドを実行します。

kubectl logs --follow -n kube-system --selector 'k8s-app=kube-dns'

ndots 値を更新する

DNS は、名前解決に nameserver を使用します (通常は kube-dns サービスのクラスター IP)。DNS は search を使用して、クエリ名を補完して完全修飾ドメイン名にします。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 ポッドが処理しきれない可能性があります。

この問題を解決するには、ndots1 に変更します (単一のドットのみを検索します)。または、クエリまたは使用されるドメインの末尾にドット (.) を付けます。例:

nslookup example.com.

VPC リゾルバー (AmazonProvidedDNS) の制限に注意する

Amazon Virtual Private Cloud (Amazon VPC) リゾルバーは、ネットワークインターフェイスごとに 1024 パケット/秒の最大ハード制限のみを受容できます。複数の CoreDNS ポッドが同じノード上にある場合、この制限に達する可能性は、外部ドメインクエリの方が高くなります。

(Kubernetes ウェブサイトからの) PodAntiAffinity ルールを使用して、別個のインスタンスで CoreDNS ポッドをスケジュールするには、次のオプションを CoreDNS デプロイに追加します。

podAntiAffinity:
  preferredDuringSchedulingIgnoredDuringExecution:
  - podAffinityTerm:
      labelSelector:
        matchExpressions:
        - key: k8s-app
          operator: In
          values:
          - kube-dns
      topologyKey: kubernetes.io/hostname
    weight: 100

tcpdump を使用して Amazon EKS ワーカーノードから CoreDNS パケットをキャプチャする

tcpdump ツールを使用してパケットキャプチャを実行し、DNS 解決の問題を診断します。このツールは、DNS リクエストのネットワークトラフィックが CoreDNS Pod に到達しているかどうか、およびネットワーク接続の問題が根底にあるかどうかを検証するのに役立ちます。tcpdump を使用するには、次の手順を実行します。

1.    CoreDNS Pod が実行されているワーカーノードを探します。

kubectl get pod -n kube-system -l k8s-app=kube-dns -o wide

2.    SSH を使用して CoreDNS Pod が実行されているワーカーノードに接続し、tcpdump ツールをインストールします。

sudo yum install tcpdump –y

3.    ワーカーノードで CoreDNS Pod プロセス ID を探します。

ps ax | grep coredns

4.    ワーカーノードから CoreDNS Pod ネットワークでパケットキャプチャを実行し、UDP ポート 53 のネットワークトラフィックをモニタリングします。

sudo nsenter -n -t PID tcpdump udp port 53

5.    別のターミナルから CoreDNS サービスとポッド IP を取得します。

kubectl describe svc kube-dns -n kube-system

注:[IP] フィールドにある [サービス IP] と [エンドポイント] フィールドにあるポッド IP をメモします。

6.    DNS サービスをテストするポッドを起動します。次の例では、Ubuntu コンテナイメージを使用しています。

kubectl run ubuntu --image=ubuntu sleep 1d

kubectl exec -it ubuntu sh

7.    nslookup ツールを使用して、 amazon.com などのドメインに対して DNS クエリを実行します。

nslookup amazon.com

手順 5 の CoreDNS サービス IP に対して、同じクエリを明示的に実行します。

nslookup amazon.com COREDNS_SERVICE_IP

ステップ 5 の各 CoredNS ポッド IP に対してクエリを実行します。

nslookup amazon.com COREDNS_POD_IP

注:複数の CoreDNS Pod を実行している場合は、トラフィックをキャプチャするポッドに少なくとも 1 つのクエリが送信されるように、複数のクエリを実行します。

8.    パケットキャプチャの結果を確認します。

モニタリングしている CoreDNS ポッドに対する DNS クエリタイムアウトが発生し、パケットキャプチャにクエリが表示されない場合は、ネットワーク接続に問題がある可能性があります。ワーカーノード間のネットワーク到達可能性を必ず確認してください。

キャプチャ元ではないポッド IP に対して DNS クエリのタイムアウトが発生した場合は、手順 2 ~ 4 に従って、関連するワーカーノードで別のパケットキャプチャを実行します。

パケットキャプチャの結果を後で参照できるように保存するには、tcpdump コマンドに-w FILE_NAME フラグを追加します。次の例では、 capture.pcap という名前のファイルに結果を書き込みます。

tcpdump -w capture.pcap udp port 53

この記事はお役に立ちましたか。


請求に関するサポートまたは技術サポートが必要ですか?