Kubernetes网络自学系列 | 你的名字:通过域名访问服务

Posted COCOgsta

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Kubernetes网络自学系列 | 你的名字:通过域名访问服务相关的知识,希望对你有一定的参考价值。

素材来源:《Kubernetes网络权威指南》

一边学习一边整理内容,并与大家分享,侵权即删,谢谢支持!

附上汇总贴:Kubernetes网络自学系列 | 汇总_COCOgsta的博客-CSDN博客


3.7 你的名字:通过域名访问服务

众所周知,Kubernetes Master存储了所有Service的定义和更新。但是,要与后端Pod通信的客户端Pod在使用Service实现负载均衡时也需要知道这些请求会发送到何处。这些Pod可以将网络信息存储在容器环境变量中,但从长远来看这是不可行的。如果网络详细信息和一组后端Pod在将来发生更改,客户端Pod将无法与它们通信。前文提到过,Kubernetes DNS系统可以解决这个问题,下面我们将详细讨论Kubernetes的DNS。

在一个Kubernetes集群中,DNS服务是非必需的,因此无论是Kube-dns还是CoreDNS,通常以插件(add-on)的方式安装,作为运行在集群上的应用。如果涉及服务发现和域名访问,那么Kubernetes的DNS服务又是必不可少的。

3.7.1 DNS服务基本框架

具体到Kubernetes DNS服务的功能,它是用来解析Kubernetes集群内的Pod和Service域名的,而且一般情况下只供集群内的容器使用,不给外人使用。

有读者可能会好奇地问,Pod到底怎么使用Kubernetes的DNS服务呢?通常,Kubernetes的DNS应用部署好后,会对外暴露一个服务,集群内的容器通过访问该服务的Cluster IP+53端口获得域名解析服务,而这个Service的ClusterIP一般情况下都是固定的。

一般应用程序是无须感知DNS服务器的IP地址的,以Linux系统为例,容器内进程想要获得域名解析服务,只需把DNS Server写入/etc/resolv.conf文件。那么刷新/etc/resolv.conf配置这个动作是谁完成的呢?答案是Kubelet。

原来,当Kubernetes的DNS服务Cluster IP分配后,系统(一般是指安装程序)会给Kubelet配置--cluster-dns=启动参数,DNS服务的IP地址将在用户容器启动时传递,并写入每个容器的/etc/resolv.conf文件。DNS服务IP即上文提到的DNS Service的Cluster IP,可以配置成--cluster-dns=10.0.0.1。

除此之外,Kubelet的--cluster_domain=参数支持配置集群域名后缀,默认是cluster.local。

打开Kubelet配置查看便一目了然:

以上流程是Kubernetes使用集群内DNS Server的基本框架,与具体的DNS Server后端无关,即使后面换成CoreDNS,基本用法也保持一致。

3.7.2 域名解析基本原理

Kubernetes DNS的命名方案也遵循可预测的模式,使各种服务的地址更容易被记住。服务不仅可以通过完全限定域名(FQDN)引用,还可以仅通过服务本身的name引用。目前,Kubernetes DNS加载项支持正向查找(A Record)、端口查找(SRV记录)、反向IP地址查找(PTR记录)及其他功能。

对于Service,Kubernetes DNS服务器会生成三类DNS记录,分别是A记录、SRV记录和CNAME记录。

1.A记录

A记录(A Record)是用于将域或子域指向某个IP地址的DNS记录的最基本类型。记录包括域名、解析它的IP地址和以秒为单位的TTL。TTL代表生存时间,是DNS记录上的一种到期日期。每个TTL都会告诉DNS服务器,它应该在其缓存中保留给定记录多长时间。

Kubernetes为“normal”和“headless”服务分配不同的A Record name。“headless”服务与“normal”服务的不同之处在于它们未分配Cluster IP且不执行负载均衡。

“normal”服务分配一个DNS A Record作为表单your-svc.your-namespace.svc.cluster.local的name(根域名可以在kubelet设置中更改)。此name解析为服务的集群IP。“headless”服务为表单your-svc.your-namespace.svc.cluster.local的name分配一个DNS A Record。与“normal”服务相反,此name解析的是,为服务选择的一组Pod IP。DNS不会自动将此设置解析为特定的IP,因此客户端应该负责集合中进行的负载均衡或循环选择。

