在介绍 Kubernetes 中的 DNS 之前,我们先来看看 Kubernetes 中的另一个概念 Service
,以及为什么需要 Service。
什么是 Service
我们知道 k8s 集群中应用的部署是以 Pod 为单位的,在 Pod 内执行 ifconfig 可以看到每个 Pod 都有自己的 IP,这个 IP 在集群内部是唯一的,其他 Pod 都能 ping 这个地址。
这样的设计使得 Pod 里的应用程序可以直接交互。
另一方面,Pod 的生命周期是短暂的,因此 Pod IP 也是不断变化的,而且 Pod 也会有多个副本。
那么问题来了: 其他程序访问这个 Pod 时该用哪个 IP 地址呢 ?
这个时候就需要 Service 出场了, Service 对外只会提供一个 IP,一个请求到来时 Service 决定该转发到后面哪一个 Pod 上。
我们可以理解为 Service 加上的一组 Pod 可以看做是一个微服务。
Service 对外提供 ClusterIP, NodePort 等访问方式。
Kubernetes DNS
上面提到 Service 对外提供一个唯一的 IP,但这个 IP 偶尔也会随着 service 的更新改变,所以还需要一个 k8s 集群内部的 DNS 把服务对应到 IP 上。
因此 k8s 提供了 kube-dns(最新的 k8s 已经推荐使用 coreDNS)为 service 生成 DNS 记录,那么生成的名字是什么样的呢?
- 普通的 Service:会生成
servicename.namespace.svc.cluster.local
的域名,解析到 Service 对应的 ClusterIP 上,在 Pod 之间的调用可以简写成servicename.namespace
,如果处于同一个命名空间下面,甚至可以只写成servicename
。 - Headless Service:无头服务,就是把 clusterIP 设置为 None 的,会被解析为指定 Pod 的 IP 列表,同样还可以通过
podname.servicename.namespace.svc.cluster.local
访问到具体的某一个 Pod。
/etc/resolv.conf
通过前面的说明,我们知道了 k8s 中需要 DNS,并且也知道了域名的格式,那么 Pod 怎么知道去用哪个域名呢?
这个问题与 k8s 关系不大,它其实是我们 Linux 系统上常见的 resolv.conf
先说明一下 resolv.conf 各个字段的含义。
$ cat /etc/resolv.conf
domain home.local
nameserver 8.8.8.8
nameserver 192.168.2.5
search baidu.com
- nameserver 就是用来指定 DNS server 地址的,例如我常用的就是 8.8.8.8
- domain 用来指定本地的域名,在没有设置 search 的情况下,search 默认搜索 domain 的值。
- search 当 dns 解析域名的时候,找不到你指定的名称的结果时,默认加上 serach 字段的名称重试。例如 ping ditu, 显然找不到 ditu 这个域名对应的 IP 地址,然后就会自动搜索 ditu.baidu.com
Pod 中的 resolv.conf
进入任意的两个不相关的 Pod,并查看 resolv.conf 的值
[ root@redis-master-68b5d7cd85:/data ]$ cat /etc/resolv.conf
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
[ root@curl-69c656fd45-wjddg:/ ]$cat /etc/resolv.conf
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
可以看出两个不同的 Pod 中 nameserver 都是同一个,这个地址就是 k8s 集群中静态的 DNS 服务地址。
最后,尝试在一个 Pod 中使用 DNS 域名访问 redis 服务。
这个 redis service 的名字叫 redis-nodeport,在 default 名空间。
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
redis-nodeport NodePort 10.96.39.42 <none> 6379:31250/TCP 16d
# 进入 Pod
[ root@69c656f:/ ]$ telnet redis-nodeport.default.svc.cluster.local 6379
set hello safdasf
+OK
get hello
$7
safdasf
(完)