ServiceとPodに対するDNS
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.prodやdata.prod.svc.cluster.localというクエリを正常に名前解決できます。
DNSレコード
DNSレコードが作成されるオブジェクトは、以下の2つです。
- Service
- 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にhostnameが設定されていない場合、そのPod名に対するhostnameベースのA(AAAA)レコードは作成されません。
hostnameを持たずにsubdomainのみを持つPodの場合、ヘッドレスService(busybox-subdomain.my-namespace.svc.cluster-domain.example)に対し、PodのIPアドレスを指すA(AAAA)レコードのみが作成されます。
なお、ServiceにpublishNotReadyAddresses=Trueが設定されている場合を除き、PodがDNSレコードに含まれるためには、Podの状態がReadyである必要があります。PodのsetHostnameAsFQDNフィールド
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の名前空間におけるホスト名として書き込みます。
この場合、hostnameとhostname --fqdnの両方がPodのFQDNを返します。
備考:
Linuxでは、カーネルのホスト名のフィールド(struct utsnameのnodenameフィールド)は64文字に制限されています。
Podがこの機能を有効にしていて、そのFQDNが64文字より長い場合、Podは起動に失敗します。
PodはPendingステータス(kubectlではContainerCreatingと表示)のままになり、「Failed to construct FQDN from Pod hostname and cluster domain, FQDN long-FQDN is too long (64 characters is the max, 70 characters requested)」といったエラーイベントが生成されます。
この場合のユーザー体験を向上させる1つの方法は、admission webhook controllerを作成して、ユーザーがDeploymentなどのトップレベルのオブジェクトを作成するときに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"ポリシーの挙動にフォールバックします。備考:
本ポリシーはWindowsではサポートされていません。 詳細はWindowsノードにおけるDNSの名前解決をご確認ください。"
None": Kubernetes環境からDNS設定を無視することができます。 全てのDNS設定は、PodのspecのdnsConfigフィールドで指定する必要があります。 詳細は、以下のPodのDNS設定をご覧ください。
備考:
"Default"は、デフォルトのDNSポリシーではありません。dnsPolicyが明示的に指定されていない場合、"ClusterFirst"が使用されます。下記の例では、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設定
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検索ドメインリストの制限
Kubernetes 1.28 [stable]Kubernetes自体は、DNS検索リストの要素数が32を超えたり、DNS検索ドメイン名の文字数の合計が2048を超えたりしない限り、DNS設定に制限を設けません。 この制限は、ノードのリゾルバー設定ファイル、PodのDNS設定、およびそれらがマージされたDNS設定に適用されます。
備考:
古いバージョンの一部のコンテナランタイムでは、DNS検索リストの要素数に制限がある場合があります。 コンテナランタイムによっては、DNS検索ドメインの要素数が多い場合、Podの状態がPendingのままとなることがあります。
この問題は、containerd v1.5.5以前、およびCRI-O v1.21以前で発生することが確認されています。
WindowsノードにおけるDNSの名前解決
- Windowsノード上で実行されるPodでは、DNSポリシーの
ClusterFirstWithHostNetはサポートされていません。 Windowsでは、.を含む名前をFQDNとして扱い、FQDN解決はスキップされます。 - Windowsにおいては、複数のDNSリゾルバーを利用できます。
それぞれのリゾルバーの挙動がわずかに異なるため、
Resolve-DNSNamePowerShellコマンドレットを使用することが推奨されます。 - 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.localやkubernetesは名前解決できますが、部分的に修飾された名前(kubernetes.defaultやkubernetes.default.svc)は名前解決できません。
次の項目
DNS設定の管理方法に関しては、DNS Serviceの設定を確認してください。