A记录与普通Service和headless Service有区别。普通Service的A记录的映射关系是:

每个部分字段的含义是:

· service_name:Service名;

· namespace:Service所在namespace;

· domain:提供的域名后缀,是Kubelet通过--cluster-domain配置的。比如默认的cluster.local。

在Pod中可以通过域名 service name .service namespace.svc.domain访问任何服务,也可以使用缩写service name.service namespace直接访问。如果Pod和Service在同一个namespace中,那么甚至可以直接使用service name访问。

headless Service的A记录的映射关系是:

含义跟前面的一致,本节不再赘述。

一旦启用了DNS,Pod将被分配一个DNS A记录,格式如下所示:

其中pod-ip为Pod的IP地址用-符号隔开,例如Pod IP是1.2.3.4,上面的pod-ip即1-2-3-4,因此对应的域名就是1-2-3-4.default.pod.cluster.local。Pod的A记录其实没什么用,都知道Pod IP了,还用查DNS吗?所以这也是一个即将废弃的特性。

如果在Pod Spec指定hostname和subdomain,那么Kubernetes DNS会额外生成Pod的A记录:

同样,后面那一串子域名pod.cluster.local是Kubelet配置的伪域名。

2.SRV记录

SRV记录是通过描述某些服务协议和地址促进服务发现的。SRV记录通常定义一个符号名称和作为域名一部分的传输协议(如TCP),并定义给定服务的优先级、权重、端口和目标。详细内容请参阅下面的示例:

在上面的示例中,_sip是服务的符号名称,_tcp是服务的使用传输协议。记录内容代表:两个记录都定义了10的优先级。另外,第一个记录的权重为70,第二个记录的权重为20。优先级和权重通常用于建议指定使用某些服务器。记录中的最后两个值定义了要连接的端口和主机名,以便与服务通信。

Kubernetes DNS的SRV记录是按照一个约定俗成的规定实现了对服务端口的查询:

SRV记录是为“normal”或“headless”服务的部分指定端口创建的。SRV记录采用_my-port-name._my-port-protocol.my-svc.my-namespace.svc.cluster.local的形式。对于常规服务,它被解析的端口号和域名是my-svc.my-namespace.svc.cluster.local。在“headless”服务的情况下,此 name解析为多个answer,每个answer都支持服务。每个answer都包含auto-generated-name.my-svc.my-namespace.svc.cluster.local表单的Pod端口号和域名。

3.CNAME记录

CNAME记录用于将域或子域指向另一个主机名。为此,CNAME使用现有的A记录作为其值。相反,A记录会解析为指定的IP地址。此外,在Kubernetes中,CNAME记录可用于联合服务的跨集群服务发现。在整个场景中会有一个跨多个Kubernetes集群的公共服务。所有Pod都可以发现这项服务(无论这些Pod在哪个集群上)。这是一种跨集群服务发现方法。

3.7.3 DNS使用

Pod的默认主机名由Pod的metadata.name值定义。用户可以通过在可选的hostname字段中指定一个新值更改默认主机名。用户还可以在subdomain字段中自定义子域名。例如,在命名空间my-namespace中,将hostname设置为custom-host,将subdomain设置为custom-subdomain的Pod将具有完全限定的域名(FQDN)custom-host.custom-subdomain.my-namespace.svc.cluster.local。

下面我们运行一个带nslookup命令的busybox容器,说明Kubernetes域名解析的使用。

大部分busybox都不带nslookup命令,因此这里给出一个带nslookup命令的busybox Pod示例yaml文件:

在default namespace下把这个Pod创建好,就可以通过kubectl exec进入busybox容器进行以下试验了。

我们先来查询Kubernetes默认的API Server服务Kubernetes的IP地址:

如上所示,Kube-dns的IP地址是10.0.0.1,而API Server的Cluster IP地址是10.0.0.10。我们在default namespace下又创建了一个名为whoami的服务,并做以下域名解析动作:

如上所示,发起域名解析请求的busybox Pod和whoami服务均在default namespace下,因此以下所有域名都能被正确解析并且返回相同的结果。

