k8s 集群内 dns 规范
zone 设置
DNS 记录的 zone 信息为全局配置,配置地方包括 kubelet 和 coredns 两部分。
kubelet 的启动参数
- 通过 kubelet 的 yaml 配置文件的 clusterDomain 字段。
- 通过 kubelet 的参数
--cluster-domain
。
设置了 kubelet 的启动参数后,会设置容器的 /etc/resolv.conf 中的 search 域为如下格式:
1 | search default.svc.cluster.local svc.cluster.local cluster.local tbsite.net |
其中 search 域中的 cluster.local 为 kubelet 的配置。
coredns 的配置文件
coredns controller 需要 watch k8s 集群中的 pod 和 service,将其进行注册,因此 coredns 需要知道集群的 zone 配置。该配置信息位于 coredns 的配置文件 ConfigMap kube-system/coredns 中,默认的配置如下:
1 | Corefile: | |
其中 cluster.local 为对应的 k8s zone。
域名注册
在 k8s 中,Service 和 Pod 对象会创建 DNS 记录,用于 k8s 集群内部的域名解析。
Pod 域名注册
规则一:
每个 k8s pod 都会创建 DNS 记录: <pod_ip>.<namespace>.pod.<cluster-domain>
。其中 .
转换为 -
。
比如 pod nginx-deployment-57d84f57dc-cpgkc 会创建 A 记录 10-244-3-8.default.pod.cluster.local
1 | $ kubectl get pod -o wide nginx-deployment-57d84f57dc-cpgkc -o wide |
规则二:
pod 如何同时指定了 spec.hostname
和 spec.subdomain
,则会创建 A 记录:<hostname>.<subdomain>.<namespace>.svc.cluster.local
,而不是 <pod_ip>.<namespace>.pod.<cluster-domain>
。对于 Statefulset 类型的 pod 会自动设置 spec.hostname
为 pod 的名字,spec.subdomain
为 StatefulSet 的 spec.serviceName
。
比如 pod nginx-statefulset-0 会创建 A 记录 nginx-statefulset-0.nginx.default.svc.cluster.local
。
1 | $ kubectl get pod nginx-statefulset-0 -o wide |
Deployment/DaemonSet 管理的 pod
使用 Deployment/DaemonSet 拉起的 pod,k8s 会创建额外的 DNS 记录:<pod_ip>.<deployment-name/daemonset-name>.<namespace>.svc.<cluster-domain>
。
Service 域名注册
普通 Service
除了 headless service 之外的其他 service 会在 DNS 中生成 my-svc.my-namespace.svc.cluster-domain.example
的 A 或者 AAAA 记录,A 记录指向 ClusterIP。
headless service 会在 DNS 中生成 my-svc.my-namespace.svc.cluster-domain.example
的 A 或者 AAAA 记录,但指向的为 pod ip 地址集合。
k8s 在 pod 的 /etc/resolv.conf 配置如下:
1 | nameserver 10.32.0.10 |
对于跟 pod 同一个 namespace 下的 service,要访问可以直接使用 service 名字接口。跟 pod 不在同一个 namespace 下的 service,访问 service 必须为 service name.service namespace
。
ExternalName Service
service 的 spec.type
为 ExternalName
,该种类型的服务会向 dns 中注册 CNAME 记录,CNAME 记录指向 externalName 字段。例子如下:
1 | apiVersion: v1 |
当访问 my-service.prod.svc.cluster.local
时,DNS 服务会返回 CNAME 记录,指向地址为 my.database.example.com
。
externalIPs 字段
可以针对所有类型的 Service 生效,用来配置多个外部的 ip 地址(该 ip 地址不是 k8s 分配),kube-proxy 会设置该 ip 地址的规则,确保在 k8s 集群内部访问该 ip 地址时,可以路由到后端的 pod。效果就跟访问普通的 ClusterIP 类型 Service 没有区别。
1 | apiVersion: v1 |
当在集群内部访问 198.51.100.32:80
时,流量会被 kube-proxy 路由到当前 Service 的 Endpoint。
该字段存在中间人攻击的风险,不推荐使用。Detect CVE-2020-8554 – Unpatched Man-In-The-Middle (MITM) Attack in Kubernetes
Headless Service
翻译成中文又叫无头 Service,显式的将 Service spec.clusterIP
设置为 "None"
,表示该 Service 为 Headless Service。此时,该 Service 不会分配 clusterIP。因为没有 clusterIP,因此 kube-proxy 并不会处理该 service。
Headless Service 按照是否配置了 spec.selector
在实现上又有不同的区分。
未配置 spec.selector
的 Service,不会创建 EndpointSlice 对象,但是会注册如下的记录:
- 对于 ExternalName Service,配置 CNAME 记录。
- 对于非 ExternalName Service,配置 A/AAAA 记录,指向 EndPoint 的所有 ip 地址。如果未配置 Endpoint,但配置了 externalIPs 字段,则指向 externalIPs。
配置 spec.selector
的 Service,会创建 EndpointSlice 对象,并修改 DNS 配置返回 A 或者 AAAA 记录,指向 pod 的集合。
域名查询
待补充