即便Service有了IP,但是若集群上有1000+Service,使用IP地址去访问是不可能的事情,所以我们需要以Service的名称来访问服务。

由于k8s上的服务是动态管理的,随时有可能创建删除。如果使用传统的DNS解析那么每一次创建一个服务就得去手动管理其解析记录。

服务发现在it领域有很多种解决方法,如Zookeeper,Euraka,Consul等。如果使用这些方法的话服务注册和发现能很好解决,但名称解析依然无法联动,因而k8s没有使用这总服务发现机制,而是将传统的DNS服务直接提供了一个云原生解决方案,它支持从APIServer上动态加载相关的Service信息及端点信息,并自动生成资源记录。

这种DNS就成了k8s上服务注册和服务发现的动态总线:kubeDNS。

其实现方案上有3代:

  • 第一代:SkyDNS
  • 第二代:KubeDNS
  • 第三代:CoreDNS

K8S的服务发现

在K8S中服务发现有两种方法,基于环境变量或基于DNS服务。

基于环境变量的服务发现

在k8s中基于环境变量的方法又有两种:

(1)Kubernetes Service环境变量

Kubernetes为每个Service资源生成包括以下形式的环境变量在内一系列环境变量,在同一名称空间中创建的Pod对象都会自动拥有这些变量:

bash
1
2
{SVCNAME}_SERVICE_HOST
{SVCNAME}_SERVICE_PORT

default名称空间:创建的demoapp Service,意味着default名称空间下的每个Pod内部会被自动注入 DEMOAPP_SERVICE_HOST:ClusterIP , DEMOAPP_SERVICE_PORT=80

#####(2)Docker Link形式的环境变量

Docker使用–link选项实现容器连接时所设置的环境变量形式,具体使用方式请参考Docker的相关文档。在创建Pod对象时,kubernetes也会把与此形式兼容的一系列环境变量注入到Pod对象中。

基于DNS的服务发现

基于DNS的服务发现,对于每个Service对象,都会具有以下3个类型的DNS资源记录。

1)根据ClusterIP的地址类型,为IPv4生成A记录,为IPv6生成AAAA记录;
bash
1
2
3
4
5
6
<service>.<ns>.svc.<zone>. <ttl>  IN  A  <cluster-ip>
<service>.<ns>.svc.<zone>. <ttl> IN AAAA <cluster-ip>

# 如有个service为demoapp,其固定的DNS名称即为:
demoapp.default.svc.cluster.local.
# 如果部署集群时没有指定域名那么其<zone>即为cluster.local.

验证

bash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# 当前集群上有一个demoapp的svc地址为10.111.8.128。
root@k8s-master01:~# kubectl get svc demoapp
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
demoapp NodePort 10.111.8.128 <none> 80:31156/TCP 13d

# 进入一个pod进行解析
[root@demoapp-5f7d8f9847-jrfm6 /]# nslookup demoapp.default.svc.cluster.local.
Server: 10.96.0.10 # dns服务器地址,此为CoreDNS服务的地址
Address: 10.96.0.10#53

Name: demoapp.default.svc.cluster.local
Address: 10.111.8.128 # 得到的地址

# CoreDNS服务地址
root@k8s-master01:~# kubectl get svc -n kube-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 13d

# 每创建一个pod都会在其/etc/resolve.conf中指定其nameserver为kube-dns的地址
root@k8s-master01:~# kubectl exec demoapp-5f7d8f9847-jrfm6 -- cat /etc/resolv.conf
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
# 上述search参数中指定的DNS各搜索域,是以次序指定的几个域名后缀,它们各自的如下所示。
# <ns>.svc.<zone>:附带有特定名称空间的域名,例如default.svc.cluster.local;
# svc. <zone>:附带了Kubernetes标识Service专用子域svc的域名,例如svc.cluster.local
# <zone>:集群本地域名,例如cluster.local。


# 查看kube-dns详细信息
root@k8s-master01:~# kubectl describe svc kube-dns -n kube-system
Name: kube-dns
Namespace: kube-system
Labels: k8s-app=kube-dns
kubernetes.io/cluster-service=true
kubernetes.io/name=CoreDNS
Annotations: prometheus.io/port: 9153
prometheus.io/scrape: true
Selector: k8s-app=kube-dns
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.96.0.10
IPs: 10.96.0.10
Port: dns 53/UDP
TargetPort: 53/UDP
Endpoints: 10.244.0.4:53,10.244.0.5:53 # 其后端有两个端点
Port: dns-tcp 53/TCP
TargetPort: 53/TCP
Endpoints: 10.244.0.4:53,10.244.0.5:53
Port: metrics 9153/TCP
TargetPort: 9153/TCP
Endpoints: 10.244.0.4:9153,10.244.0.5:9153
Session Affinity: None
Events: <none>

