kubernetes dns

环境信息

  • Centos 7 5.4.225-1
  • Kubernetes v1.24.7

Kubernetes DNS 服务的功能,是用来解析 Kubernetes 集群内的 Pod 和 Service 的域名,一般只供集群内部使用,不给外部使用。

默认情况下,Kubernetes DNS 应用部署后,会对外暴露一个 Service,集群内的容器通过访问该 Service 获得域名解析服务,这个 Service 的 ClusterIP 一般情况下都是固定的。

$ kubectl get services -n kube-system -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 147d k8s-app=kube-dns

当 Kubernetes DNS 服务获得 ClusterIP 后,系统会给 Kubelet 配置启动参数指定 DNS Service 的 ClusterIP,DNS Service 的 IP 会在容器启动时传入,并写入容器系统的 DNS 配置中(一般为 /etc/resolv.conf 文件)

根据 kubelet 服务的启动命令,配置参数可以写在以下相关配置文件中

$ systemctl status kubelet -l
● kubelet.service - kubelet: The Kubernetes Node Agent
Loaded: loaded (/usr/lib/systemd/system/kubelet.service; enabled; vendor preset: disabled)
Drop-In: /usr/lib/systemd/system/kubelet.service.d
└─10-kubeadm.conf
Active: active (running) since Tue 2023-05-02 16:06:16 CST; 21h ago
Docs: https://kubernetes.io/docs/
Main PID: 1413 (kubelet)
Tasks: 29
Memory: 203.0M
CGroup: /system.slice/kubelet.service
└─1413 /usr/bin/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf \
--kubeconfig=/etc/kubernetes/kubelet.conf \
--config=/var/lib/kubelet/config.yaml \
--container-runtime=remote \
--container-runtime-endpoint=unix:///var/run/cri-dockerd.sock \
--pod-infra-container-image=k8s.gcr.io/pause:3.7

$ ps aux | grep kubelet
/usr/bin/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf 、
--kubeconfig=/etc/kubernetes/kubelet.conf \
--config=/var/lib/kubelet/config.yaml \
--container-runtime=remote \
--container-runtime-endpoint=unix:///var/run/cri-dockerd.sock \
--pod-infra-container-image=k8s.gcr.io/pause:3.7

DNS 的相关配置在文件 /var/lib/kubelet/config.yaml 中,主要选项为 clusterDNS

/var/lib/kubelet/config.yaml
apiVersion: kubelet.config.k8s.io/v1beta1
authentication:
anonymous:
enabled: false
webhook:
cacheTTL: 0s
enabled: true
x509:
clientCAFile: /etc/kubernetes/pki/ca.crt
authorization:
mode: Webhook
webhook:
cacheAuthorizedTTL: 0s
cacheUnauthorizedTTL: 0s
cgroupDriver: systemd
clusterDNS:
- 10.96.0.10
clusterDomain: cluster.local
cpuManagerReconcilePeriod: 0s
evictionPressureTransitionPeriod: 0s
fileCheckFrequency: 0s
healthzBindAddress: 127.0.0.1
healthzPort: 10248
httpCheckFrequency: 0s
imageMinimumGCAge: 0s
kind: KubeletConfiguration
logging:
flushFrequency: 0
options:
json:
infoBufferSize: "0"
verbosity: 0
memorySwap: {}
nodeStatusReportFrequency: 0s
nodeStatusUpdateFrequency: 0s
rotateCertificates: true
runtimeRequestTimeout: 0s
shutdownGracePeriod: 0s
shutdownGracePeriodCriticalPods: 0s
staticPodPath: /etc/kubernetes/manifests
streamingConnectionIdleTimeout: 0s
syncFrequency: 0s
volumeStatsAggPeriod: 0s

Kubernetes DNS 解析基本原理

对于 Service,Kubernetes NDS 会生成三类记录,分别是 A 记录、SRV 记录、CNAME 记录。

A 记录

A 记录用于做正向解析,将域名解析到对应的 IP 地址。Kubernetes 为 normalheadless 类型的服务分配不同的 A 记录,不同之处在于 headless 类型的服务未分配 ClusterIP 且不执行负载均衡。

  • DNS 为 normal 类型的 Service 分配一个 A 记录,域名遵循 ${your-svc-name}.${your-namespace}.svc.cluster.local(其中 cluster.local 为集群默认的根域,可在 kubelet 设置 clusterDomain 中更改),A 记录指向 Service 的 ClusterIP。
  • DNS 为 headless 类型的 Service 分配一个 A 记录,域名遵循 ${your-svc-name}.${your-namespace}.svc.cluster.local(其中 cluster.local 为集群默认的根域,可在 kubelet 设置 clusterDomain 中更改),A 记录指向就绪的 Pod 的 IP。DNS 不会自动将此 IP 配置为特定 Pod 的 IP,后端如果有多个就绪的 Pod,DNS 会添加所有解析。

在集群内部,可以通过 ${your-svc-name}.${your-namespace}.svc.cluster.local 访问任何服务,也可以通过简写 ${your-svc-name}.${your-namespace} 直接访问。如果 Pod 和 Service 在同一个 namespace,可以通过 Service name (${your-svc-name}) 直接访问

Pod IP 的 A 记录

启用了 DNS 后,Pod 将被分配一个 DNS A 记录,格式如下

${Pod-ip}.${Pod namespace}.pod.${clusterDomain } --> Pod IP

${Pod-ip} 为 Pod 的 IP 地址使用 - 替换 .,如 Pod IP 为 1.2.3.4,${Pod-ip} 为 1-2-3-4

如果在 Pod Spec 中指定了 hostnamesubdomain,那么 Kubernetes DNS 会为 Pod 额外生产 A 记录

${hostname}.${subdomain}.${Pod namespace}.pod.${clusterDomain } --> Pod IP

SRV 记录

SRV 记录通过在 DNS 中定义服务协议和地址(域名及端口)来促进服务发现。SRV 记录通常定义了 服务名称、协议、请求端口、请求域名(主机)、权重、优先级等内容。以下是一个 SRV 记录的示例

_sip._tcp.example.com    3600    IN    SRV    10    70  5060    srvrecord.example.com
_sip._tcp.example.com 3600 IN SRV 10 30 5060 srvrecord2.example.com

在上面的示例中:

  • _sip - 是服务的名称
  • _tcp - 服务使用的协议
  • 10 - 表示优先级
  • 70 - 表示权重
  • 5060 - 服务要连接的 端口
  • srvrecord.example.com - 服务要连接的主机

Kubernetes 的 DNS 服务遵循以下规则为 Service 提供了服务端口的解析

_${port name}._tcp.${service name}.${service namespace}.svc.cluster.local --> Service Port

解析到的域名(主机)是 ${service name}.${service namespace}.svc.cluster.local
如果是 headless 类型的 Service ,解析到的域名(主机)是 Pod 的 域名。