服务和 Pod 的 DNS
Kubernetes 为服务和 Pod 创建 DNS 记录。您可以使用一致的 DNS 名称而不是 IP 地址来联系服务。
Kubernetes 发布有关 Pod 和服务的信息,这些信息用于编程 DNS。Kubelet 配置 Pod 的 DNS,以便运行的容器可以通过名称而不是 IP 来查找服务。
集群中定义的服务被分配了 DNS 名称。默认情况下,客户端 Pod 的 DNS 搜索列表包括 Pod 自身的命名空间和集群的默认域。
服务的命名空间
DNS 查询可能会根据发出查询的 Pod 的命名空间返回不同的结果。未指定命名空间的 DNS 查询仅限于 Pod 的命名空间。通过在 DNS 查询中指定命名空间来访问其他命名空间中的服务。
例如,考虑一个位于 test 命名空间中的 Pod。一个名为 data 的服务位于 prod 命名空间中。
对 data 的查询不会返回任何结果,因为它使用的是 Pod 的 test 命名空间。
对 data.prod 的查询返回预期结果,因为它指定了命名空间。
可以使用 Pod 的 /etc/resolv.conf 来扩展 DNS 查询。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 记录?
- Service
- Pod
以下部分详细介绍了支持的 DNS 记录类型和布局。任何其他碰巧有效的布局、名称或查询都被视为实现细节,如有更改,恕不另行通知。有关最新规范,请参阅基于 Kubernetes DNS 的服务发现。
Service
A/AAAA 记录
“普通”(非无头)服务根据服务的 IP 系列或系列分配 DNS A 和/或 AAAA 记录,其名称格式为 my-svc.my-namespace.svc.cluster-domain.example。这将解析为服务的集群 IP。
无头服务(没有集群 IP)服务也被分配了 DNS A 和/或 AAAA 记录,其名称格式为 my-svc.my-namespace.svc.cluster-domain.example。与普通服务不同,这将解析为服务选择的所有 Pod 的 IP 集。客户端应使用该集合,或者从该集合中使用标准的循环选择。
SRV 记录
为作为普通或无头服务一部分的命名端口创建 SRV 记录。对于每个命名端口,SRV 记录的格式为 _port-name._port-protocol.my-svc.my-namespace.svc.cluster-domain.example。对于常规服务,这将解析为端口号和域名:my-svc.my-namespace.svc.cluster-domain.example。对于无头服务,这将解析为多个答案,每个支持服务的 Pod 一个,并包含端口号和 Pod 的域名,格式为 hostname.my-svc.my-namespace.svc.cluster-domain.example。
Pod
A/AAAA 记录
在实现DNS 规范之前,Kube-DNS 版本具有以下 DNS 解析
pod-ipv4-address.my-namespace.pod.cluster-domain.example.
例如,如果 default 命名空间中的 Pod 的 IP 地址为 172.17.0.3,并且集群的域名是 cluster.local,则该 Pod 的 DNS 名称是
172-17-0-3.default.pod.cluster.local.
服务公开的任何 Pod 都具有以下可用的 DNS 解析
pod-ipv4-address.service-name.my-namespace.svc.cluster-domain.example.
Pod 的主机名和子域名字段
目前,当创建一个 Pod 时,它的主机名(从 Pod 内部观察到)是 Pod 的 metadata.name 值。
Pod 规范有一个可选的 hostname 字段,可用于指定不同的主机名。指定后,它将优先于 Pod 的名称作为 Pod 的主机名(同样,从 Pod 内部观察到)。例如,给定一个 spec.hostname 设置为 "my-host" 的 Pod,该 Pod 的主机名将设置为 "my-host"。
Pod 规范还有一个可选的 subdomain 字段,可用于指示该 Pod 是命名空间子组的一部分。例如,一个 spec.hostname 设置为 "foo" 且 spec.subdomain 设置为 "bar" 的 Pod,位于命名空间 "my-namespace" 中,它的主机名将设置为 "foo",其完全限定域名 (FQDN) 将设置为 "foo.bar.my-namespace.svc.cluster.local"(同样,从 Pod 内部观察到)。
如果在与 Pod 相同的命名空间中存在一个与子域名同名的无头服务,则集群的 DNS 服务器还会返回 Pod 的完全限定主机名的 A 和/或 AAAA 记录。
示例
apiVersion: v1
kind: Service
metadata:
name: busybox-subdomain
spec:
selector:
name: busybox
clusterIP: None
ports:
- name: foo # name is not required for single-port Services
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" 和将 spec.subdomain 设置为 "busybox-subdomain" 的 Pod,第一个 Pod 会将其自身的 FQDN 视为 "busybox-1.busybox-subdomain.my-namespace.svc.cluster-domain.example"。DNS 在该名称下提供 A 和/或 AAAA 记录,指向 Pod 的 IP。Pod "busybox1" 和 "busybox2" 都将拥有自己的地址记录。
一个EndpointSlice可以为任何端点地址指定 DNS 主机名及其 IP。
注意
因为不会为 Pod 名称创建 A 和 AAAA 记录,所以需要hostname 才能创建 Pod 的 A 或 AAAA 记录。没有 hostname 但有 subdomain 的 Pod 将只为无头服务 (busybox-subdomain.my-namespace.svc.cluster-domain.example) 创建 A 或 AAAA 记录,指向 Pod 的 IP 地址。此外,除非在服务上设置了 publishNotReadyAddresses=True,否则 Pod 需要处于就绪状态才能拥有记录。Pod 的 setHostnameAsFQDN 字段
Kubernetes v1.22 [稳定]当 Pod 配置为具有完全限定域名 (FQDN) 时,其主机名是短主机名。例如,如果您有一个完全限定域名 busybox-1.busybox-subdomain.my-namespace.svc.cluster-domain.example 的 Pod,则默认情况下,该 Pod 中的 hostname 命令返回 busybox-1,而 hostname --fqdn 命令返回 FQDN。
当您在 Pod 规范中设置 setHostnameAsFQDN: true 时,kubelet 会将 Pod 的 FQDN 写入该 Pod 命名空间的主机名中。在这种情况下,hostname 和 hostname --fqdn 都返回 Pod 的 FQDN。
注意
在 Linux 中,内核的主机名字段(struct utsname 的 nodename 字段)限制为 64 个字符。
如果 Pod 启用了此功能,并且其 FQDN 超过 64 个字符,则它将无法启动。Pod 将保持在 Pending 状态(kubectl 显示为 ContainerCreating),并生成错误事件,例如“无法从 Pod 主机名和集群域构造 FQDN,FQDN long-FQDN 太长(最大 64 个字符,请求了 70 个字符)”。改善此场景下用户体验的一种方法是创建一个准入 webhook 控制器,以便在用户创建顶级对象(例如 Deployment)时控制 FQDN 大小。
Pod 的 DNS 策略
可以针对每个 Pod 设置 DNS 策略。目前,Kubernetes 支持以下特定于 Pod 的 DNS 策略。这些策略在 Pod 规范的 dnsPolicy 字段中指定。
- “
Default”:Pod 从其运行所在的节点继承名称解析配置。有关更多详细信息,请参阅相关讨论。 - “
ClusterFirst”:任何与已配置的集群域后缀(例如“www.kubernetes.io”)不匹配的 DNS 查询都将由 DNS 服务器转发到上游名称服务器。集群管理员可能配置了额外的存根域和上游 DNS 服务器。有关在这些情况下如何处理 DNS 查询的详细信息,请参阅相关讨论。 - “
ClusterFirstWithHostNet”:对于使用 hostNetwork 运行的 Pod,您应该将其 DNS 策略显式设置为“ClusterFirstWithHostNet”。否则,使用 hostNetwork 和“ClusterFirst”运行的 Pod 将回退到“Default”策略的行为。- 注意:Windows 不支持此功能。有关详细信息,请参阅下方。
- “
None”:它允许 Pod 忽略来自 Kubernetes 环境的 DNS 设置。所有 DNS 设置都应该使用 Pod Spec 中的dnsConfig字段提供。请参阅下面的Pod 的 DNS 配置小节。
注意
“Default”不是默认的 DNS 策略。如果未显式指定dnsPolicy,则使用“ClusterFirst”。下面的示例显示了一个 Pod,其 DNS 策略设置为“ClusterFirstWithHostNet”,因为它已将 hostNetwork 设置为 true。
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 [稳定]Pod 的 DNS 配置允许用户更好地控制 Pod 的 DNS 设置。
dnsConfig 字段是可选的,它可以与任何 dnsPolicy 设置一起使用。但是,当 Pod 的 dnsPolicy 设置为“None”时,必须指定 dnsConfig 字段。
以下是用户可以在 dnsConfig 字段中指定的属性
nameservers:将用作 Pod 的 DNS 服务器的 IP 地址列表。最多可以指定 3 个 IP 地址。当 Pod 的dnsPolicy设置为“None”时,该列表必须至少包含一个 IP 地址,否则此属性是可选的。列出的服务器将与从指定的 DNS 策略生成的基准名称服务器合并,并删除重复的地址。searches:Pod 中用于主机名查找的 DNS 搜索域列表。此属性是可选的。指定后,提供的列表将合并到从所选 DNS 策略生成的基准搜索域名中。重复的域名将被删除。Kubernetes 允许最多 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 # this is an example
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 [稳定]Kubernetes 本身不会限制 DNS 配置,直到搜索域列表的长度超过 32 或所有搜索域的总长度超过 2048。此限制分别适用于节点的解析器配置文件、Pod 的 DNS 配置和合并的 DNS 配置。
注意
某些早期版本的容器运行时可能对 DNS 搜索域的数量有其自身的限制。根据容器运行时环境,具有大量 DNS 搜索域的 Pod 可能会陷入挂起状态。
已知 containerd v1.5.5 或更早版本以及 CRI-O v1.21 或更早版本存在此问题。
Windows 节点上的 DNS 解析
- 对于在 Windows 节点上运行的 Pod,不支持 ClusterFirstWithHostNet。Windows 将所有带有
.的名称视为 FQDN,并跳过 FQDN 解析。 - 在 Windows 上,可以使用多个 DNS 解析器。由于这些解析器的行为略有不同,因此建议使用
Resolve-DNSNamePowerShell cmdlet 进行名称查询解析。 - 在 Linux 上,您有一个 DNS 后缀列表,该列表在完全限定名称解析失败后使用。在 Windows 上,您只能拥有 1 个 DNS 后缀,即与该 Pod 的命名空间关联的 DNS 后缀(例如:
mydns.svc.cluster.local)。Windows 可以解析 FQDN、服务或可以使用此单个后缀解析的网络名称。例如,在default命名空间中生成的 Pod 将具有 DNS 后缀default.svc.cluster.local。在 Windows Pod 内部,您可以解析kubernetes.default.svc.cluster.local和kubernetes,但不能解析部分限定名称(kubernetes.default或kubernetes.default.svc)。
下一步
有关管理 DNS 配置的指南,请查看配置 DNS 服务