目录

    1. 关于 DNS

    1.1 DNS 服务的用途

    DNS 提供的是域名到 IP 的映射服务。例如,在浏览器输入 https://www.chenshaowen.com 访问页面,但数据链路是基于 IP 的通信,无法识别 www.chenshaowen.com 。这时就需要进行 DNS 查询,输入参数是 www.chenshaowen.com ,返回结果是 IP 地址。

    可以看到 DNS 提供了一种助记方法,我们不必关注 IP 地址以及其变动,而只需记住一段英文字符串,就能够找到服务。

    一种常见的服务发现机制是配置管理中心,存储 Key/Value 值,例如 Consul、ZooKeeper、Etcd 等。而 DNS 提供的功能,也可以满足微服务架构中服务发现的需求,Kubernetes 就是采用的这种方式。

    Kubernetes 从 1.11 版本开始,使用 CoreDNS 替代 KubeDNS 成为了内置的 DNS 服务。

    1.2 resolv.conf

    /etc/resolv.conf 是 DNS 客户端的配置文件,主要有四部分组成:

    • nameserver ,DNS 服务器的 IP 地址
    • domain ,本地域名的后缀
    • search ,搜索的域名后缀
    • sortlist ,对查询结果进行特定排序

    当遇到无法解析的域名时,解析器才会用到 domain 、search 。例如,访问 http://abc/index.html, 解析器无法解析 abc ,就会拼接 domain 或 search 的配置作为后缀继续解析。当配置了 search 时,domain 失效。

    2. CoreDNS

    2.1 简介

    CoreDNS 是 CNCF 正式毕业的项目。它是一个基于 Caddy 实现,模块化且可插拔的 DNS 服务器。

    每个插件都遵循一个特定的接口协议。在 Corefile 文件中采用 DSL 定义 DNS 服务,可以很方便地开启各种插件,定制 DNS 服务。下面是一个示例:

    example.org:8000 {
        file example.org
        prometheus
        errors  
        log
    }
    .:8000 {
        kubernetes
        proxy . 8.8.8.8
        log
        errors
        cache
    }
    

    这个配置暴露了一个 DNS Server ,监听在 8000 端口,根据不同的域名匹配不同的处理逻辑。每个逻辑,加载指定的插件处理。

    2.2 相关插件

    常用的插件包括:

    • hosts,配置集群全局可解析的 hosts ,需要注意的是域名后缀需要与 search 保持一致,例如,cluster.local ,否则 nodelocaldns 无法上报 coredns 解析
    • errors, 错误记录到 stdout
    • health,提供健康报告接口
    • kubernetes,解析为 Kubernetes 集群服务的 IP 地址
    • prometheus,提供 Prometheus 的 Metrics 接口
    • proxy,不在集群域内的查询转到指定解析器
    • cache,启用缓存
    • loop,检测死循环,并中断
    • reload,自动加载 Corefile,热更新
    • loadbalance,DNS 负载均衡器

    2.3 集群 ConfigMap 配置

    • 查看 CoreDNS 的服务:
    kubectl -n kube-system get svc coredns
    
    coredns                            ClusterIP   10.233.0.3      <none>        53/UDP,53/TCP,9153/TCP   5h
    
    • 查看 CoreDNS 的配置
    kubectl -n kube-system get cm  coredns -o yaml
    
    apiVersion: v1
    data:
      Corefile: |
        .:53 {
            errors
            health
            ready
            kubernetes cluster.local in-addr.arpa ip6.arpa {
              pods insecure
              upstream /etc/resolv.conf
              fallthrough in-addr.arpa ip6.arpa
            }
            prometheus :9153
            forward . /etc/resolv.conf {
              prefer_udp
            }
            cache 30
            loop
            reload
            loadbalance
        }
    ...
    

    DNS 的默认端口是 53 。cluster.local 、 in-addr.arpa 、 ip6.arpa 格式的域名将被解析为 Kubernetes 的内部 IP 地址。

    3. NodelocalDNS

    3.1 简介

    为了避免 Pod 进行 DNS 解析时,频繁查询 CoreDNS ,NodelocalDNS 在每个节点上都以 DaemonSet 运行 DNS 缓存以提高集群性能。

    NodelocalDNS 的原理是,运行一个 hostNetwork 网络模式的 Pod,创建一个网卡绑定本地 DNS 的 IP 地址。节点上的 Pod 请求 DNS 解析时,将被拦截到 NodelocaDNS 。NodelocalDNS 通过取缓存或向上游请求 DNS ,完成解析过程。

    3.2 集群 ConfigMap 配置

    • 查看 NodelocalDNS 服务
    kubectl -n kube-system get ds nodelocaldns
    
    nodelocaldns   1         1         1       1            1           <none>                        5h
    
    • 查看 NodelocalDNS 配置
    kubectl -n kube-system get cm nodelocaldns -o yaml
    
    apiVersion: v1
    data:
      Corefile: |
        cluster.local:53 {
            errors
            cache {
                success 9984 30
                denial 9984 5
            }
            reload
            loop
            bind 169.254.25.10
            forward . 10.233.0.3 {
                force_tcp
            }
            prometheus :9253
            health 169.254.25.10:9254
        }
        in-addr.arpa:53 {
            errors
            cache 30
            reload
            loop
            bind 169.254.25.10
            forward . 10.233.0.3 {
                force_tcp
            }
            prometheus :9253
        }
        ip6.arpa:53 {
            errors
            cache 30
            reload
            loop
            bind 169.254.25.10
            forward . 10.233.0.3 {
                force_tcp
            }
            prometheus :9253
        }
        .:53 {
            errors
            cache 30
            reload
            loop
            bind 169.254.25.10
            forward . /etc/resolv.conf
            prometheus :9253
        }
    ...
    

    同样使用 53 端口提供 DNS 服务,但是根据不同的域名,NodelocalDNS 提供了不同的解析策略。 cluster.local、in-addr.arpa、ip6.arpa 格式的域名从 CoreDNS 解析后缓存到本地,其他则使用节点的 DNS 解析后缓存。

    4. Kubernetes Pod 中的 DNS 解析

    • 创建测试用的 Pod
    cat > busybox.yaml <<-EOF
    apiVersion: v1
    kind: Pod
    metadata:
      name: busybox
      namespace: default
    spec:
      containers:
      - name: busybox
        image: busybox:1.28.4
        command:
          - sleep
          - "3600"
        imagePullPolicy: IfNotPresent
      restartPolicy: Always
    EOF
    
    kubectl apply -f busybox.yaml
    
    • 查看 DNS 解析配置
    kubectl exec busybox cat /etc/resolv.conf
    
    nameserver 169.254.25.10
    search default.svc.cluster.local svc.cluster.local cluster.local
    options ndots:5
    
    • 解析正常的内部服务
    kubectl exec -ti busybox -- nslookup kubernetes.default
    
    Server:    169.254.25.10
    Address 1: 169.254.25.10
    
    Name:      kubernetes.default
    Address 1: 10.233.0.1 kubernetes.default.svc.cluster.local
    

    解析链路:nodelocaldns -> 缓存 -> coredns -> 返回 IP

    其中涉及 search 添加域名后缀的逻辑,在此不再表述。

    • 解析不存在的服务
    kubectl exec -ti busybox -- nslookup a.b
    
    Server:    169.254.25.10
    Address 1: 169.254.25.10
    
    nslookup: can't resolve 'a.b'
    

    解析链路:nodelocaldns -> 节点配置的 DNS -> 未找到

    • 解析正常的外部服务
    kubectl exec -ti busybox -- nslookup www.chenshaowen.com
    
    Server:    169.254.25.10
    Address 1: 169.254.25.10
    
    Name:      www.chenshaowen.com
    Address 1: 163.181.33.208
    

    解析逻辑:nodelocaldns -> 节点配置的 DNS -> 返回 IP

    5. ExternalName - CNAME 解析

    ExternalName Service 是 Service 的一个特例,没有选择器,可以用于给外部服务取一个内部别名。

    • 创建 ExternalName Service
    cat > externalname.yaml <<-EOF
    apiVersion: v1
    kind: Service
    metadata:
      name: chenshaowen
      namespace: default
    spec:
      type: ExternalName
      externalName: www.chenshaowen.com
    EOF
    
    kubectl apply -f externalname.yaml
    
    • 测试访问内部服务
    kubectl exec -ti busybox -- nslookup chenshaowen.default
    
    Server:    169.254.25.10
    Address 1: 169.254.25.10
    
    Name:      chenshaowen.default
    Address 1: 58.215.145.110
    

    chenshaowen.default 将会被映射到 www.chenshaowen.com ,这是通过 DNS 的 CNAME 记录实现的。

    6. 参考