# 查看kube-dns的后端端点。
root@k8s-master01:~# kubectl get pods -o wide -n kube-system -l 'k8s-app=kube-dns'
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
coredns-57d4cbf879-p5c58 1/1 Running 1 13d 10.244.0.4 k8s-master01 <none> <none>
coredns-57d4cbf879-rfdsk 1/1 Running 1 13d 10.244.0.5 k8s-master01 <none> <none>
# coredns会始终监视着APIServer中的资源变动,删除一个Service其将无法解析。
2)为每个定义了名称的端口生成一个SRV记录,未命名的端口号则不具有该记录;
bash
1
2
# SRV是用来实现服务发现的
_<port>._<protocol>.<service>.<ns>.svc.<zone>. <ttl> IN SRV <weight> <priority> <port-number> <service>.<ns>.svc.<zone>.
3)对于每个给定的A记录或AAAA记录都要生成PTR记录,
bash
1
2
3
# PTR记录各自的格式如下所示
<d>.<c>.<b>.<a>.in-addr.arpa. <ttl> IN PTR <service>.<ns>.svc.<zone>.
h4.h3.h2.h1.g4.g3.g2.g1.f4.f3.f2.f1.e4.e3.e2.e1.d4.d3.d2.d1.c4.c3.c2.c1.b4.b3.b2.b1.a4.a3.a2.a1.ip6.arpa <ttl> IN PTR <service>.<ns>.svc.<zone>.

验证PTR记录

bash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 查询demoapp-svc的ServiceIP 
root@k8s-master01:~# kubectl get svc demoapp-svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
demoapp-svc ClusterIP 10.97.72.1 <none> 80/TCP 6d22h

# 在pod中对其进行反向解析
root@k8s-master01:~# kubectl exec demoapp-5f7d8f9847-jrfm6 -- nslookup -A 10.97.72.1
*** Invalid option: A
1.72.97.10.in-addr.arpa name = demoapp-svc.default.svc.cluster.local.

# 在pod中做正向解析
root@k8s-master01:~# kubectl exec demoapp-5f7d8f9847-jrfm6 -- nslookup 10.97.72.1
1.72.97.10.in-addr.arpa name = demoapp-svc.default.svc.cluster.local.

root@k8s-master01:~# kubectl exec demoapp-5f7d8f9847-jrfm6 -- nslookup demoapp-svc.default.svc.cluster.local.
Server: 10.96.0.10
Address: 10.96.0.10#53

Name: demoapp-svc.default.svc.cluster.local
Address: 10.97.72.1

前面在default名称空间中创建Service对象demoapp-svc的地址为10.97.72.1,且为TCP协议的80端口取名http,对于默认的cluster.local域名来说,此它会拥有如下3个DNS资源记录。

  • A记录:demoapp-svc.default.svc.cluster.local. 30 IN A 10.97.72.1;
  • SRV记录:_http._tcp.demoapp-svc.default.svc.cluster.local. 30 IN SRV 0 100 80 demoapp-svc.default.svc.cluster.local.
  • PTR记录:1.72.97.10.in-addr.arpa. 30 IN PTR demoapp-svc.default.svc.cluster.local.

CoreDNS配置

有时候我们需要对CoreDNS进行配置,对其增加一些解析的功能,CoreDNS在kube-system名称空间下,其配置文件也是由ConfigMap来提供的

bash
1
2
3
root@k8s-master01:~# kubectl get cm coredns -n kube-system
NAME DATA AGE
coredns 1 13d

编辑coredns配置文件

bash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
root@k8s-master01:~# kubectl edit cm coredns -n kube-system
# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: v1
data:
Corefile: |
.:53 {
errors # 表示将错误日志发往标准输出
health { # 做健康状态检测
lameduck 5s
}
ready # 所有状态就绪后才能报告自身为健康
kubernetes cluster.local in-addr.arpa ip6.arpa { # 集群解析区域
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
prometheus :9153 # 向外输出prometheus兼容的指标数据
forward . /etc/resolv.conf { # 前向转发,若pod dns无法解析,就调用宿主机的/etc/resolv.conf文件中的dns服务器进行解析。
max_concurrent 1000
}
# forward . 223.6.6.6 223.5.5.5 { # 可以自己指定公网上的dns服务器地址
# max_concurrect 1000
# except mylinuxops.com. # 排除某个域名,不需要外网dns解析
# }
# forward mylinuxops.com. 43.123.45.22 # 使用forward 对排除的域名进行单独解析
# 一个配置段中只能出现一个forward . 否则将冲突。
cache 30
loop
reload # 修改后自动重载
loadbalance # 若某个记录后有多条A记录,他会在多个A记录中轮询
}
kind: ConfigMap
metadata:
creationTimestamp: "2021-06-28T10:53:46Z"
name: coredns
namespace: kube-system
resourceVersion: "264"
uid: a7bb8e7b-90f1-416f-bbcc-111f715a0171