作者 | 江小南


说到DNS域名解析,大家想到最多的可能就是/etc/hosts文件,并没有什么错,但是/etc/hosts只能做到本机域名解析,如果跨机器的解析就有点捉襟见肘了。

在服务器中还有一个配置值得大家注意,/etc/resolv.conf,这个文件用于配置DNS服务器,使域名解析可以扩展到本机以外。

kubernetes集群使用到的就是这种机制。

原理

当kubernetes初始化完成后,在kube-system名称空间下会出现kube-dns的service服务与coredns的pod。

[root@k8s-master etc]# kubectl get svc -n kube-system
NAME       TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE
kube-dns   ClusterIP   10.96.0.10   <none>        53/UDP,53/TCP,9153/TCP   14d
[root@k8s-master etc]# kubectl get pod -n kube-system -o wide| grep coredns
coredns-5897cd56c4-7ps2n                   1/1     Running   9          14d   192.168.235.220   k8s-master    <none>           <none>
coredns-5897cd56c4-j7psj                   1/1     Running   9          14d   192.168.235.221   k8s-master    <none>           <none>
[root@k8s-master etc]#

CoreDNS是一个DNS解析的组件,作为集群内的DNS服务器,为集群内部提供域名解析服务。比如说一个前端pod要通过service name访问后端pod,前端pod会先通过自身的dns文件(/etc/resolv.conf)指向dns服务器,由dns服务器做域名解析转换成对用的ip,然后通过ip访问到后端pod。

配置策略

在yaml中,通过dnsPolicy字段配置DNS策略,共有4种策略:

  1. ClusterFirst:默认策略,表示使用集群内部的CoreDNS来做域名解析。
  2. Default:Pod直接继承集群node节点的域名解析配置,也就是,Pod会直接使用宿主机上的/etc/resolv.conf文件内容。
  3. None:忽略k8s集群环境中的DNS设置,Pod会使用其dnsConfig字段所提供的DNS配置。
  4. ClusterFirstWithHostNet:宿主机与 Kubernetes 共存,这种情况下的POD,既能用宿主机的DNS服务,又能使用kube-dns的Dns服务,注意的是需要将hostNetwork打开。

部署验证

首先说明一点,CoreDNS本身具有解析集群外域名的能力,但是集群外的DNS服务器并不一定具有解析集群内域名的能力。基于这个认识,我们做下列的测试。

  1. ClusterFirst
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx-deploy
  name: nginx-deploy
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx-deploy
  template:
    metadata:
      labels:
        app: nginx-deploy
    spec:
      restartPolicy: Always
      containers:
        - name: mynginx
          image: nginx
          imagePullPolicy: IfNotPresent
      dnsPolicy: ClusterFirst
[root@k8s-master test]# kubectl apply -f deployment.yaml 
deployment.apps/nginx-deploy created
[root@k8s-master test]# kubectl get pod
NAME                            READY   STATUS    RESTARTS   AGE
nginx-deploy-6d79d74f76-qp8pr   1/1     Running   0          77s
nginx-deploy-6d79d74f76-tjcxt   1/1     Running   0          77s
[root@k8s-master test]#
# 进入到容器内部
[root@k8s-master test]# kubectl exec -it nginx-deploy-6d79d74f76-qp8pr -c mynginx -- /bin/bash
root@nginx-deploy-6d79d74f76-qp8pr:/# cat /etc/resolv.conf 
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local pek3.qingcloud.com
options ndots:5
root@nginx-deploy-6d79d74f76-qp8pr:/#
# 访问service成功
root@nginx-deploy-6d79d74f76-qp8pr:/# curl nginx-deploy.default.svc:8000
<!DOCTYPE html>
<html>
...
<body>
<h1>Welcome to nginx!</h1>
...
</body>
</html>
root@nginx-deploy-6d79d74f76-qp8pr:/#

可以发现NDS服务器为10.96.0.10,这个地址我们在上面原理部分获取到的kube-dns的地址一致。说明ClusterFirst的策略使用集群内部的CoreDNS来做域名解析,并且成功解析了service域名。

  1. Default

将yaml中的dnsPolicy: ClusterFirst修改为dnsPolicy: Default

