服务和 Pod 的 DNS
Kubernetes 为 Services 和 Pod 创建 DNS 记录。你可以使用一致的 DNS 名称而不是 IP 地址来访问 Services。
Kubernetes 发布有关 Pods 和 Services 的信息,这些信息用于对 DNS 进行编程。kubelet 配置 Pod 的 DNS,以便运行中的容器可以通过名称而不是 IP 查找 Services。
在集群中定义的 Services 会被分配 DNS 名称。默认情况下,客户端 Pod 的 DNS 搜索列表包括 Pod 自己的命名空间和集群的默认域。
Services 的命名空间
DNS 查询可能会根据发出查询的 Pod 的命名空间返回不同的结果。未指定命名空间的 DNS 查询仅限于 Pod 的命名空间。通过在 DNS 查询中指定命名空间来访问其他命名空间中的 Services。
例如,考虑一个在 `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 记录?
- 服务
- Pod
以下各节详细介绍了支持的 DNS 记录类型和布局。任何其他可能有效的布局、名称或查询都被视为实现细节,并可能在不通知的情况下更改。有关最新规范,请参阅基于 Kubernetes DNS 的服务发现。
服务
A/AAAA 记录
“普通”(非 Headless)Services 会根据 Service 的 IP 族为其分配 DNS A 和/或 AAAA 记录,名称格式为 `my-svc.my-namespace.svc.cluster-domain.example`。这会解析为 Service 的集群 IP。
Headless Services(没有集群 IP)也会被分配 DNS A 和/或 AAAA 记录,名称格式为 `my-svc.my-namespace.svc.cluster-domain.example`。与普通 Service 不同,它会解析为 Service 选择的所有 Pod 的 IP 地址集。客户端预计会使用该集合,或者从该集合中进行标准轮询选择。
SRV 记录
为作为普通或 Headless Service 的一部分的命名端口创建 SRV 记录。
- 对于每个命名端口,SRV 记录的格式为 `_port-name._port-protocol.my-svc.my-namespace.svc.cluster-domain.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 记录
在 DNS 规范 实现之前,Kube-DNS 版本具有以下 DNS 解析
<pod-IPv4-address>.<namespace>.pod.<cluster-domain>
例如,如果 `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>
例如,如果 `cafe` 命名空间中的 Pod 的 IP 地址为 172.17.0.3,是名为 `barista` 的 Service 的端点,并且集群的域名是 `cluster.local`,则该 Pod 将具有此服务作用域的 DNS `A` 记录。
172-17-0-3.barista.cafe.svc.cluster.local
Pod 的主机名和子域名字段
目前,当创建 Pod 时,其主机名(从 Pod 内部观察)是 Pod 的 `metadata.name` 值。
Pod Spec 具有可选的 `hostname` 字段,可用于指定不同的主机名。当指定时,它优先于 Pod 的名称作为 Pod 的主机名(再次强调,从 Pod 内部观察)。例如,给定一个 `spec.hostname` 设置为 `"my-host"` 的 Pod,该 Pod 的主机名将被设置为 `"my-host"`。
Pod spec 还有一个可选的 `subdomain` 字段,用于指示 Pod 是命名空间子组的一部分。例如,一个 `spec.hostname` 设置为 `"foo"`,`spec.subdomain` 设置为 `"bar"`,在命名空间 `"my-namespace"` 中的 Pod,其主机名将设置为 `"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"` 的 Pods,第一个 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 地址。此外,Pod 需要处于 Ready 状态才能拥有记录,除非在 Service 上设置了 `publishNotReadyAddresses=True`。Pod 的 setHostnameAsFQDN 字段
当 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 将保持 `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)”。改进此场景用户体验的一种方法是创建一个准入 Webhook 控制器,以便在用户创建顶级对象(例如 Deployment)时控制 FQDN 大小。
Pod 的 DNS 策略
DNS 策略可以按每个 Pod 进行设置。目前 Kubernetes 支持以下 Pod 特定的 DNS 策略。这些策略在 Pod Spec 的 `dnsPolicy` 字段中指定。
“`Default`”:Pod 从其运行节点继承名称解析配置。有关更多详细信息,请参阅相关讨论。
“`ClusterFirst`”:任何不匹配已配置的集群域后缀的 DNS 查询,例如“`www.kubernetes.io`”,都由 DNS 服务器转发到上游名称服务器。集群管理员可能配置了额外的 stub 域和上游 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 配置
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 本身不对 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、Services 或可以通过此单一后缀解析的网络名称。例如,在 `default` 命名空间中生成的 Pod 将具有 DNS 后缀 `default.svc.cluster.local`。在 Windows Pod 内部,你可以解析 `kubernetes.default.svc.cluster.local` 和 `kubernetes`,但不能解析部分限定的名称(`kubernetes.default` 或 `kubernetes.default.svc`)。
下一步
有关管理 DNS 配置的指导,请查看配置 DNS 服务。