CoreDNS - DNS server for the cloud native world and Service Discovery for Kubernetes



    Two weeks ago, the CoreNS Open Source project was marked with its next release - 008 . The authors call their product “a DNS server, consisting of a chain of intermediate components (middleware), each of which implements some kind of DNS capability”. What is noteworthy, they have already managed to achieve the inclusion of CoreDNS in the list of official projects of the CNCF (Cloud Native Computing Foundation) organization , having joined the ranks of Kubernetes, Prometheus, CNI , containerd , rkt and other developments actively used in the world of containers, microservices and "native cloud applications" ( cloud native ).

    How did CoreDNS come about, what is it for, and how can it be used?

    Introducing CoreDNS


    CoreDNS is a DNS server that appeared in early 2016 (under the free Apache License v2) as a fork of the fast Caddy web server written in Go . The HTTP server itself in Caddy is implemented by the httpserver package, the two most important types of which are Handler (the function of processing the HTTP request) and Middleware (an intermediate layer that attaches one Handler to another - this forms a chain of handlers). This approach with a chain of functions was adopted in CoreDNS, which allowed developers to describe their solution very succinctly: “CoreDNS is a DNS server that links middleware”.

    The second fundamental detail in the CoreDNS project is its succession from SkyDNS- service discovery, built on top of the NoSQL repository etcd and using DNS queries (specially generated SRV records) to discover available services. In fact, SkyDNS was an easy layer between etcd, where information about services was actually stored, and the DNS server through which this information became “publicly” available. Apparently, the active development of SkyDNS stopped about 7 months ago (with the addition of support for etcd 3), while commits in the CoreDNS code base can be observed almost daily.

    CoreDNS did not limit itself to etcd as the only backend for data displayed in DNS records. Kubernetes is still supported at the moment (which, however, as you know, also uses etcd ...), which allows authors to officially position CoreDNS as a replacement for kube-dns . (For more details on how to try this replacement in action, read below.)

    Note : The full history of the relationship of the mentioned DNS solutions: SkyDNS, CoreDNS, kube-dns is intertwined even more closely than it might seem. The fact is that, firstly, kube-dns uses SkyDNS libraries to service DNS queries received in Kubernetes pods and services. And secondly, the main developer of CoreDNS is the original author of SkyDNS - Miek Gieben - SRE from Google, who is also known in the Go community thanks to its DNS library . All this allows us to see in CoreDNS not a “competitor” kube-dns, but rather its evolution.

    CoreDNS Features


    This server allows you to receive requests over UDP / TCP, TLS (RFC 7858) and gRPC. And it functions as:

    • Primary DNS server that transfers data about a zone from a file (DNS and DNSSEC) and allows transferring a zone;
    • Secondary DNS server (only AXFR supported);
    • proxy (redirects requests to other servers).

    Among other significant features of CoreDNS:

    • caching query results;
    • rewrite for queries (qtype, qclass, qname);
    • request balancing;
    • health checking of end nodes;
    • metrics in Prometheus;
    • query and error logging;
    • profiling.

    All of these functions (including even the primary and secondary server modes) are implemented by various modules, or rather (in Caddy / CoreDNS terminology) - middleware. Obviously, the possibilities are easy to expand with the creation of new middleware.


    The architecture of CoreDNS, where each middleware

    John Belamaric, an architect at Infoblox and one of the leading developers of CoreDNS, is responsible for each function , considers this particular feature to be the main one in the project:
    There are many different DNS servers; there are even other DNS-based service discovery solutions. But one of the core strengths of CoreDNS is how extensible and flexible this solution is. This makes it easy to adapt to the dynamic, often changing world of cloud-native.

    Why have CoreDNS taken custody of CNCF?


    Here is how this event is explained on the project website:
    Our goal is to make CoreDNS a DNS server and a service discovery solution for cloud-native. CNCF as an organization focuses on improving architectures for cloud-native. Thus, for us, this is a wonderful coincidence [of the pursued goals]. Service discovery is a key component in CNCF's native cloud space, and CoreDNS excels in this role.

    A statement on behalf of CNCF itself was made by Chris Aniszczyk (COO in CNCF), noting that “CoreDNS provides important naming services and integrates efficiently with many other projects in the cloud-native category in CNCF,” and “CoreDNS is an attractive option for discovery services at Kubernetes. "

    Note : At the moment, CoreDNS has an inception status among CNCF projects, which means that the technical committee needs to review this status after a year and decide on its future fate: remove, extend, upgrade to incubating or graduated.

    Let's move from theory to practice.

    CoreDNS as Service Discovery for Kubernetes


    As mentioned in the note above, CoreDNS developers do not just offer an alternative for kube-dns - they interact with the Kubernetes community to make the result of their work useful to everyone. A good example is their initiative to create a specification describing DNS-based Service Discovery for Kubernetes. It appeared in order to "guarantee the compatibility of the existing implementation in Kube-DNS and the new one in CoreDNS." Version 1.0.0 of this specification basically copies the behavior of kube-dns - CoreDNS releases 005 and higher correspond to it (offering, in addition, additional features when compared with kube-dns).

    To start using CoreDNS as a Service Discovery in Kubernetes, developers prepared a configuration ( ConfigMapandDeployment) and even the deploy.sh Bash script for a quick deployment. They took care of an example of how to use it (all further listings are taken from it) :

    $ ./deploy.sh 10.3.0.0/24 cluster.local

    • 10.3.0.0/24 - CIDRs of services;
    • cluster.local(optional) - the domain name of the cluster.

    The result of the script will be such a manifest:

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: coredns
      namespace: kube-system
    data:
      Corefile: |
        .:53 {
            errors
            log stdout
            health
            kubernetes cluster.local {
              cidrs 10.3.0.0/24
            }
            proxy . /etc/resolv.conf
            cache 30
        }
    ---
    apiVersion: extensions/v1beta1
    kind: Deployment
    metadata:
      name: coredns
      namespace: kube-system
      labels:
        k8s-app: coredns
        kubernetes.io/cluster-service: "true"
        kubernetes.io/name: "CoreDNS"
    spec:
      replicas: 1
      selector:
        matchLabels:
          k8s-app: coredns
      template:
        metadata:
          labels:
            k8s-app: coredns
          annotations:
            scheduler.alpha.kubernetes.io/critical-pod: ''
            scheduler.alpha.kubernetes.io/tolerations: '[{"key":"CriticalAddonsOnly", "operator":"Exists"}]'
        spec:
          containers:
          - name: coredns
            image: coredns/coredns:latest
            imagePullPolicy: Always
            args: [ "-conf", "/etc/coredns/Corefile" ]
            volumeMounts:
            - name: config-volume
              mountPath: /etc/coredns
            ports:
            - containerPort: 53
              name: dns
              protocol: UDP
            - containerPort: 53
              name: dns-tcp
              protocol: TCP
            livenessProbe:
              httpGet:
                path: /health
                port: 8080
                scheme: HTTP
              initialDelaySeconds: 60
              timeoutSeconds: 5
              successThreshold: 1
              failureThreshold: 5
          dnsPolicy: Default
          volumes:
            - name: config-volume
              configMap:
                name: coredns
                items:
                - key: Corefile
                  path: Corefile
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: kube-dns
      namespace: kube-system
      labels:
        k8s-app: coredns
        kubernetes.io/cluster-service: "true"
        kubernetes.io/name: "CoreDNS"
    spec:
      selector:
        k8s-app: coredns
      clusterIP: 10.3.0.10
      ports:
      - name: dns
        port: 53
        protocol: UDP
      - name: dns-tcp
        port: 53
        protocol: TCP

    The Corefiledirective specified here (c ) cidrs 10.3.0.0/24tells Kubernetes middleware from CoreDNS that it is necessary to serve PTR requests for the reverse zone 0.3.10.in-addr.arpa.

    It remains to pass the result to execution in Kubernetes:

    $ ./deploy.sh 10.3.0.0/24 | kubectl apply -f -
    configmap "coredns" created
    deployment "coredns" created
    service "kube-dns" configured

    ... and make sure the new DNS server really works:

    $ kubectl run -it --rm --restart=Never --image=infoblox/dnstools:latest dnstools
    Waiting for pod default/dnstools to be running, status is Pending, pod ready: false
    If you don't see a command prompt, try pressing enter.
    # host kubernetes
    kubernetes.default.svc.cluster.local has address 10.3.0.1
    # host kube-dns.kube-system
    kube-dns.kube-system.svc.cluster.local has address 10.3.0.10
    # host 10.3.0.1
    1.0.3.10.in-addr.arpa domain name pointer kubernetes.default.svc.cluster.local.
    # host 10.3.0.10
    10.0.3.10.in-addr.arpa domain name pointer kube-dns.kube-system.svc.cluster.local.

    How does it look on the side of CoreDNS itself? Here is an example for the case of a cluster of two CoreDNS replicas between which DNS query balancing is done:
    # найдем поды со службой CoreDNS
    $ kubectl get --namespace kube-system pods
    NAME                                    READY     STATUS    RESTARTS   AGE
    coredns-3558181428-0zhnh                1/1       Running   0          2m
    coredns-3558181428-xri9i                1/1       Running   0          2m
    heapster-v1.2.0-4088228293-a8gkc        2/2       Running   0          126d
    kube-apiserver-10.222.243.77            1/1       Running   2          126d
    kube-controller-manager-10.222.243.77   1/1       Running   2          126d
    kube-proxy-10.222.243.77                1/1       Running   2          126d
    kube-proxy-10.222.243.78                1/1       Running   0          126d
    kube-scheduler-10.222.243.77            1/1       Running   2          126d
    kubernetes-dashboard-v1.4.1-gi2xr       1/1       Running   0          24d
    tiller-deploy-3299276078-e8phb          1/1       Running   0          24d
    # посмотрим на логи первого
    $ kubectl logs --namespace kube-system coredns-3558181428-0zhnh
    2017/02/23 14:48:29 [INFO] Kubernetes middleware configured without a label selector. No label-based filtering will be performed.
    .:53
    2017/02/23 14:48:29 [INFO] CoreDNS-005
    CoreDNS-005
    10.2.6.127 - [23/Feb/2017:14:49:44 +0000] "AAAA IN kubernetes.default.svc.cluster.local. udp 54 false 512" NOERROR 107 544.128µs
    10.2.6.127 - [23/Feb/2017:14:49:44 +0000] "MX IN kubernetes.default.svc.cluster.local. udp 54 false 512" NOERROR 107 7.576897ms
    10.2.6.127 - [23/Feb/2017:14:49:52 +0000] "A IN kube-dns.kube-system.default.svc.cluster.local. udp 64 false 512" NXDOMAIN 117 471.176µs
    23/Feb/2017:14:49:52 +0000 [ERROR 0 kube-dns.kube-system.default.svc.cluster.local. A] no items found
    10.2.6.127 - [23/Feb/2017:14:50:00 +0000] "PTR IN 10.0.3.10.in-addr.arpa. udp 40 false 512" NOERROR 92 752.956µs
    # посмотрим на логи второго
    $ kubectl logs --namespace kube-system coredns-3558181428-xri9i
    2017/02/23 14:48:29 [INFO] Kubernetes middleware configured without a label selector. No label-based filtering will be performed.
    .:53
    2017/02/23 14:48:29 [INFO] CoreDNS-005
    CoreDNS-005
    10.2.6.127 - [23/Feb/2017:14:49:44 +0000] "A IN kubernetes.default.svc.cluster.local. udp 54 false 512" NOERROR 70 1.10732ms
    10.2.6.127 - [23/Feb/2017:14:49:52 +0000] "A IN kube-dns.kube-system.svc.cluster.local. udp 56 false 512" NOERROR 72 409.74µs
    10.2.6.127 - [23/Feb/2017:14:49:52 +0000] "AAAA IN kube-dns.kube-system.svc.cluster.local. udp 56 false 512" NOERROR 109 210.817µs
    10.2.6.127 - [23/Feb/2017:14:49:52 +0000] "MX IN kube-dns.kube-system.svc.cluster.local. udp 56 false 512" NOERROR 109 796.703µs
    10.2.6.127 - [23/Feb/2017:14:49:56 +0000] "PTR IN 1.0.3.10.in-addr.arpa. udp 39 false 512" NOERROR 89 694.649µs

    To disable the logging of all DNS queries (high disk load during real use), it is enough to remove the line log stdoutfrom Corefile.

    Important : the authors warn that if you use the Google Container Engine (GKE), the described example will not work due to additional processes that do not allow replacing the standard kube-dns. There is a way to solve this problem, but officially it has not yet been documented / announced by them.

    CoreDNS for Minikube


    In case of local launch of Kubernetes with Minikube, there is a similar problem: the addon manager used in it periodically checks (and maintains) the configuration status of all installed add-ons, one of which is kube-dns. To prevent this manager from interfering with CoreDNS, there is a simple solution .

    It consists in changing the list of installed add-ons for minikube:

    $ minikube addons list
    - dashboard: enabled
    - default-storageclass: enabled
    - kube-dns: enabled
    - heapster: disabled
    - ingress: disabled
    - registry-creds: disabled
    - addon-manager: enabled
    $ minikube addons disable kube-dns
    kube-dns was successfully disabled
    $ minikube addons list
    - heapster: disabled
    - ingress: disabled
    - registry-creds: disabled
    - addon-manager: enabled
    - dashboard: enabled
    - default-storageclass: enabled
    - kube-dns: disabled

    You must complete this configuration before applying the CoreDNS configuration in Kubernetes (i.e., before starting kubectl apply -ffrom the example above). And after applying this configuration, you will still need to remove it ReplicationControllerfrom kube-dns, since disabling the add-on does not do this automatically:

    $ kubectl get -n kube-system pods
    NAME                          READY     STATUS    RESTARTS   AGE
    coredns-980047985-g2748       1/1       Running   1          36m
    kube-addon-manager-minikube   1/1       Running   0          9d
    kube-dns-v20-qzvr2            3/3       Running   0          1m
    kubernetes-dashboard-ks1jp    1/1       Running   0          9d
    $ kubectl delete -n kube-system rc kube-dns-v20
    replicationcontroller "kube-dns-v20" deleted

    Conclusion


    CoreDNS is an interesting project whose real prospects are given by its convincing legacy (experience since SkyDNS), close cooperation with the core community (Kubernetes and Go), recognition in CNCF and, of course, a modern approach to implementation.

    Also read on our blog about related topics:


    Also popular now: