ServiceとPodに対するDNS

ワークロードは、DNSを用いてクラスター内のServiceを探索できます。 本ページでは、その仕組みを解説します。

KubernetesはServiceとPodのDNSレコードを作成します。 IPアドレスの代わりに安定したDNS名を用いて、Serviceに接続できます。

Kubernetesは、DNSの設定に用いられるPodとServiceの情報を公開します。 kubeletがPodのDNSを設定することで、実行中のコンテナがIPアドレスではなくDNS名でServiceの名前解決を行えます。

クラスター内で定義されたServiceにはDNS名が割り当てられます。 デフォルトでは、クライアントであるPodのDNS検索リストには、そのPod自身の名前空間とクラスターのデフォルトドメインが含まれています。

サービスの名前空間

DNSクエリの結果は、クエリを発行したPodの名前空間によって異なる場合があります。 名前空間を指定しないDNSクエリは、Pod自身の名前空間に限定して解決されます。 他の名前空間にアクセスするには、DNSクエリ内で名前空間を指定する必要があります。

例えば、testという名前空間にPodが、prodという名前空間にdataというServiceがそれぞれ存在しているとします。

Podからdataというクエリを発行しても、DNS解決はPodの名前空間testに限定されるため、結果は返りません。

data.prodというクエリを発行すれば、Serviceの属する名前空間が指定されているため、Serviceを探索することができます。

DNSクエリはPodの/etc/resolv.confに基づいて展開される場合があります。 kubeletは、それぞれのPodにこのファイルを設定します。 例えば、dataというクエリは、data.test.svc.cluster.localに展開される場合があります。 クエリの展開にはsearchオプションの値が用いられます。 DNSクエリの詳細については、resolv.confのマニュアルをご覧ください。

nameserver 10.32.0.10
search <namespace>.svc.cluster.local svc.cluster.local cluster.local
options ndots:5

以上のように、test という名前空間に存在するPodは、data.proddata.prod.svc.cluster.localというクエリを正常に名前解決できます。

DNSレコード

DNSレコードが作成されるオブジェクトは、以下の2つです。

  1. Service
  2. Pod

以降のセクションでは、サポートされているDNSレコードの種類および構成について説明します。 その他の構成、名前、クエリは実装に依存し、予告なく変更される可能性があります。 最新の仕様については、Kubernetes DNS-Based Service Discoveryをご覧ください。

Service

A/AAAAレコード

「通常の」(ヘッドレスでない)Serviceは、my-svc.my-namespace.svc.cluster-domain.exampleという形式のDNS A(AAAA)レコードが、ServiceのIPファミリーに応じて割り当てられます。 割り当てられたAレコードは、ServiceのClusterIPへと名前解決されます。

ClusterIPのないヘッドレスServiceにもmy-svc.my-namespace.svc.cluster-domain.exampleの形式のDNS A(AAAA)レコードが割り当てられます。 通常のServiceとは異なり、Serviceによって選択されたすべてのPodのIPアドレスに解決されます。 クライアントは、得られたIPアドレスの集合を扱うか、標準のラウンドロビン方式で集合からIPアドレスを選択します。

SRVレコード

SRVレコードは、通常のServiceもしくはヘッドレスServiceの一部である名前付きポート向けに作成されます。

  • それぞれの名前付きポートに対して、SRVレコードは_port-name._port-protocol.my-svc.my-namespace.svc.cluster-domain.exampleという形式です。
  • 通常のServiceに対しては、このSRVレコードはmy-svc.my-namespace.svc.cluster-domain.exampleという形式のドメイン名とポート番号へ名前解決します。
  • ヘッドレスServiceに対しては、このSRVレコードは複数の結果を返します。 Serviceの背後にある各Podに対し1つずつレコードが返され、それぞれのレコードはPodのポート番号とhostname.my-svc.my-namespace.svc.cluster-domain.exampleという形式のドメイン名を含んでいます。

Pod

A/AAAAレコード

DNSの仕様が実装される前のバージョンのKube-DNSでは、以下のような名前解決が行われていました。

<pod-IPv4-address>.<namespace>.pod.<cluster-domain>

例えば、IPアドレスが172.17.0.3のPodがdefaultという名前空間に存在しており、クラスターのドメイン名がcluster.localの場合、PodのDNS名は以下のとおりです。

172-17-0-3.default.pod.cluster.local

CoreDNSなどの一部のクラスター実装では、以下のようなAレコードも提供されます。

<pod-ipv4-address>.<service-name>.<my-namespace>.svc.<cluster-domain.example>

例えば、IPアドレスが172.17.0.3のPodがcafeという名前空間に存在しており、PodがbaristaというServiceのエンドポイントで、クラスターのドメイン名がcluster.localの場合、Podは次のようなServiceスコープのAレコードを持ちます。

