使用dnsmasq搭建更加灵活的 k8s DNS解析服务

原因

k8s 集群中可以通过 coredns 进行解析,但没有 dnsmasq 丰富的解析和转发能力。

比如使用 coredns 做一个自定义域名泛解析

.:53 {
    errors
    health
    ready
    template IN A domain.local {
        answer "{{ .Name }} 60 IN A 192.168.23.7"
        fallthrough
    }
    forward . 8.8.8.8
    cache 30
    loop
    reload
    loadbalance
}

比如要解析多个 hosts

.:53 {
    errors
    health
    ready
    hosts /etc/coredns/NodeHosts {
      ttl 60
      reload 15s
      fallthrough
    }
    forward . 8.8.8.8
    cache 30
    loop
    reload
    loadbalance
}

再到 /etc/coredns/NodeHosts 中配置多行记录。

以上是 hosts 插件和 template 的用法,hosts插件在一个 server 中只能用一次,不够灵活。

[ERROR] plugin/reload: Corefile changed but reload failed: starting with listener file descriptors: plugin/hosts: this plugin can only be used once per Server Block

官方的自定义 DNS 服务

https://kubernetes.io/zh-cn/docs/tasks/administer-cluster/dns-custom-nameservers/

可行性

coredns 中可以指定一条 forward 指令,那我们可以将 Corsdns 中未命中的域转发到上游DNS,并返回上游 DNS 的结果。

这里的上游DNS,用 DnsMasq 来搭建。

DnsMasq 简单教程

https://blog.newnius.com/deploy-your-private-dns-resolver-using-dnsmasq.html

构建镜像

dnsmasq 版本太老,没有官方的镜像,所以我一般自己构建镜像,原因主要是怕出现像 nodejs 的组件被加料的情况出现

dockerfile 灰常简单

FROM alpine:3.16
RUN apk add dnsmasq
EXPOSE 53
CMD ["/usr/sbin/dnsmasq", "-k"]

然后构建镜像

docker build . -t hub.4wei.cn/dnsmasq/dnsmasq-alpine:3.16

服务部署

---
apiVersion: v1
data:
  dnsmasq-resolv.conf: |-
    nameserver 1.2.4.8
    nameserver 114.114.114.114
  dnsmasq.conf: |-
    # 表示dnsmasq 会从这个指定的文件中寻找上游dns服务器。格式参考/etc/resolv.conf
    resolv-file=/etc/dnsmasq-resolv.conf
    strict-order
    no-hosts

    # /etc/dnsmasq.hosts中写要解析的域名
    addn-hosts=/etc/dnsmasq.hosts

    #不同的网站使用不同的DNS
    server=/cn/114.114.114.114
    server=/com/8.8.8.8

    #手动指定解析记录
    address=/t66y.local/10.27.193.192
    address=/4wei.local/10.27.193.192

kind: ConfigMap
metadata:
  annotations: {}
  labels: {}
  name: dnsmasq
  namespace: dnsmasq
---
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations: {}
  labels:
    k8s.kuboard.cn/name: dnsmasq
  name: dnsmasq
  namespace: dnsmasq
spec:
  replicas: 1
  selector:
    matchLabels:
      k8s.kuboard.cn/name: dnsmasq
  template:
    metadata:
      labels:
        k8s.kuboard.cn/name: dnsmasq
    spec:
      containers:
        - args:
            - '-k'
          command:
            - dnsmasq
          image: 'hub.4wei.cn/dnsmasq/dnsmasq-alpine:3.16'
          imagePullPolicy: IfNotPresent
          name: dnsmasq
          ports:
            - containerPort: 53
              name: tcp
              protocol: TCP
            - containerPort: 53
              name: udp
              protocol: UDP
          volumeMounts:
            - mountPath: /etc/dnsmasq.conf
              name: volume-configmap
              subPath: dnsmasq.conf
            - mountPath: /etc/dnsmasq-resolv.conf
              name: volume-configmap
              subPath: dnsmasq-resolv.conf
      imagePullSecrets:
        - name: default-secret
      volumes:
        - configMap:
            items: []
            name: dnsmasq
          name: volume-configmap
---
apiVersion: v1
kind: Service
metadata:
  annotations: {}
  labels:
    k8s.kuboard.cn/name: dnsmasq
  name: dnsmasq
  namespace: dnsmasq
spec:
  externalIPs:
    - 10.10.10.10
  ports:
    - name: dnsmasq
      port: 53
      protocol: UDP
  selector:
    k8s.kuboard.cn/name: dnsmasq
  type: ClusterIP

k8s CoreDNS 修改

添加一行 forward 参数,指定到 clusterIP

.:5353 {
    bind {$POD_IP}
    cache 30
    errors
    health {$POD_IP}:8080
    kubernetes cluster.local in-addr.arpa ip6.arpa {
      pods insecure
      fallthrough in-addr.arpa ip6.arpa
    }
    loadbalance round_robin
    prometheus {$POD_IP}:9153
    forward . 10.10.10.10
    reload
}

性能测试

docker run redsift/dnstrace -n 10000 -c 20 --server 10.10.10.10 --recurse baidu.com