Service discovery is an important feature of K8s, and there are two ways to do this: either by injecting the svc ClusterIP into the pod as an environment variable, or by using DNS, which has replaced kube dns as the built-in DNS server since version 1.13. In this article, we will briefly analyze coreDNS.
K8s DNS Policies
There are four types of DNS policies for Pods in Kubernetes.
- Default: Pod inherits the DNS configuration on the host where it resides.
- ClusterFirst: the default setting for K8s; first query in the coreDNS of K8s cluster configuration, and then query in the upstream nameserver of the inherited host if you can’t find it.
- ClusterFirstWithHostNet: for Pods with network configuration as hostNetwork, the DNS configuration rules are the same as ClusterFirst.
- None: Ignore the DNS configuration of the K8s environment and only recognize the Pod’s dnsConfig settings.
Here’s a quick overview of how coreDNS resolves domain names.
resolv.conf file analysis
When deploying a pod, if it uses the DNS of the K8s cluster, the kubelet will initialize its DNS resolution configuration to that of the cluster when it starts the pause container.
For example, if I create a deployment called my-nginx
, the resolv.conf
file in the pod is as follows.
When pods in the cluster access each other with svc name, the domain name is resolved according to the DNS configuration in the resolv.conf
file, and the following is a breakdown of the process.
The process of domain name resolution
The pod resolv.conf file has three main sections, nameserver, search and option, which can be specified by K8s or customized by the pod.spec.dnsConfig field.
nameserver
The first line of the resolv.conf
file, nameserver, specifies the IP of the DNS service, in this case the clusterIP of coreDNS.
This means that all domain names resolve through the virtual IP 10.96.0.10
of coreDNS, whether they are internal to Kubernetes or external to it.
search domain
The second line of the resolv.conf
file specifies the DNS search domain. When resolving a domain name, the domain names to be accessed are brought into the search domain in order to perform a DNS lookup.
For example, if I want to access a service with the domain name your-nginx
in the pod, the order of the DNS lookups will be as follows.
|
|
until it is checked.
options
The third line of the resolv.conf
file specifies additional items, most often dnots
. dnots
means that if the query domain contains a dot “.” The default configuration in K8s is 5.
In other words, if I visit a.b.c.e.f.g
, then the domain name lookup order is as follows.
|
|
If I visit a.b.c.e
, then the domain lookup order is as follows.
|
|
Communication between pods
After understanding the domain resolution process, let’s take a look at the communication between pods.
Access via svc
As we all know, in K8s, when pods access each other via svc, they go through DNS domain name resolution and then get the ip communication. The full name of K8s domain is "<service-name>. <namespace>.svc.cluster.local"
, and we usually just use svc name as the domain name to access the pod, which is not hard to understand by the domain name resolution process above.
Let’s look at an example. There are two deployments, one called busybox
under the namespace default
, and one called your-nginx
under the namespace hdls
, with the same svc name. We try to access your-nginx
in busybox
.
|
|
As you can see, when accessing directly with your-nginx
, it prompts bad address
, which means that the domain name is wrong, because all the search domains under different namespace have been searched and still cannot be found; when accessing with your-nginx.hdls
, it resolves to 10.100.3.148
, which is the ClusterIP of your-nginx
.
So, when pods under different namespace are accessed via svc, you need to add . <namespace>
.
Hostname and subdomain of pod
In K8s, if you don’t specify the hostname of a pod, it defaults to pod.metadata.name, which can be customized via the spec.hostname field; you can also set the subdomain of a pod via the spec.subdomain field. For example, the following example.
|
|
You can check the hostname and hosts file of this pod.
|
|
Access this pod in the busybox container.
|
|
As you can see, when accessing domain-test.subdomain-test
, it resolves to 10.244.1.253
, which is the pod ip of nginx, not the clusterIP; while when accessing subdomain-test
, it resolves to 10.108.213.70
, which is the clusterIP, which is the normal svc name route.
coreDNS Corefile file
CoreDNS implements application plugging, allowing users to select the required plugins to compile into an executable; the CoreDNS configuration file is in the form of a Corefile, here is an example of a coreDNS configMap.
|
|
Corefile file analysis
Part 1.
The domain names that specify the cluster.local suffix are all internal kubernetes domains. coredns listens to service changes to maintain domain relationships, so the cluster.local related domains are resolved here.
Part 2.
|
|
proxy means no record found in coredns, then it goes to the nameserver in /etc/resolv.conf to request resolution, while /etc/resolv.conf in the coredns container is inherited from the host. The practical effect is that if the domain name is not internal to k8s, it will go to the default dns server to request resolution and return it to the coredns requester.
Third part.
prometheus
: CoreDNS is monitored at: http://localhost:9153/metrics
, satisfying the Prometheus format.
cache
: allows caching
loop
: detects a simple forwarding loop and stops the CoreDNS process if a loop is found.
reload
: allows the Corefile configuration to be updated automatically. The changes take effect two minutes after the ConfigMap is changed
loadbalance
: This is a cyclic DNS load balancer that randomizes the order of A, AAAA and MX records in the answer.
Specifying hosts
Sometimes the service of a domain is outside the cluster and I want to access it inside the cluster, we can specify the hosts in the corefile to achieve this. This is done by adding the domain name and the corresponding ip to the corefile as a hosts plugin, as follows.
Where 10.244.1.245
is the pod ip of your-nginx
, and then the service other-company.com
is accessed from the busybox pod above, as follows.