DNS解決のデバッグ

このページでは、DNSの問題を診断するためのヒントを提供します。

始める前に

Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:


クラスターは、CoreDNSアドオンまたはその前身であるkube-dnsを使用するように設定されている必要があります。

作業するKubernetesサーバーは次のバージョン以降のものである必要があります: v1.6.

バージョンを確認するには次のコマンドを実行してください: kubectl version.

テスト環境として使用するシンプルなPodを作成する

apiVersion: v1
kind: Pod
metadata:
  name: dnsutils
  namespace: default
spec:
  containers:
  - name: dnsutils
    image: registry.k8s.io/e2e-test-images/agnhost:2.39
    imagePullPolicy: IfNotPresent
  restartPolicy: Always

このマニフェストを使用してPodを作成します:

kubectl apply -f https://k8s.io/examples/admin/dns/dnsutils.yaml
pod/dnsutils created

そして、ステータスを確認します:

kubectl get pods dnsutils
NAME       READY     STATUS    RESTARTS   AGE
dnsutils   1/1       Running   0          <some-time>

このPodが実行されたら、その環境でnslookupを実行できます。 以下のような結果が表示された場合、DNSは正常に動作しています。

kubectl exec -i -t dnsutils -- nslookup kubernetes.default
Server:    10.0.0.10
Address 1: 10.0.0.10

Name:      kubernetes.default
Address 1: 10.0.0.1

nslookupコマンドが失敗した場合は、以下を確認してください:

まずは、ローカルのDNS設定を確認する

resolv.confファイルの内容を確認します。 (詳細については、DNSサービスのカスタマイズおよび下記の既知の問題を参照してください)

kubectl exec -ti dnsutils -- cat /etc/resolv.conf

検索パスとネームサーバーが以下のように設定されていることを確認します。 (検索パスはクラウドプロバイダーによって異なる場合があることに注意してください):

search default.svc.cluster.local svc.cluster.local cluster.local google.internal c.gce_project_id.internal
nameserver 10.0.0.10
options ndots:5

以下のようなエラーは、CoreDNS(またはkube-dns)アドオンまたは関連するServiceに問題があることを示しています:

kubectl exec -i -t dnsutils -- nslookup kubernetes.default
Server:    10.0.0.10
Address 1: 10.0.0.10

nslookup: can't resolve 'kubernetes.default'

または、

kubectl exec -i -t dnsutils -- nslookup kubernetes.default
Server:    10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local

nslookup: can't resolve 'kubernetes.default'

DNSのPodが実行されているか確認する

kubectl get podsコマンドを使用して、DNSのPodが実行されていることを確認します。

kubectl get pods --namespace=kube-system -l k8s-app=kube-dns
NAME                       READY     STATUS    RESTARTS   AGE
...
coredns-7b96bf9f76-5hsxb   1/1       Running   0           1h
coredns-7b96bf9f76-mvmmt   1/1       Running   0           1h
...

CoreDNSのPodが実行されていない、またはPodが失敗/完了している場合、現在の環境ではDNSアドオンがデフォルトでデプロイされていない可能性があり、手動でデプロイする必要があります。

DNSのPodのエラーを確認する

kubectl logsコマンドを使用して、DNSコンテナのログを確認します。

CoreDNSの場合:

kubectl logs --namespace=kube-system -l k8s-app=kube-dns

以下は正常なCoreDNSログの例です:

.:53
2018/08/15 14:37:17 [INFO] CoreDNS-1.2.2
2018/08/15 14:37:17 [INFO] linux/amd64, go1.10.3, 2e322f6
CoreDNS-1.2.2
linux/amd64, go1.10.3, 2e322f6
2018/08/15 14:37:17 [INFO] plugin/reload: Running configuration MD5 = 24e6c59e83ce706f07bcc82c31b1ea1c

ログに疑わしいメッセージや予期しないメッセージがないか確認してください。

DNSサービスは起動しているか

kubectl get serviceコマンドを使用して、DNSサービスが起動していることを確認します。

kubectl get svc --namespace=kube-system
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)             AGE
...
kube-dns     ClusterIP   10.0.0.10      <none>        53/UDP,53/TCP        1h
...

Serviceを作成した場合、またはデフォルトで作成されるはずなのに表示されない場合、詳細については、Serviceのデバッグを参照してください。

DNSエンドポイントは公開されているか

kubectl get endpointsliceコマンドを使用して、DNSエンドポイントが公開されていることを確認できます。

kubectl get endpointslice -l k8s.io/service-name=kube-dns --namespace=kube-system
NAME             ADDRESSTYPE   PORTS   ENDPOINTS                  AGE
kube-dns-zxoja   IPv4          53      10.180.3.17,10.180.3.17    1h

エンドポイントが表示されない場合は、Serviceのデバッグドキュメントのエンドポイントセクションを参照してください。

DNSクエリは受信/処理されているか

CoreDNS設定(別名: Corefile)にlogプラグインを追加することで、クエリが受信されているかどうかを確認できます。 CoreDNSのCorefileは、corednsという名前のConfigMapに保持されています。 編集するには、次のコマンドを使用します:

kubectl -n kube-system edit configmap coredns