[root@k8s-master test]# kubectl apply -f deployment.yaml 
deployment.apps/nginx-deploy created
[root@k8s-master test]# kubectl get pod
NAME                            READY   STATUS    RESTARTS   AGE
nginx-deploy-85bd9d5f4c-js6fv   1/1     Running   0          5s
nginx-deploy-85bd9d5f4c-q8pxb   1/1     Running   0          5s
[root@k8s-master test]#
# 进入到容器内部
[root@k8s-master test]# kubectl exec -it nginx-deploy-85bd9d5f4c-js6fv -c mynginx -- /bin/bash
root@nginx-deploy-85bd9d5f4c-js6fv:/# cat /etc/resolv.conf 
nameserver 100.64.9.5
search pek3.qingcloud.com
root@nginx-deploy-85bd9d5f4c-js6fv:/#
# 查看本机的 /etc/resolv.conf
[root@k8s-master test]# cat /etc/resolv.conf 
# Generated by NetworkManager
search pek3.qingcloud.com
nameserver 100.64.9.5
[root@k8s-master test]#
# 访问service不成功
root@nginx-deploy-85bd9d5f4c-js6fv:/# curl nginx-deploy.default.svc:8000
curl: (6) Could not resolve host: nginx-deploy.default.svc
root@nginx-deploy-85bd9d5f4c-js6fv:/#
# 访问百度成功
root@nginx-deploy-85bd9d5f4c-js6fv:/# curl www.baidu.com
<!DOCTYPE html>
<!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer><link rel=stylesheet type=text/css href=http://s1.bdstatic.com/r/www/cache/bdorz/baidu.min.css><title>百度一下,你就知道</title></head> <body link=#0000cc> <div id=wrapper> <div id=head> <div class=head_wrapper> <div class=s_form> <div class=s_form_wrapper> <div id=lg> <img hidefocus=true src=//www.baidu.com/img/bd_logo1.png width=270 height=129> </div> <form id=form name=f action=//www.baidu.com/s class=fm> <input type=hidden name=bdorz_come value=1> <input type=hidden name=ie value=utf-8> <input type=hidden name=f value=8> <input type=hidden name=rsv_bp value=1> <input type=hidden name=rsv_idx value=1> <input type=hidden name=tn value=baidu><span class="bg s_ipt_wr"><input id=kw name=wd class=s_ipt value maxlength=255 autocomplete=off autofocus></span><span class="bg s_btn_wr"><input type=submit id=su value=百度一下 class="bg s_btn"></span> </form> </div> </div> <div id=u1> <a href=http://news.baidu.com name=tj_trnews class=mnav>新闻</a> <a href=http://www.hao123.com name=tj_trhao123 class=mnav>hao123</a> <a href=http://map.baidu.com name=tj_trmap class=mnav>地图</a> <a href=http://v.baidu.com name=tj_trvideo class=mnav>视频</a> <a href=http://tieba.baidu.com name=tj_trtieba class=mnav>贴吧</a> <noscript> <a href=http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u=http%3A%2F%2Fwww.baidu.com%2f%3fbdorz_come%3d1 name=tj_login class=lb>登录</a> </noscript> <script>document.write('<a href="http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u='+ encodeURIComponent(window.location.href+ (window.location.search === "" ? "?" : "&")+ "bdorz_come=1")+ '" name="tj_login" class="lb">登录</a>');</script> <a href=//www.baidu.com/more/ name=tj_briicon class=bri style="display: block;">更多产品</a> </div> </div> </div> <div id=ftCon> <div id=ftConw> <p id=lh> <a href=http://home.baidu.com>关于百度</a> <a href=http://ir.baidu.com>About Baidu</a> </p> <p id=cp>©2017 Baidu <a href=http://www.baidu.com/duty/>使用百度前必读</a>  <a href=http://jianyi.baidu.com/ class=cp-feedback>意见反馈</a> 京ICP证030173号  <img src=//www.baidu.com/img/gs.gif> </p> </div> </div> </div> </body> </html>
root@nginx-deploy-85bd9d5f4c-js6fv:/#

说明使用Default策略,Pod会直接使用宿主机上的/etc/resolv.conf文件内容,当然解析service域名是不能成功的。

  1. None
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx-deploy
  name: nginx-deploy
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx-deploy
  template:
    metadata:
      labels:
        app: nginx-deploy
    spec:
      restartPolicy: Always
      containers:
        - name: mynginx
          image: nginx
          imagePullPolicy: IfNotPresent
      dnsPolicy: None
      dnsConfig:
        nameservers: ["172.31.0.3","172.31.0.4"]
        searches:
          - default.svc.cluster.local
          - svc.cluster.local
          - cluster.local
        options:
          - name: ndots
            value: "5"
[root@k8s-master test]# kubectl apply -f deployment.yaml 
deployment.apps/nginx-deploy created
[root@k8s-master test]# kubectl get pod
NAME                            READY   STATUS    RESTARTS   AGE
nginx-deploy-6699fcc589-7nrn7   1/1     Running   0          7s
nginx-deploy-6699fcc589-8sk8p   1/1     Running   0          7s
[root@k8s-master test]#
# 进入到容器内部
[root@k8s-master test]# kubectl exec -it nginx-deploy-6699fcc589-7nrn7 -c mynginx -- /bin/bash
root@nginx-deploy-6699fcc589-7nrn7:/# cat /etc/resolv.conf 
nameserver 172.31.0.3
nameserver 172.31.0.4
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
root@nginx-deploy-6699fcc589-7nrn7:/#

