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 (
ConfigMap
andDeployment
) 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
Corefile
directive specified here (c ) cidrs 10.3.0.0/24
tells 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 stdout
from 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 -f
from the example above). And after applying this configuration, you will still need to remove it ReplicationController
from 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:
- “ What is a service mesh and why do I need it [for a cloud application with microservices]? " (On the example of linkerd - another project in CNCF) ;
- “ Container Networking Interface (CNI) - the network interface and standard for Linux containers ” (another network project in CNCF) ;
- “ Our experience with Kubernetes in small projects (review and video report) ” (about the architecture and device of Kubernetes in general) .