172-17-0-3.barista.cafe.svc.cluster.local

Podのhostnameとsubdomainフィールド

現在、Podが作成されたとき、Pod内部から観測されるホスト名は、Podのmetadata.nameフィールドの値です。

Podのspecでは、オプションのhostnameフィールドで別のホスト名を指定できます。 hostnameを指定すると、Podの内部から観測されるホスト名として、Podの名前よりも優先されます。 例えば、spec.hostnameフィールドが"my-host"に設定されたPodのホスト名は"my-host"です。

Podのspecはまた、オプションのsubdomainフィールドで、Podの名前空間のサブグループを指定することができます。 例えば、"my-namespace"という名前空間において、spec.hostname"foo"spec.subdomain"bar"にそれぞれ設定されているPodがあるとします。 このとき、Podのホスト名は"foo"で、Pod内部から観測される完全修飾ドメイン名(FQDN)は"foo.bar.my-namespace.svc.cluster.local"です。

Podと同じ名前空間内に、Podのサブドメインと同じ名前のヘッドレスServiceが存在する場合、クラスターのDNSサーバーは、そのPodのFQDNに対するA(AAAA)レコードを返します。

例えば、以下の設定について考えてみましょう:

apiVersion: v1
kind: Service
metadata:
  name: busybox-subdomain
spec:
  selector:
    name: busybox
  clusterIP: None
  ports:
  - name: foo # 単一ポートのServiceには、nameは必須ではありません
    port: 1234
---
apiVersion: v1
kind: Pod
metadata:
  name: busybox1
  labels:
    name: busybox
spec:
  hostname: busybox-1
  subdomain: busybox-subdomain
  containers:
  - image: busybox:1.28
    command:
      - sleep
      - "3600"
    name: busybox
---
apiVersion: v1
kind: Pod
metadata:
  name: busybox2
  labels:
    name: busybox
spec:
  hostname: busybox-2
  subdomain: busybox-subdomain
  containers:
  - image: busybox:1.28
    command:
      - sleep
      - "3600"
    name: busybox

上記の設定のように、"busybox-subdomain"というServiceと、spec.subdomain"busybox-subdomain"を指定したPodが存在するとします。 このとき、1つ目のPodは、自身のFQDNを"busybox-1.busybox-subdomain.my-namespace.svc.cluster-domain.example"と認識します。 DNSはその名前に対して、PodのIPを指し示すA(AAAA)レコードを返します。 "busybox1"と"busybox2"の両方のPodはそれぞれ自身のA(AAAA)レコードを持ちます。

EndpointSliceでは、IPアドレスとともに、任意のエンドポイントアドレスに対するDNSホスト名を指定できます。

PodのsetHostnameAsFQDNフィールド

FEATURE STATE: Kubernetes v1.22 [stable]

PodがFQDNを持つように構成されている場合、そのホスト名は短縮されたホスト名です。 例えば、FQDNがbusybox-1.busybox-subdomain.my-namespace.svc.cluster-domain.exampleのPodがあるとします。 この場合、デフォルトではそのPod内でhostnameコマンドを実行するとbusybox-1が返され、hostname --fqdnコマンドを実行するとFQDNが返されます。

PodのspecでsetHostnameAsFQDN: trueを設定した場合、kubeletはPodのFQDNを、そのPodの名前空間におけるホスト名として書き込みます。 この場合、hostnamehostname --fqdnの両方がPodのFQDNを返します。

PodのDNSポリシー

DNSポリシーはPodごとに設定できます。 現在のKubernetesでは次のようなPod固有のDNSポリシーをサポートしています。 これらのポリシーはPodのspecのdnsPolicyフィールドで指定されます。

  • "Default": Podが実行されているノードから名前解決の設定を継承します。 詳細に関しては、関連する議論を参照してください。

  • "ClusterFirst": "www.kubernetes.io"のようなクラスターのドメインのサフィックスに一致しないDNSクエリは、DNSサーバーによって上流のネームサーバーに転送されます。 クラスター管理者が追加のスタブドメインと上流のDNSサーバーを設定している場合があります。 このような場合におけるDNSクエリ処理の詳細に関しては、関連する議論を参照してください。

  • "ClusterFirstWithHostNet": hostNetworkによって稼働しているPodに対しては、明示的にDNSポリシーを"ClusterFirstWithHostNet"に設定してください。 そうしない場合、hostNetworkによって稼働し、かつ"ClusterFirst"が設定されているPodは、"Default"ポリシーの挙動にフォールバックします。

  • "None": Kubernetes環境からDNS設定を無視することができます。 全てのDNS設定は、PodのspecのdnsConfigフィールドで指定する必要があります。 詳細は、以下のPodのDNS設定をご覧ください。

