coreDNS 除了在Kubernetes集群上调度 DNS Pod 和 Service, 还配置 kubelet 以告知各个容器使用 DNS Service 的 IP 来解析 DNS 名称。集群搭建好之后,需要确认各个节点上的Pod都能ping通coreDNS,否则无法正常进行域名解析。另外“无头(Headless)” Service(没有集群 IP)与普通 Service 不同,servicename会被解析成对应 Service 所选择的 Pod IP 的集合。而大多数情况下,普通 Service域名会被解析成对应的clusterIP.

操作环境

k8s-master
k8s-node1
k8s-node2

下载coredns

cd /opt/k8s/coredns
git clone https://github.com/coredns/deployment.git mv deployment coredns

配置coredns

cd /opt/k8s/coredns/coredns/kubernetes
./deploy.sh 10.0.0.0/24 cluster.local
这里,10.0.0.0/24是你的service网段, cluster.local是域名后缀。该命令输出的内容保存为文件generatedCoredns.yaml.

启动coredns

kubectl create -f generatedCoredns.yaml
如果报错:Get "https://10.0.0.1:443/api/v1/endpoints?limit=500&resourceVersion=0": x509: certificate is valid for 127.0.0.1, 172.x.x.x, not 10.0.0.1,那么Coredns是默认kubernetes的API-Server是10.0.0.1:443,需要修改上面的generatedCoredns.yaml文件。添加如下的KUBERNETES_SERVICE_HOST、KUBERNETES_SERVICE_PORT和KUBERNETES_SERVICE_PORT_HTTPS三个coredns容器的环境变量,使之指向你的apiserver IP和端口。

containers:
      - name: coredns
        image: coredns/coredns:1.7.0
        imagePullPolicy: IfNotPresent
        env:
          - name: KUBERNETES_SERVICE_HOST
            value: "172.171.19.210"
          - name: KUBERNETES_SERVICE_PORT
            value: "6443"
          - name: KUBERNETES_SERVICE_PORT_HTTPS
            value: "6443"

查看创建结果类似如下:

# kubectl get all -n kube-system -l k8s-app=kube-dns
NAME                           READY   STATUS    RESTARTS   AGE
pod/coredns-76ff9d9d89-2lzml   1/1     Running   0          3h47m

NAME               TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE
service/kube-dns   ClusterIP   10.0.0.2     <none>        53/UDP,53/TCP,9153/TCP   3h47m

NAME                      READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/coredns   1/1     1            1           3h47m

NAME                                 DESIRED   CURRENT   READY   AGE
replicaset.apps/coredns-76ff9d9d89   1         1         1       3h47m

显示所有的容器都是Running并且READY的个数都是“1/1”,如果不是这样需要查看log并根据具体情况进行修复。

验证

本coredns要能解析本机上所有的service的域名,也就是能解析kubernetes.default.svc.cluster.local和nginx-service.test.svc.nginx-service

#kubectl get svc -o wide --all-namespaces
NAMESPACE     NAME                                         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE     SELECTOR
default       kubernetes                                   ClusterIP   10.0.0.1     <none>        443/TCP                  85d     <none>
test          nginx-service                                ClusterIP   10.0.0.100   <none>        80:32460/TCP             47h     app=nginx

如果想在pod里面能解析域名,需要修改kubelet的配置文件,加上一句--cluster-dns=10.0.0.2 --cluster-domain=cluster.local :

--cluster-dns=10.0.0.2 --cluster-domain=cluster.local \
--network-plugin=cni --cni-bin-dir=/opt/cni/bin --cni-conf-dir=/etc/cni/net.d \

然后重启kubelet.尝试在pod中ping 这几个service的域名可以通。在Pod里面去nslookup kubernetes.default.svc.cluster.local 可以得到预期的结果,解析出了地址10.0.0.1,如果不支持nslookup可以直接ping该域名.
注意:不能到容器的网络命名空间去nslookup该域名,因为网络命名空间和文件命名空间不一致无法正确解析,必须要到容器内部去域名解析。

QA

  1. 我们知道集群内的容器是通过kube-dns这个service来封装coredns容器的。那容器是怎么知道service名称要到coredns去域名解析的呢?kube-dns这个service又是谁解析的呢?
    答:当集群创建kube-dns这个service后,kubelet会为每个启动的容器配置域名解析地址也就是kube-dns service的clusterIP. 如下所示:
[root@cluster-product-master-1 ~]# kubectl exec -ti -n monitoring    blackbox-f494c5f74-6lqb5  cat /etc/resolv.conf
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
nameserver 10.244.64.10
search monitoring.svc.cluster.local svc.cluster.local cluster.local
options ndots:5

因此kube-dns这个service是不需要解析的。当容器的DNS解析请求到达10.244.64.10(service clusterIP)时,会把数据包转发给coredns容器(10.244.4.12和10.244.7.9)。这个转换过程是由kube-proxy完成的。kube-proxy可以使用iptables或者IPVS模式,以IPVS模式为例,每个节点输入如下命令可以看到转发规则:

[root@cluster-product-worker-4 ~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  172.17.0.1:30609 rr
  -> 10.244.3.12:8080             Masq    1      0          0         
UDP  10.244.64.10:53 rr
  -> 10.244.4.12:53               Masq    1      0          9         
  -> 10.244.7.9:53                Masq    1      0          9