How Kubernetes (k8s) uses kube-dns to achieve service discovery

Outline:

  • How to discover services in Kubernetes

  • How to discover services provided by pods
  • How to use Service to discover services
  • How to discover services using kube-dns
  • kube-dns principle

  • composition
  • Domain name format
  • configure

Note: This sharing content is based on Kubernetes version 1.2!

Let's start with a simple example.

1. How to discover services in Kubernetes

◆ Discover the services provided by the Pod

First create an Nginx Deployment using the nginx-deployment.yaml file, as shown in the figure:

First create two Pods running the Nginx service:

20161014201039

Use kubectl create -f nginx-deployment.yaml command to create, so you can get two pods running nginx service. After the Pods are running, check their IPs and access the Nginx service through the podIP and containerPort in the k8s cluster:

Get Pod IP:

20161014201048

Access the Nginx service within the cluster:

20161014201057

Seeing this, I believe many people will have the following questions:

  1. Getting the podIP every time you receive it is too much. You can’t manually change the program or configuration every time to access the service. How do you know the podIP in advance?
  2. Pods may be rebuilt during operation. What if the IP changes?
  3. How to achieve load balancing among multiple Pods?

These problems can be solved by using k8s Service.

◆ Use Service to discover services

Let's create a Service for two Nginx Pods. Use the nginx-service.yaml file to create, the file content is as follows:

20161014201106

After creation, you still need to obtain the Cluster-IP of the Service, and then use the Port to access the Nginx service.

Service可以将pod  IP封装起来,即使Pod发生重建,依然可以通过Service来访问Pod提供的服务。此外,Service还解决了负载均衡的问题,大家可以多访问几次Service,然后通过kubectl logs <Pod Name>来查看两个Nginx Pod的访问日志来确认。

获取IP:

20161014201113

在集群内访问Service:

20161014201119

虽然Service解决了Pod的服务发现和负载均衡问题,但存在着类似的问题:不提前知道Service的IP,还是需要改程序或配置啊。看到这里有没有感觉身体被掏空?

接下来聊聊kube-dns是如何解决上面这个问题的。

◆   使用kube-dns发现服务

kube-dns可以解决Service的发现问题,k8s将Service的名称当做域名注册到kube-dns中,通过Service的名称就可以访问其提供的服务。

可能有人会问如果集群中没有部署kube-dns怎么办?没关系,实际上kube-dns插件只是运行在kube-system命名空间下的Pod,完全可以手动创建它。可以在k8s源码(v1.2)的cluster/addons/dns目录下找到两个模板(skydns-rc.yaml.in和skydns-svc.yaml.in)来创建,为大家准备的完整示例文件会在分享结束后提供获取方式,PPT中只截取了部分内容。

通过skydns-rc.yaml文件创建kube-dns Pod,其中包含了四个containers,这里开始简单过一下文件的主要部分,稍后做详细介绍。

第一部分可以看到kube-dns使用了RC来管理Pod,可以提供最基本的故障重启功能。

创建kube-dns Pod,其中包含了4个containers

20161014201128

接下来是第一个容器  etcd  ,它的用途是保存DNS规则。

20161014201134

第二个容器  kube2sky ,作用是写入DNS规则。

20161014201141

第三个容器是  skydns ,提供DNS解析服务。

20161014201148

最后一个容器是  healthz ,提供健康检查功能。

20161014201154

有了Pod之后,还需要创建一个Service以便集群中的其他Pod访问DNS查询服务。通过skydns-svc.yaml创建Service,内容如下:

20161014201201

创建完kube-dns Pod和Service,并且Pod运行后,便可以访问kube-dns服务。

下面创建一个Pod,并在该Pod中访问Nginx服务:

创建之后等待kube-dns处于运行状态

20161014201212

再新建一个Pod,通过其访问Nginx服务

20161014201220

在curl-util Pod中通过Service名称访问my-nginx Service:

20161014201227

只要知道需要的服务名称就可以访问,使用kube-dns发现服务就是那么简单。

虽然领略了使用kube-dns发现服务的便利性,但相信有很多人也是一头雾水:kube-dns到底怎么工作的?在集群中启用了kube-dns插件,怎么就能通过名称访问Service了呢?

2、kube-dns原理

◆   Kube-dns组成

之前已经了解到kube-dns是由四个容器组成的,它们扮演的角色可以通过下面这张图来理解。

20161014201235