查看busybox Pod的DNS配置文件,可以看到如下DNS Server的地址及搜索的domain列表:

其中,DNS Server的IP地址是10.0.0.1。options ndots:5的含义是当查询的域名字符串内的点字符数量超过ndots(5)值时,则认为是完整域名,直接解析,否则Linux系统会自动尝试用default.pod.cluster.local、default.svc.cluster.local或svc.cluster.local补齐域名后缀。例如,查询whoami会自动补齐成whoami.default.pod.cluster.local、whoami.default.svc.cluster.local和whoami.svc.cluster.local,查询过程中,任意一个记录匹配便返回,显然能返回DNS记录的匹配是whoami+default.svc.cluster.local。而查询whoami.default能返回DNS记录的匹配是whoami.default+svc.cluster.local。

最后,运行DNS Pod可能需要特权,即配置Kubelet的参数:--allow-privileged=true。

1.Kubernetes域名解析策略

Kubernetes域名解析策略对应到Pod配置中的dnsPolicy,有4种可选策略,分别是None、ClusterFirstWithHostNet、ClusterFirst和Default,其中:

· None:从Kubernetes 1.9版本起引入的一个新选项值。它允许Pod忽略Kubernetes环境中的DNS设置。应使用dnsConfigPod规范中的字段提供所有DNS设置;

· ClusterFirstWithHostNet:对于使用hostNetwork运行的Pod,用户应该明确设置其DNS策略为ClusterFirstWithHostNet;

· ClusterFirst:任何与配置的群集域后缀(例如cluster.local)不匹配的DNS查询(例如“www.kubernetes.io”)将转发到从宿主机上继承的上游域名服务器。集群管理员可以根据需要配置上游DNS服务器;

· Default:Pod从宿主机上继承名称解析配置。

None

一个配置了None类型的dnsPolicy的Pod如下:

以上Pod被创建后,test容器的/etc/resolv.conf内容如下所示:

ClusterFirstWithHostNet

使用ClusterFirstWithHostNet策略的一个Pod配置文件如下:

如上所示。当Pod使用主机网络(hostNetwork:true)时,DNS策略需要设置成ClusterFirstWithHostNet。对于那些使用主机网路的Pod,它们是可以直接访问宿主机的/etc/resolv.conf文件的。因此,如果不加上dnsPolicy:ClusterFirstWithHostNet,则Pod将默认使用宿主机的DNS配置,这样会导致集群内容器无法通过域名访问Kubernetes的服务(除非在宿主机的/etc/resolv.conf文件配置了Kubernetes的DNS服务器)。

ClusterFirst

使用ClusterFirst策略的一个Pod配置文件如下所示:

ClusterFirst策略就是优先使用Kubernetes的DNS服务解析,失败后再使用外部级联的DNS服务解析,工作流程如图3-21所示。

图3-21 Kubernetes DNS级联的工作流程

3.7.4 调试DNS

如果nslookup命令由于某种原因失败,则有几种调试和排除故障的方案。但是,应该如何得知DNS查找失败呢?若DNS失败,通常会得到如下响应:

如果出现此错误,则需要做的第一件事是检查DNS配置是否正确。

查看容器中的resolv.conf文件:

验证是否正确设置了搜索路径和名称服务器,如下例所示:

如果/etc/resolve.conf的所有条目都是正确的,则需要检查kube-dns/coredns插件是否已启用,或者检查kubedns/coredns Pod是否正在运行。

如果Pod正在运行,则全局DNS服务可能存在问题。

检查:

可能还需要检查后端DNS Endpoint是否准备好:

以上是关于Kubernetes网络自学系列 | 你的名字:通过域名访问服务的主要内容,如果未能解决你的问题,请参考以下文章

Kubernetes网络自学系列 | 初识Linux隧道:ipip

Kubernetes网络自学系列 | 打通CNI与Kubernetes:Kubernetes网络驱动

Kubernetes网络自学系列 | 终于等到你:Kubernetes网络

Kubernetes网络自学系列 | 前方高能:Kubernetes网络故障定位指南

Kubernetes网络自学系列 | iptables

Kubernetes网络自学系列 | Linux隧道网络的代表:VXLAN