kubernetes集群内部DNS解析原理
当kubernetes初始化完成后,在kube-system名称空间下会出现kube-dns的service服务与coredns的pod
$ kubectl get svc -n kube-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kube-dns ClusterIP 241.254.0.10 <none> 53/UDP,53/TCP,9153/TCP 25d
$ kubectl get pod -n kube-system -o wide| grep coredns
coredns-7844787459-f7sb4 1/1 Running 0 25d 241.255.0.123 master <none> <none>
coredns-7844787459-rg9rz 1/1 Running 0 25d 241.255.0.124 master <none> <none>
CoreDNS是一个DNS解析的组件,作为集群内的DNS服务器,为集群内部提供域名解析服务。比如当集群内Pod要通过service名称访问后端pod时,就会用到coredns的解析服务。CoreDNS服务监视Kubernetes API,当使用kubectl命令向apiServer提交service请求时,CoreDNS会为每一个Service创建DNS记录用于域名解析。
DNS解析原理
当客户端Pod想要通过service name访问后端服务时,会先通过客户端pod自身的dns文件(/etc/resolv.conf)指向dns服务器,
DNS服务器将service name转换成对应ip,客户端Pod在通过ip请求后端服务
DNS配置策略
每个Pod所使用的DNS策略,是通过pod.spec.dnsPolicy字段设置的,共有4种DNS策略:
- ClusterFirst:默认策略,表示使用集群内部的CoreDNS来做域名解析,Pod内/etc/resolv.conf文件中配置的nameserver是集群的DNS服务器,即kube-dns的地址。
- Default:Pod直接继承集群node节点的域名解析配置,也就是,Pod会直接使用宿主机上的/etc/resolv.conf文件内容。
- None:忽略k8s集群环境中的DNS设置,Pod会使用其dnsConfig字段所提供的DNS配置,dnsConfig字段的内容要在创建Pod时手动设置好。
- ClusterFirstWithHostNet:宿主机与 Kubernetes 共存,这种情况下的POD,既能用宿主机的DNS服务,又能使用kube-dns的Dns服务,需要将hostNetwork打开。
ClusterFirst
apiVersion: v1
kind: Pod
metadata:
name: mypod
labels:
app: mypod
spec:
containers:
- name: mynginx
image: mynginx:v1
dnsPolicy: ClusterFirst #字段设置为ClusterFirst(该值为默认值,不设置也是该值)
#namserver指向kube-dns service地址
$ kubectl exec mypod -- cat /etc/resolv.conf
nameserver 241.254.0.10
search default.svc.cluster.local svc.cluster.local cluster.local localdomain
options ndots:5
Default
apiVersion: v1
kind: Pod
metadata:
name: mypod
labels:
app: mypod
spec:
containers:
- name: mynginx
image: mynginx:v1
dnsPolicy: Default
#pod内的resolv.conf与宿主机的resolv.conf一致
$ kubectl exec mypod -- cat /etc/resolv.conf
nameserver 192.168.234.2
search localdomain
$ cat /etc/resolv.conf
search localdomain
nameserver 192.168.234.2
None
apiVersion: v1
kind: Pod
metadata:
name: mypod
labels:
app: mypod
spec:
containers:
- name: mynginx
image: mynginx:v1
dnsPolicy: None
dnsConfig:
nameservers: ["192.168.234.1","192.168.234.2"] #最多可指定3个IP,当Pod的dnsPolicy设置为None时,列表必须至少包含一个IP地址
searches: #Pod中主机名查找的DNS搜索域列表
- default.svc.cluster.local
- svc.cluster.local
- cluster.local
options:
- name: ndots
value: "5"
#pod内resolv.conf文件为dnsConfig配置
$ kubectl exec mypod -- cat /etc/resolv.conf
nameserver 192.168.234.1
nameserver 192.168.234.2
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
ClusterFirstWithHostNet
apiVersion: v1
kind: Pod
metadata:
name: mypod
labels:
app: mypod
spec:
containers:
- name: mynginx
image: mynginx:v1
hostNetwork: true #hostNetwork为true时,表示与宿主机共享网络空间
dnsPolicy: ClusterFirst #即使dnsPolicy设置为集群优先,由于hostNetwork: true也会强制将dnsPolicy设置为Default
#所以Pod内resolv.conf与宿主机相同
$ kubectl exec mypod -- cat /etc/resolv.conf
nameserver 192.168.234.2
search localdomain
apiVersion: v1
kind: Pod
metadata:
name: mypod
labels:
app: mypod
spec:
containers:
- name: mynginx
image: mynginx:v1
hostNetwork: true
dnsPolicy: ClusterFirstWithHostNet
#只有dnsPolicy: ClusterFirstWithHostNet,此时pod既可以使用宿主机网络也可以使用kube-dns网络
$ kubectl exec -it mypod -- cat /etc/resolv.conf
nameserver 241.254.0.10
search default.svc.cluster.local svc.cluster.local cluster.local localdomain
options ndots:5
DNS解析5s超时
参考链接:https://monkeywie.cn/2019/12/10/k8s-dns-lookup-timeout/
主要通过配置resolv.conf的single-request-reopen和single-request选项来避免
- single-request-reopen (glibc>=2.9) 发送 A 类型请求和 AAAA 类型请求使用不同的源端口。这样两个请求在 conntrack 表中不占用同一个表项,从而避免冲突。
- single-request (glibc>=2.10) 避免并发,改为串行发送 A 类型和AAAA类型请求,没有了并发,从而也避免了冲突。
修改/etc/resolv.conf文件,在最后加入一行文本:
options single-request-reopen
或者
options single-request
k8s部署pod可通过修改 pod 的 postStart hook 来设置
containers:
- lifecycle:
postStart:
exec:
command:
- /bin/sh
- -c
- "/bin/echo 'options single-request-reopen' >> /etc/resolv.conf"
或者通过修改 pod 的 template.spec.dnsConfig 来设置
template:
spec:
dnsConfig:
options:
- name: single-request-reopen
注: 需要 k8s 版本>=1.9并且不支持alpine基础镜像的容器,因为apline底层使用的musl libc库并不支持这些 resolv.conf 选项,所以如果使用alpine基础镜像构建的应用,还是无法规避超时的问题