说明None策略Pod会使用其dnsConfig字段所提供的DNS配置。nameserver最多可配置3个ip。域名解析能力视DNS服务器的解析能力而定。

  1. ClusterFirstWithHostNet
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx-deploy
  name: nginx-deploy
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx-deploy
  template:
    metadata:
      labels:
        app: nginx-deploy
    spec:
      restartPolicy: Always
      containers:
        - name: mynginx
          image: nginx
          imagePullPolicy: IfNotPresent
      dnsPolicy: ClusterFirstWithHostNet
      hostNetwork: true
[root@k8s-master test]# kubectl apply -f deployment.yaml 
deployment.apps/nginx-deploy created
[root@k8s-master test]# kubectl get pod
NAME                            READY   STATUS    RESTARTS   AGE
nginx-deploy-74bd47ccdd-cjbmv   1/1     Running   0          4s
nginx-deploy-74bd47ccdd-m6bm6   1/1     Running   0          4s
[root@k8s-master test]#
[root@k8s-master test]# kubectl exec -it nginx-deploy-74bd47ccdd-cjbmv -c mynginx -- /bin/bash
root@k8s-worker2:/# cat /etc/resolv.conf 
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local pek3.qingcloud.com
options ndots:5
root@k8s-worker2:/#
# 访问service成功
root@k8s-worker2:/# curl nginx-deploy.default.svc:8000
<!DOCTYPE html>
<html>
...
<body>
<h1>Welcome to nginx!</h1>
...
</html>
root@k8s-worker2:/#
# 访问百度成功
root@k8s-worker2:/# curl www.baidu.com
<!DOCTYPE html>
<!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer><link rel=stylesheet type=text/css href=http://s1.bdstatic.com/r/www/cache/bdorz/baidu.min.css><title>百度一下,你就知道</title></head> <body link=#0000cc> <div id=wrapper> <div id=head> <div class=head_wrapper> <div class=s_form> <div class=s_form_wrapper> <div id=lg> <img hidefocus=true src=//www.baidu.com/img/bd_logo1.png width=270 height=129> </div> <form id=form name=f action=//www.baidu.com/s class=fm> <input type=hidden name=bdorz_come value=1> <input type=hidden name=ie value=utf-8> <input type=hidden name=f value=8> <input type=hidden name=rsv_bp value=1> <input type=hidden name=rsv_idx value=1> <input type=hidden name=tn value=baidu><span class="bg s_ipt_wr"><input id=kw name=wd class=s_ipt value maxlength=255 autocomplete=off autofocus></span><span class="bg s_btn_wr"><input type=submit id=su value=百度一下 class="bg s_btn"></span> </form> </div> </div> <div id=u1> <a href=http://news.baidu.com name=tj_trnews class=mnav>新闻</a> <a href=http://www.hao123.com name=tj_trhao123 class=mnav>hao123</a> <a href=http://map.baidu.com name=tj_trmap class=mnav>地图</a> <a href=http://v.baidu.com name=tj_trvideo class=mnav>视频</a> <a href=http://tieba.baidu.com name=tj_trtieba class=mnav>贴吧</a> <noscript> <a href=http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u=http%3A%2F%2Fwww.baidu.com%2f%3fbdorz_come%3d1 name=tj_login class=lb>登录</a> </noscript> <script>document.write('<a href="http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u='+ encodeURIComponent(window.location.href+ (window.location.search === "" ? "?" : "&")+ "bdorz_come=1")+ '" name="tj_login" class="lb">登录</a>');</script> <a href=//www.baidu.com/more/ name=tj_briicon class=bri style="display: block;">更多产品</a> </div> </div> </div> <div id=ftCon> <div id=ftConw> <p id=lh> <a href=http://home.baidu.com>关于百度</a> <a href=http://ir.baidu.com>About Baidu</a> </p> <p id=cp>©2017 Baidu <a href=http://www.baidu.com/duty/>使用百度前必读</a>  <a href=http://jianyi.baidu.com/ class=cp-feedback>意见反馈</a> 京ICP证030173号  <img src=//www.baidu.com/img/gs.gif> </p> </div> </div> </div> </body> </html>
root@k8s-worker2:/#

能同时访问service和百度,说明此配置既能使用集群内部的CoreDNS来做域名解析,又可以使用宿主机的DNS做域名解析。

注意点:我们有时也会看到如下的配置。

dnsPolicy: ClusterFirst
hostNetwork: true

hostNetwork表示与宿主机共享网络空间。但是只有dnsPolicy: ClusterFirstWithHostNet时生效。而此处配置的ClusterFirst由于打开了hostNetwork为true,会自动转换为Default,那么此时解析集群内的域名是不能成功的。