基于Docker提供内置的DNS服务器

dns简介
dns服务是域名系统的缩写, 英文全称:domain name system,将域名和ip地址相互映射。在容器环境中,dns至关重要,例如在kubernetes集群中,通常一组pod由一个service负载,但是service的ip地址有可能需要变动,那么就可以让pod通过域名的方式去访问service,pod无需理会ip地址的变化。
docker dns
docker link
docker link是一个遗留的特性,在新版本的docker中,一般不推荐使用。简单来说docker link就是把两个容器连接起来,容器可以使用容器名进行通信,而不需要依赖ip地址(其实就是在容器的/etc/hosts文件添加了host记录,原本容器之间的ip就是通的,只是我们增加了host记录,可以不用ip去访问)
创建容器centos-1:
[root@host1 ~]# docker run -itd --name centos-1  registry.cn-shanghai.aliyuncs.com/public-namespace/cr7-centos7-tool:v2  
创建容器centos-2,使用--link name:alias,name就是要访问的目标机器,alias就是自定义的别名。
[root@host1 ~]# docker run -itd --name centos-2  --link centos-1:centos-1-alias  registry.cn-shanghai.aliyuncs.com/public-namespace/cr7-centos7-tool:v2  
查看容器centos-2的/etc/hosts文件:
[root@host1 ~]# docker exec centos-2 cat /etc/hosts127.0.0.1       localhost::1     localhost ip6-localhost ip6-loopbackfe00::0 ip6-localnetff00::0 ip6-mcastprefixff02::1 ip6-allnodesff02::2 ip6-allrouters172.18.0.2      centos-1-alias 9dde6339057a centos-1  #容器centos-1的host记录172.18.0.3      f1a7e5fa3d96  #容器centos-2自身的host记录  
意味着centos-2可以用centos-1-alias,9dde6339057a,centos-1来访问原先创建的容器。centos-1是不可以通过hostname访问centos-2的。
[root@host1 ~]# docker exec centos-2 ping centos-1-aliasping centos-1-alias (172.18.0.2) 56(84) bytes of data.64 bytes from centos-1-alias (172.18.0.2): icmp_seq=1 ttl=64 time=0.174 ms^c[root@host1 ~]# docker exec centos-2 ping centos-1ping centos-1-alias (172.18.0.2) 56(84) bytes of data.64 bytes from centos-1-alias (172.18.0.2): icmp_seq=1 ttl=64 time=1.37 ms64 bytes from centos-1-alias (172.18.0.2): icmp_seq=2 ttl=64 time=0.523 ms^c[root@host1 ~]# docker exec centos-2 ping 9dde6339057aping centos-1-alias (172.18.0.2) 56(84) bytes of data.64 bytes from centos-1-alias (172.18.0.2): icmp_seq=1 ttl=64 time=2.59 ms64 bytes from centos-1-alias (172.18.0.2): icmp_seq=2 ttl=64 time=3.75 ms  
embedded dns
从docker 1.10开始,docker提供了一个内置的dns服务器,当创建的容器属于自定义网络时,容器的/etc/resolv.conf会使用内置的dns服务器(地址永远是127.0.0.11)来解析相同自定义网络内的其他容器。
为了向后兼容,default bridge网络的dns配置没有改变,默认的docker网络使用的是宿主机的/etc/resolv.conf的配置。
创建一个自定义网络:
[root@host1 ~]# docker network create my-network#bridge,host,none为docker默认创建的网络[root@host1 ~]# docker network lsnetwork id          name                driver              scope2115f17cd9d0        bridge              bridge              local19accfa096cf        host                host                locala23c8b371c7f        my-network          bridge              local0a33edc20fae        none                null                local  
分别创建两个容器属于自定义网络my-network中:
[root@host1 ~]# docker run -itd --name centos-3 --net my-network  registry.cn-shanghai.aliyuncs.com/public-namespace/cr7-centos7-tool:v2 [root@host1 ~]# docker run -itd --name centos-4 --net my-network  registry.cn-shanghai.aliyuncs.com/public-namespace/cr7-centos7-tool:v2    
查看容器centos-4的/etc/hosts和/etc/resolv.conf,可以看到nameserver添加的ip为127.0.0.11的embedded dns:
#/etc/hosts中没有配置对方的host记录[root@host1 ~]# docker exec centos-4 cat /etc/hosts127.0.0.1       localhost::1     localhost ip6-localhost ip6-loopbackfe00::0 ip6-localnetff00::0 ip6-mcastprefixff02::1 ip6-allnodesff02::2 ip6-allrouters172.19.0.3      555281f37ea3#/etc/resolv.conf配置了dns服务器127.0.0.11[root@host1 ~]# docker exec centos-4 cat /etc/resolv.confnameserver 127.0.0.11options ndots:0  
此时centos-3和centos-4可以互相解析:
[root@host1 ~]# docker exec centos-4 ping centos-3ping centos-3 (172.19.0.2) 56(84) bytes of data.64 bytes from centos-3.my-network (172.19.0.2): icmp_seq=1 ttl=64 time=0.128 ms64 bytes from centos-3.my-network (172.19.0.2): icmp_seq=2 ttl=64 time=0.078 ms64 bytes from centos-3.my-network (172.19.0.2): icmp_seq=3 ttl=64 time=0.103 ms^c[root@host1 ~]# docker exec centos-3 ping centos-4ping centos-4 (172.19.0.3) 56(84) bytes of data.64 bytes from centos-4.my-network (172.19.0.3): icmp_seq=1 ttl=64 time=0.087 ms64 bytes from centos-4.my-network (172.19.0.3): icmp_seq=2 ttl=64 time=0.101 ms64 bytes from centos-4.my-network (172.19.0.3): icmp_seq=3 ttl=64 time=0.076 ms^c  
docker dns配置
方式一:docker run (针对单个容器)
flag description
--dns 指定dns服务器地址,如果容器不能访问指定的所有ip地址,则会使用8.8.8.8作为dns服务器地址(docker默认定义的)
--dns-search 当容器访问一个不包括完全域名的主机名时,在该主机名后面添加dns-search指定的域名后缀,例如容器访问centos-1,dns-search配置的是example.com,则会解析成centos-1.example.com
--dns-opt options ndots:5的含义是当查询的域名字符串内的点字符数量大于等于ndots值(5)时,则认为是完整域名,直接解析,不会走 search 域
--hostname 指定容器hostname
方式二:daemon.json
nameserver只针对docker默认网络所有容器,dns-search和dns-opts针对所有网络容器。
{     dns: [114.114.114.114,223.5.5.5],     dns-opts:[ndots:5],     dns-search:[example.com]}   
kubernetes dns
在kubernetes中,有以下4中dns策略,可以通过dnspolicy指定:
default: pod从运行所在的节点继承名称解析配置,就是该 pod 的 dns 配置会跟宿主机完全一致。。default 不是默认的 dns 策略。如果未明确指定dnspolicy,则使用 clusterfirst。
clusterfirst: 它会预先把 kube-dns(或 coredns)的信息当作预设参数写入到该 pod 内的 dns 配置。不过clusterfirst 还有一个冲突,如果你的 pod 设置了 hostnetwork=true,则 clusterfirst 就会被强制转换成 default。
clusterfirstwithhostnet: 对于与 hostnetwork(网络接口使用的是宿主机的) 一起运行的 pod,应显式设置其dns策略 clusterfirstwithhostnet,他将同时解决default和clusterfirst的dns解析。如果不加上dnspolicy: clusterfirstwithhostnet ,pod默认使用所在宿主主机使用的dns,这样也会导致容器内不能通过service name 访问k8s集群中其他pod。
none: 表示会清除 pod 预设的 dns 配置,当 dnspolicy 设置成这个值之后,kubernetes 不会为 pod 预先载入任何自身逻辑判断得到的 dns 配置。因此若要将 dnspolicy 的值设为 none,为了避免 pod 里面没有配置任何 dns参数,至少需要在dnsconfig中设置nameservers的参数。
在 kubernetes 1.11 及其以后版本中,推荐使用 coredns, kubeadm 默认会安装 coredns。当pod向coredns发起dns解析请求时,coredns先会自己尝试解析,如果无法解析该域名,会将dns请求交给coredns的pod所在的宿主机,让宿主机尝试解析。
本次实验kubernetes集群中coredns service的地址是10.247.3.10。
❯ kubectl get svc -n kube-systemname type cluster-ip external-ip port(s) agecoredns clusterip 10.247.3.10 53/udp,53/tcp,8080/tcp 13d  
宿主机的/etc/resolv.conf文件如下:
[root@cr7-k8s-85091-ydy99 ~]# cat /etc/resolv.conf# generated by networkmanagersearch openstacklocalnameserver 100.125.1.250nameserver 100.125.64.250options single-request-reopen  
cluterfirst
cluterfirst是kubernetes集群中默认的dns策略,这里是一个普通的pod yaml文件,没有指定dnspolicy。
apiversion: v1kind: podmetadata:  name: busybox  namespace: defaultspec:  containers:  - image: busybox:1.28    command:      - sleep      - 3600    imagepullpolicy: ifnotpresent    name: busybox  restartpolicy: always  
创建pod后,进入该pod查看/etc/resolv.conf配置,可以看到nameserver为coredns的service的地址。
/ # cat /etc/resolv.confnameserver 10.247.3.10search default.svc.cluster.local svc.cluster.local cluster.local openstacklocaloptions single-request-reopen timeout:2 ndots:5  
如果在pod的yaml文件中指定了dns参数,会和默认的clusterfirst的配置叠加:
apiversion: v1kind: podmetadata:  name: busybox  namespace: defaultspec:  containers:  - image: busybox:1.28    command:      - sleep      - 3600    imagepullpolicy: ifnotpresent    name: busybox  restartpolicy: always  dnsconfig:    nameservers:      - 1.2.3.4    searches:      - ns1.svc.cluster-domain.example      - my.dns.search.suffix    options:      - name: ndots        value: 2      - name: edns0/ # cat /etc/resolv.confnameserver 10.247.3.10nameserver 1.2.3.4search default.svc.cluster.local svc.cluster.local cluster.local openstacklocal ns1.svc.cluster-domain.example my.dns.search.suffixoptions timeout:2 ndots:2 edns0 single-request-reopen  
default
dnspolicy为default模式时,pod使用的是宿主机的dns配置:
apiversion: v1kind: podmetadata:  name: busybox  namespace: defaultspec:  containers:  - image: busybox:1.28    command:      - sleep      - 3600    imagepullpolicy: ifnotpresent    name: busybox  restartpolicy: always  dnspolicy: default/ # cat /etc/resolv.confnameserver 100.125.1.250nameserver 100.125.64.250search openstacklocaloptions single-request-reopen timeout:2  
clusterfirstwithhostnet
当pod使用了hostnetwork模式时,pod使用的是宿主机的网卡:
#进入pod后查看/ # ifconfig......eth0      link encap:ethernet  hwaddr fa3e14:9b          inet addr:192.168.0.8  bcast:192.168.0.255  mask:255.255.255.0          inet6 addr: fe80:3eff149b/64 scope:link          up broadcast running multicast  mtu:1500  metric:1          rx packets:44239432 errors:0 dropped:0 overruns:0 frame:0          tx packets:47841007 errors:0 dropped:0 overruns:0 carrier:0          collisions:0 txqueuelen:1000          rx bytes:19884749467 (18.5 gib)  tx bytes:34713001649 (32.3 gib)......     
当pod使用hostnetwork模式,并且未指定dnspolicy为clusterfirstwithhostnet时,pod会使用的宿主机的dns:
apiversion: v1kind: podmetadata:  name: busybox  namespace: defaultspec:  containers:  - image: busybox:1.28    command:      - sleep      - 3600    imagepullpolicy: ifnotpresent    name: busybox  restartpolicy: always  hostnetwork: true  
此时pod无法通过域名访问kubernetes集群内部:
#hostnetwork模式如果不指定dnspolicy则使用default模式,使用的宿主机的dns/ # cat /etc/resolv.confnameserver 100.125.1.250nameserver 100.125.64.250search openstacklocaloptions single-request-reopen timeout:2#pod可以通过域名访问外网,但是无法通过域名访问kubernetes集群内部/ # ping baidu.comping baidu.com (39.156.69.79): 56 data bytes64 bytes from 39.156.69.79: seq=0 ttl=49 time=29.193 ms64 bytes from 39.156.69.79: seq=1 ttl=49 time=29.104 ms^c--- baidu.com ping statistics ---2 packets transmitted, 2 packets received, 0% packet lossround-trip min/avg/max = 29.104/29.148/29.193 ms/ # ping nginxping: bad address 'nginx'  
如果pod在hostnetwork模式下要通过域名的方式访问kubernetes集群内的服务,需要指定dnspolicy为clusterfirstwithhostnet:
apiversion: v1kind: podmetadata:  name: busybox  namespace: defaultspec:  containers:  - image: busybox:1.28    command:      - sleep      - 3600    imagepullpolicy: ifnotpresent    name: busybox  restartpolicy: always  hostnetwork: true  dnspolicy: clusterfirstwithhostnet   
此时查看pod的dns配置,可以看到nameserver使用的是coredns:
#clusterfirstwithhostnet模式dns使用的是coredns的地址,/ # cat /etc/resolv.confnameserver 10.247.3.10search default.svc.cluster.local svc.cluster.local cluster.local openstacklocaloptions single-request-reopen timeout:2 ndots:5#可以通过域名访问外网,也通过域名访问集群内部/ # nslookup baidu.comserver:    10.247.3.10address 1: 10.247.3.10 coredns.kube-system.svc.cluster.localname:      baidu.comaddress 1: 39.156.69.79address 2: 220.181.38.148/ #/ # nslookup nginxserver:    10.247.3.10address 1: 10.247.3.10 coredns.kube-system.svc.cluster.localname:      nginxaddress 1: 10.247.60.222 nginx.default.svc.cluster.local/ #  
none
当设置dnspolicy为none时,不会使用kubernetes集群和宿主机的 dns 策略,但是必须自己配置dnsconfig。
apiversion: v1kind: podmetadata:  name: busybox  namespace: defaultspec:  containers:  - image: busybox:1.28    command:      - sleep      - 3600    imagepullpolicy: ifnotpresent    name: busybox  restartpolicy: always  dnspolicy: none  dnsconfig:    nameservers:      - 1.2.3.4/ # cat /etc/resolv.confnameserver 1.2.3.4options single-request-reopen timeout:2  
statefulset 和 service
statefulset pod 具有唯一的标识,该标识包括顺序标识、稳定的网络标识和稳定的存储。该标识和 pod 是绑定的,不管它被调度在哪个节点上。
statefulset 中的每个 pod 根据 statefulset 的名称和 pod 的序号派生出它的主机名。组合主机名的格式为$(statefulset 名称)-$(序号)。下例将会创建三个名称分别为 web-0、web-1、web-2 的 pod。statefulset 可以使用 headless service(无头服务)控制它的 pod 的网络域。管理域的这个服务的格式为: $(服务名称).$(命名空间).svc.cluster.local,其中 cluster.local 是集群域。一旦每个 pod 创建成功,就会得到一个匹配的 dns 子域,格式为:$(pod 名称).$(所属服务的 dns 域名),其中所属服务由 statefulset 的 servicename 域来设定。
通过域名去访问headless service负载的pod是不走iptables的,通过域名去访问clusterip负载的pod要走iptables。
下面给出一些选择集群域、服务名、statefulset 名、及其怎样影响 statefulset 的 pod 上的 dns 名称的示例:
cluster domain service (ns/name) statefulset (ns/name) statefulset domain pod dns pod hostname
cluster.local default/nginx default/web nginx.default.svc.cluster.local web-{0..n-1}.nginx.default.svc.cluster.local web-{0..n-1}
cluster.local foo/nginx foo/web nginx.foo.svc.cluster.local web-{0..n-1}.nginx.foo.svc.cluster.local web-{0..n-1}
kube.local foo/nginx foo/web nginx.foo.svc.kube.local web-{0..n-1}.nginx.foo.svc.kube.local web-{0..n-1}
headless service
首先我们将statefulset和headless service结合使用,(通常情况下是这么做的):
apiversion: v1kind: servicemetadata:  name: headless-nginx  labels:    app: nginxspec:  ports:  - port: 80    name: web  clusterip: none  selector:    app: nginx---apiversion: apps/v1kind: statefulsetmetadata:  name: webspec:  selector:    matchlabels:      app: nginx   servicename: headless-nginx  replicas: 3   template:    metadata:      labels:        app: nginx     spec:      containers:      - name: nginx        image: nginx:1.7.9        ports:        - containerport: 80          name: web  
查看创建的statefulset的pod,命名是有规律的按照0,1,2的顺序递增。
root@master01:~/yaml/service# kubectl get pod -o widename                     ready   status    restarts   age     ip               node       nominated node   readiness gatesweb-0                    1/1     running   0          6s      192.168.5.59     worker01              web-1                    1/1     running   0          5s      192.168.30.117   worker02              web-2                    1/1     running   0          3s      192.168.5.58     worker01                
查看创建的headless service,可以看到clusterip为none:
root@master01:~/yaml/service# kubectl get svcname              type           cluster-ip       external-ip     port(s)   ageheadless-nginx    clusterip      none                       80/tcp    15m  
找一个相同namespace的pod来解析该headless service:
root@master01:~/yaml/service# kubectl exec busybox1 -- nslookup headless-nginxserver:    10.96.0.10address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local#解析出来的ip地址为3个statefulset的pod的ipname:      headless-nginxaddress 1: 192.168.30.117 web-1.headless-nginx.default.svc.cluster.localaddress 2: 192.168.5.59 web-0.headless-nginx.default.svc.cluster.localaddress 3: 192.168.5.58 web-2.headless-nginx.default.svc.cluster.local  
查看default命名空间下的pod的/etc/resolv.conf配置:
root@master01:~/yaml/service# kubectl exec busybox1 -- cat /etc/resolv.conf           nameserver 10.96.0.10search default.svc.cluster.local svc.cluster.local cluster.localoptions ndots:5  
在不同的 namespace 下的 pod 通过 service 访问的时候,需要在 service name 后面加上 .。名字>
root@master01:~/yaml/service# kubectl exec busybox2 -n kube-system  -- nslookup  headless-nginx.default  server:    10.96.0.10address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.localname:      headless-nginx.default.svc.cluster.localaddress 1: 192.168.5.58 web-2.headless-nginx.default.svc.cluster.localaddress 2: 192.168.5.59 web-0.headless-nginx.default.svc.cluster.localaddress 3: 192.168.30.117 web-1.headless-nginx.default.svc.cluster.local  
查看kube-system命名空间下的pod的/etc/resolv.conf配置:
root@master01:~/yaml/service# kubectl exec busybox2 -n kube-system  -- cat /etc/resolv.conf             nameserver 10.96.0.10search kube-system.svc.cluster.local svc.cluster.local cluster.local options ndots:5  
clusterip service
现在我们将statefulset和clusterip service结合使用:
apiversion: v1kind: servicemetadata:  name: clusterip-nginx  labels:    app: nginx#clusterip不为none则表示该service有clusterip    spec:  ports:  - port: 80    name: web  selector:    app: nginx  
查看创建的service:
root@master01:~/yaml/service# kubectl get svcname              type           cluster-ip       external-ip     port(s)   ageclusterip-nginx   clusterip      10.110.176.201             80/tcp    13s  
此时用pod解析域名只能得到clusterip地址,无法得到pod的ip地址:
root@master01:~/yaml/service# kubectl exec busybox1 -- nslookup clusterip-nginxserver:    10.96.0.10address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.localname:      clusterip-nginxaddress 1: 10.110.176.201 clusterip-nginx.default.svc.cluster.local  
pod 的 hostname 与 subdomain
在 kubernetes 中,如果不指定 pod 的 hostname,其默认为 pod.metadata.name,通过 spec.hostname 字段可以自定义;另外还可以给 pod 设置 subdomain,通过 spec.subdomain 字段。比如下面这个例子:
创建一个nginx pod,指定pod的hostname和subdomain:
apiversion: v1kind: podmetadata:  name: nginx  labels:    name: nginxspec:  hostname: domain-test  subdomain: subdomain-test  containers:  - image: nginx    name: nginx---apiversion: v1kind: servicemetadata:  name: subdomain-testspec:  selector:    name: nginx  ports:  - port: 80    targetport: 80    protocol: tcp  
可以查看这个 pod 的 hostname 和 hosts 文件:
[root@localhost ~]# kubectl get po -o widename ready status restarts age ip node nominated node readiness gatesbusybox-5bbb5d7ff7-dh68j 1/1 running 0 112m 10.244.1.246 172-16-105-2 nginx 1/1 running 0 2m 10.244.1.253 172-16-105-2 [root@localhost ~]# kubectl exec -it nginx bashroot@domain-test:/# cat /etc/hosts# kubernetes-managed hosts file.127.0.0.1localhost::1localhost ip6-localhost ip6-loopbackfe00::0ip6-localnetfe00::0ip6-mcastprefixfe00::1ip6-allnodesfe00::2ip6-allrouters10.244.1.253domain-test.subdomain-test.default.svc.cluster.localdomain-testroot@domain-test:/#  
在 busybox 容器中通过域名访问这个pod:


安立LTE信令测试仪获美国无线通信大会新兴科技奖
大众又要出新款跑车了,堆出这款xl跑车不输奥迪R8,售价三十万左右!
石墨烯电池“烯王”遭质疑,到底是怎么回事?
荣耀MagicBook锐龙版轻薄本评测 兼具颜值和性能简直不给传统PC留一点活路
高压变频器在密炼机上的应用
基于Docker提供内置的DNS服务器
物联网项目实施中需要关注的5大领域
富士通新型无线连接控制技术有望用于5G
2G物联网池子入口将关闭,NB-IoT引流正当时
浏览器里的Cookie是什么
百度、阿里巴巴和腾讯齐聚智博会
如何通过RFIC简化5G毫米波设计
vxworks BSP设计
ST抢镜慕尼黑电子展 深耕汽车电子
什么是伺服变压器?变压器检测时需要检测哪几个方面?
多线程下为什么HashMap会出现死循环
XD602大行程压电纳米定位台,应用于精密定位
涂布机数据采集监控运维系统解决方案
智能家电的语音怎么样
雷曼光电推出基于COB技术的Micro LED超高清显示产品