次に、以下の例に従ってCorefileセクションにlogを追加します:

apiVersion: v1
kind: ConfigMap
metadata:
  name: coredns
  namespace: kube-system
data:
  Corefile: |
    .:53 {
        log
        errors
        health
        kubernetes cluster.local in-addr.arpa ip6.arpa {
          pods insecure
          upstream
          fallthrough in-addr.arpa ip6.arpa
        }
        prometheus :9153
        forward . /etc/resolv.conf
        cache 30
        loop
        reload
        loadbalance
    }    

変更を保存した後、Kubernetesがこれらの変更をCoreDNSのPodに伝播するまでに最大1〜2分かかる場合があります。

次に、いくつかのクエリを実行し、このドキュメントの上記のセクションに従ってログを確認します。 CoreDNSのPodがクエリを受信している場合、ログにそれらが表示されるはずです。

以下はログ内のクエリの例です:

.:53
2018/08/15 14:37:15 [INFO] CoreDNS-1.2.0
2018/08/15 14:37:15 [INFO] linux/amd64, go1.10.3, 2e322f6
CoreDNS-1.2.0
linux/amd64, go1.10.3, 2e322f6
2018/09/07 15:29:04 [INFO] plugin/reload: Running configuration MD5 = 162475cdf272d8aa601e6fe67a6ad42f
2018/09/07 15:29:04 [INFO] Reloading complete
172.17.0.18:41675 - [07/Sep/2018:15:29:11 +0000] 59925 "A IN kubernetes.default.svc.cluster.local. udp 54 false 512" NOERROR qr,aa,rd,ra 106 0.000066649s

CoreDNSに十分な権限があるか

CoreDNSは、サービス名を適切に解決するために、ServiceおよびEndpointSlice関連のリソースをリストできる必要があります。

エラーメッセージの例:

2022-03-18T07:12:15.699431183Z [INFO] 10.96.144.227:52299 - 3686 "A IN serverproxy.contoso.net.cluster.local. udp 52 false 512" SERVFAIL qr,aa,rd 145 0.000091221s

まず、system:corednsの現在のClusterRoleを取得します:

kubectl describe clusterrole system:coredns -n kube-system

期待される出力:

PolicyRule:
  Resources                        Non-Resource URLs  Resource Names  Verbs
  ---------                        -----------------  --------------  -----
  endpoints                        []                 []              [list watch]
  namespaces                       []                 []              [list watch]
  pods                             []                 []              [list watch]
  services                         []                 []              [list watch]
  endpointslices.discovery.k8s.io  []                 []              [list watch]

権限が不足している場合は、ClusterRoleを編集して追加します:

kubectl edit clusterrole system:coredns -n kube-system

EndpointSlices権限の追加例:

...
- apiGroups:
  - discovery.k8s.io
  resources:
  - endpointslices
  verbs:
  - list
  - watch
...

正しい名前空間のServiceを指定しているか

名前空間を指定しないDNSクエリは、Podの名前空間に制限されます。

Podの名前空間とServiceの名前空間が異なる場合、DNSクエリにはServiceの名前空間を含める必要があります。

このクエリはPodの名前空間に制限されます:

kubectl exec -i -t dnsutils -- nslookup <service-name>

このクエリは名前空間を指定します:

kubectl exec -i -t dnsutils -- nslookup <service-name>.<namespace>

名前解決の詳細については、ServiceとPodに対するDNSを参照してください。

既知の問題

一部のLinuxディストリビューション(Ubuntuなど)は、デフォルトでローカルDNSリゾルバー(systemd-resolved)を使用します。 systemd-resolvedは/etc/resolv.confを移動してスタブファイルに置き換えるため、アップストリームサーバーで名前を解決する際に致命的な転送ループが発生する可能性があります。 これは、kubeletの--resolv-confフラグを使用して正しいresolv.confを指定することで手動で修正できます(systemd-resolvedの場合、これは/run/systemd/resolve/resolv.confです)。 kubeadmはsystemd-resolvedを自動的に検出し、それに応じてkubeletフラグを調整します。

Kubernetesのインストールでは、ノードのresolv.confファイルをクラスターDNSを使用するように設定しません。 このプロセスは本質的にディストリビューション固有であるためです。 これは最終的には実装される必要があるでしょう。

LinuxのlibC(別名: glibc)には、DNSのnameserverレコードに対してデフォルトで3つという制限があり、Kubernetesは1つのnameserverレコードを消費する必要があります。 つまり、ローカルインストールがすでに3つのnameserverを使用している場合、それらのエントリの一部が失われます。 この制限を回避するには、ノードでdnsmasqを実行することで、より多くのnameserverエントリを提供できます。 kubeletの--resolv-confフラグを使用することもできます。

ベースイメージとして、バージョン3.17以前のAlpineを使用している場合、Alpineの設計上の問題によりDNSが正しく動作しない可能性があります。 muslバージョン1.24まで、DNSスタブリゾルバーへのTCPフォールバックが含まれていなかったため、512バイトを超えるDNS呼び出しは失敗していました。 バージョン3.18以降のAlpineイメージにアップグレードしてください。

次の項目