下記の例では、hostNetworkフィールドがtrueのためdnsPolicyに"ClusterFirstWithHostNet"を指定したPodを示しています。

apiVersion: v1
kind: Pod
metadata:
  name: busybox
  namespace: default
spec:
  containers:
  - image: busybox:1.28
    command:
      - sleep
      - "3600"
    imagePullPolicy: IfNotPresent
    name: busybox
  restartPolicy: Always
  hostNetwork: true
  dnsPolicy: ClusterFirstWithHostNet

PodのDNS設定

FEATURE STATE: Kubernetes v1.14 [stable]

PodのDNS設定では、Podに対するDNS設定をより細かく制御できます。

dnsConfigフィールドは任意で指定でき、どのdnsPolicyの設定でも併用できます。 ただし、PodのdnsPolicyが"None"の場合、dnsConfigフィールドの設定は必須です。

以下は、dnsConfigフィールドで指定可能なプロパティです。

  • nameservers: PodのDNSサーバーとして使用されるIPアドレスのリストです。 最大で3つのIPアドレスを指定できます。 PodのdnsPolicyが"None"の場合、少なくとも1つのIPアドレスを指定する必要があります。 それ以外の場合は、このプロパティは任意です。 ここで指定したサーバーは、指定されたDNSポリシーから生成されるベースのネームサーバーと結合され、重複するアドレスは削除されます。
  • searches: Pod内のホスト名の名前解決のためのDNS検索ドメインのリストです。 このプロパティは任意です。 このプロパティを指定した場合、このリストは、選択されたDNSポリシーから生成されるベースの検索ドメイン名にマージされます。 重複するドメイン名は削除されます。 最大で32個の検索ドメインを指定できます。
  • options: nameプロパティ(必須)とvalueプロパティ(任意)を持つオブジェクトのリストです。 このプロパティの内容は、指定されたDNSポリシーから生成されるオプションにマージされます。 重複するエントリは削除されます。

以下は、カスタムDNS設定を持つPodの例です。

apiVersion: v1
kind: Pod
metadata:
  namespace: default
  name: dns-example
spec:
  containers:
    - name: test
      image: nginx
  dnsPolicy: "None"
  dnsConfig:
    nameservers:
      - 192.0.2.1 # このIPアドレスは例です
    searches:
      - ns1.svc.cluster-domain.example
      - my.dns.search.suffix
    options:
      - name: ndots
        value: "2"
      - name: edns0

上記のPodが作成されたとき、testコンテナの/etc/resolv.confファイルには以下の内容が設定されます。

nameserver 192.0.2.1
search ns1.svc.cluster-domain.example my.dns.search.suffix
options ndots:2 edns0

IPv6の設定では、検索パスとネームサーバーは次のように設定されます。

kubectl exec -it dns-example -- cat /etc/resolv.conf

このコマンドの出力は以下のようになります。

nameserver 2001:db8:30::a
search default.svc.cluster-domain.example svc.cluster-domain.example cluster-domain.example
options ndots:5

DNS検索ドメインリストの制限

FEATURE STATE: Kubernetes 1.28 [stable]

Kubernetes自体は、DNS検索リストの要素数が32を超えたり、DNS検索ドメイン名の文字数の合計が2048を超えたりしない限り、DNS設定に制限を設けません。 この制限は、ノードのリゾルバー設定ファイル、PodのDNS設定、およびそれらがマージされたDNS設定に適用されます。

WindowsノードにおけるDNSの名前解決

  • Windowsノード上で実行されるPodでは、DNSポリシーのClusterFirstWithHostNetはサポートされていません。 Windowsでは、.を含む名前をFQDNとして扱い、FQDN解決はスキップされます。
  • Windowsにおいては、複数のDNSリゾルバーを利用できます。 それぞれのリゾルバーの挙動がわずかに異なるため、Resolve-DNSName PowerShellコマンドレットを使用することが推奨されます。
  • Linuxには完全修飾名としての名前解決が失敗した後に使用されるDNSサフィックスリストがあります。 一方で、WindowsにはDNSサフィックスを1つしか指定できず、それはPodの名前空間に対応するDNSサフィックスです(例: mydns.svc.cluster.local)。 Windowsでは、この単一のサフィックスを用いてFQDNやService、ネットワーク名の名前解決を行えます。 例えば、defaultという名前空間で起動されたPodは、DNSサフィックスとしてdefault.svc.cluster.localが設定されます。 このPodでは、kubernetes.default.svc.cluster.localkubernetesは名前解決できますが、部分的に修飾された名前(kubernetes.defaultkubernetes.default.svc)は名前解決できません。

次の項目

DNS設定の管理方法に関しては、DNS Serviceの設定を確認してください。