服务的 DNS 和 Pod
Kubernetes 为 Service 和 Pod 创建 DNS 记录。您可以使用固定的 DNS 名称而非 IP 地址来访问 Service。
Kubernetes 发布有关 Pod 和 Service 的信息,这些信息用于编程 DNS。kubelet 配置 Pod 的 DNS,以便运行中的容器可以通过名称而不是 IP 查找 Service。
集群中定义的 Service 会被分配 DNS 名称。默认情况下,客户端 Pod 的 DNS 搜索列表包含 Pod 自己的命名空间和集群的默认域。
Service 的命名空间
DNS 查询可能会根据发出查询的 Pod 所在的命名空间返回不同的结果。未指定命名空间的 DNS 查询仅限于 Pod 的命名空间。通过在 DNS 查询中指定命名空间来访问其他命名空间中的 Service。
例如,考虑一个位于 test
命名空间中的 Pod。一个名为 data
的 Service 位于 prod
命名空间中。
对 data
的查询不返回任何结果,因为它使用了 Pod 所在的 test
命名空间。
对 data.prod
的查询返回预期结果,因为它指定了命名空间。
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 记录?
- Service
- Pod
以下部分详细介绍了支持的 DNS 记录类型和布局。任何其他碰巧能工作的布局、名称或查询都被视为实现细节,可能会在不通知的情况下发生变化。有关最新规范,请参阅 基于 DNS 的 Kubernetes Service 发现。
Service
A/AAAA 记录
“正常”(非 Headless)Service 会根据 Service 的 IP 族分配 DNS A 和/或 AAAA 记录,名称格式为 my-svc.my-namespace.svc.cluster-domain.example
。这会解析到 Service 的集群 IP。
Headless Service(没有集群 IP)也会被分配 DNS A 和/或 AAAA 记录,名称格式为 my-svc.my-namespace.svc.cluster-domain.example
。与普通 Service 不同,这会解析到由 Service 选择的所有 Pod 的 IP 集合。客户端可以使用此集合,或者采用标准的轮询机制从集合中选择。
SRV 记录
SRV 记录是为属于普通 Service 或 Headless Service 的命名端口创建的。
- 对于每个命名端口,SRV 记录的格式为
_端口名._端口协议.我的服务.我的命名空间.svc.集群域.example
。 - 对于常规 Service,这会解析为端口号和域名:
my-svc.my-namespace.svc.cluster-domain.example
。 - 对于 Headless Service,这会解析为多个答案,Service 后端的每个 Pod 对应一个答案,答案中包含端口号和 Pod 的域名,格式为
hostname.my-svc.my-namespace.svc.cluster-domain.example
。
Pod
A/AAAA 记录
Kube-DNS 版本在实现 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
一些集群 DNS 机制,例如 CoreDNS,也为 提供 A
记录
<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,其主机名将被设置为 "my-host"
。
Pod 规约还有一个可选的 subdomain
字段,可以用来表明 Pod 是该命名空间中某个子组的一部分。例如,在命名空间 "my-namespace"
中,一个 Pod 的 spec.hostname
设置为 "foo"
,spec.subdomain
设置为 "bar"
,则其主机名将设置为 "foo"
,其完全限定域名 (FQDN) 将设置为 "foo.bar.my-namespace.svc.cluster.local"
(再次强调,从 Pod 内部观察到)。
如果在与 Pod 相同的命名空间中存在一个 Headless Service,且其名称与子域相同,则集群的 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
给定上面的 Service "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 没有设置hostname
,所以不会为其 Pod 名称创建 A 和 AAAA 记录。没有 hostname
但设置了 subdomain
的 Pod 将只为 Headless Service(busybox-subdomain.my-namespace.svc.cluster-domain.example
)创建 A 或 AAAA 记录,指向 Pod 的 IP 地址。此外,除非在 Service 上设置了 publishNotReadyAddresses=True
,否则 Pod 需要处于就绪状态才能拥有记录。Pod 的 setHostnameAsFQDN 字段
Kubernetes v1.22 [stable]
当 Pod 配置为具有完全限定域名 (FQDN) 时,其主机名为短主机名。例如,如果你的 Pod 的完全限定域名是 busybox-1.busybox-subdomain.my-namespace.svc.cluster-domain.example
,那么默认情况下在该 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 策略
DNS 策略可以按 Pod 进行设置。当前 Kubernetes 支持以下 Pod 特有的 DNS 策略。这些策略在 Pod 规约的 dnsPolicy
字段中指定。
“
Default
”:Pod 继承其所运行节点的名称解析配置。更多详细信息请参阅相关讨论。“
ClusterFirst
”:任何与配置的集群域后缀不匹配的 DNS 查询(例如 “www.kubernetes.io
”)都会由 DNS 服务器转发到上游的命名服务器。集群管理员可以配置额外的 stub 域和上游 DNS 服务器。关于在这种情况下如何处理 DNS 查询的详细信息,请参阅相关讨论。“
ClusterFirstWithHostNet
”:对于使用 hostNetwork 运行的 Pod,应将其 DNS 策略明确设置为 “ClusterFirstWithHostNet
”。否则,使用 hostNetwork 运行且 DNS 策略为"ClusterFirst"
的 Pod 将回退到"Default"
策略的行为。说明
这在 Windows 上不受支持。详情请参阅下文。“
None
”:允许 Pod 忽略 Kubernetes 环境中的 DNS 设置。所有 DNS 设置应使用 Pod 规约中的dnsConfig
字段提供。请参阅下方的Pod 的 DNS 配置小节。
说明
“Default” 不是默认的 DNS 策略。如果未明确指定dnsPolicy
,则使用 “ClusterFirst”。下面的示例展示了一个 Pod,由于其 hostNetwork
被设置为 true
,因此其 DNS 策略设置为 “ClusterFirstWithHostNet
”。
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
” 时,该列表必须包含至少一个 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 [stable]
Kubernetes 本身不会限制 DNS 配置,除非搜索域列表的长度超过 32 个或所有搜索域的总长度超过 2048 个。此限制分别适用于节点的解析器配置文件、Pod 的 DNS 配置以及合并后的 DNS 配置。
说明
一些早期版本的容器运行时可能对其 DNS 搜索域的数量有自己的限制。根据容器运行时环境的不同,包含大量 DNS 搜索域的 Pod 可能会停留在 pending 状态。
已知 containerd v1.5.5 或更早版本以及 CRI-O v1.21 或更早版本存在此问题。
Windows 节点上的 DNS 解析
- 在 Windows 节点上运行的 Pod 不支持
ClusterFirstWithHostNet
。Windows 将所有包含.
的名称视为 FQDN 并跳过 FQDN 解析。 - 在 Windows 上,可以使用多种 DNS 解析器。由于它们行为略有不同,建议使用
Resolve-DNSName
powershell cmdlet 进行名称查询解析。 - 在 Linux 上,有一个 DNS 后缀列表,用于在名称作为完全限定名称解析失败后使用。在 Windows 上,你只能有一个 DNS 后缀,即与该 Pod 的命名空间关联的 DNS 后缀(例如:
mydns.svc.cluster.local
)。Windows 可以解析 FQDN、Service 或可以使用此单个后缀解析的网络名称。例如,在default
命名空间中创建的 Pod 将具有 DNS 后缀default.svc.cluster.local
。在 Windows Pod 内部,可以解析kubernetes.default.svc.cluster.local
和kubernetes
,但不能解析部分限定名称(kubernetes.default
或kubernetes.default.svc
)。
接下来
有关管理 DNS 配置的指南,请查阅配置 DNS 服务。