其中:

  • SkyDNS是用于服务发现的开源框架,构建于etcd之上。作用是为kubernetes集群中的Pod提供DNS查询接口。项目托管于https://github.com/skynetservices/skydns
  • etcd是一种开源的分布式key-value存储,其功能与ZooKeeper类似。在kube-dns中的作用为存储SkyDNS需要的各种数据,写入方为kube2sky,读取方为SkyDNS。项目托管于https://github.com/coreos/etcd。
  • kube2sky是k8s实现的一个适配程序,它通过名为kubernetes的Service(通过kubectl get svc可以查看到该Service,由集群自动创建)调用k8s的list和watch API来监听k8s Service资源的变更,从而修改etcd中的SkyDNS记录。代码可以在k8s源码(v1.2)的cluster/addons/dns/kube2sky/目录中找到。
  • exec-healthz是k8s提供的一种辅助容器,多用于side car模式中。它的原理是定期执行指定的Linux指令,从而判断当前Pod中关键容器的健康状态。在kube-dns中的作用就是通过nslookup指令检查DNS查询服务的健康状态,k8s livenessProbe通过访问exec-healthz提供的Http API了解健康状态,并在出现故障时重启容器。其源码位于https://github.com/kubernetes/contrib/tree/master/exec-healthz。
  • 从图中可以发现,Pod查询DNS是通过ServiceName.Namespace子域名来查询的,但在之前的示例中只用了Service名称,什么原理呢?其实当我们只使用Service名称时会默认Namespace为default,而上面示例中的my-nginx Service就是在default Namespace中,因此是可以正常运行的。关于这一点,后续再深入介绍。
  • skydns-rc.yaml中可以发现livenessProbe是设置在kube2sky容器中的,其意图应该是希望通过重启kube2sky来重新写入DNS规则。

◆   域名格式

接下来了解一下kube-dns支持的域名格式,具体为:<service_name>.<namespace>.svc.<cluster_domain>。

其中cluster_domain可以使用kubelet的–cluster-domain=SomeDomain参数进行设置,同时也要保证kube2sky容器的启动参数中–domain参数设置了相同的值。通常设置为cluster.local。那么之前示例中的my-nginx Service对应的完整域名就是my-nginx.default.svc.cluster.local。看到这里,相信很多人会有疑问,既然完整域名是这样的,那为什么在Pod中只通过Service名称和Namespace就能访问Service呢?下面来解释其中原因。

3、配置

◆   域名解析配置

为了在Pod中调用其他Service,kubelet会自动在容器中创建域名解析配置(/etc/resolv.conf),内容为:

20161014201244

感兴趣的可以在网上查找一些resolv.conf的资料来了解具体的含义。之所以能够通过Service名称和Namespace就能访问Service,就是因为search配置的规则。在解析域名时会自动拼接成完整域名去查询DNS。

刚才提到的kubelet –cluster-domain参数与search的具体配置是相对应的。而kube2sky容器的–domain参数影响的是写入到etcd中的域名,kube2sky会获取Service的名称和Namespace,并使用–domain参数拼接完整域名。这也就是让两个参数保持一致的原因。

◆   NS相关配置

kube-dns可以让Pod发现其他Service,那Pod又是如何自动发现kube-dns的呢?在上一节中的/etc/resolv.conf中可以看到nameserver,这个配置就会告诉Pod去哪访问域名解析服务器。

20161014201251

Correspondingly, you can see that spec.clusterIP is configured with the same value in the skydns-svc.yaml mentioned earlier. Generally speaking, creating a Service does not need to specify the clusterIP, k8s will automatically assign it, but kube-dns is special, you need to specify the clusterIP to make it consistent with the nameserver in /etc/resolv.conf.

Modifying the nameserver configuration also requires modifying two places, one is the –cluster-dns parameter of kubelet, and the other is the clusterIP of kube-dns Service.

4. Summary

Next, re-organize the main content of this article:

  • In a k8s cluster, services run in Pods, and Pod discovery and load balancing between replicas are the problems we face.
  • These two problems can be solved through the Service, but the corresponding IP is also required to access the Service, so the problem discovered by the Service is introduced.
  • Thanks to the kube-dns plugin, we can access the service in the cluster through the domain name, which solves the problem found by the service.
  • In order for the containers in the Pod to use kube-dns to resolve domain names, k8s will modify the container's /etc/resolv.conf configuration.

 

With the guarantee of the above mechanism, it is very convenient to access the corresponding service through the Service name and namespace in the Pod.

 

https://www.kubernetes.org.cn/273.html

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326646242&siteId=291194637