深入挖掘 OpenShift 内部 DNS
Jul 4, 2019 00:30 · 977 words · 2 minute read
OpenShift 容器云集群中有两种 DNS:
- 外部 DNS(DNS 服务商或自己搭建的 DNS 服务器)用于解析集群中主机的 IP
- 内部 DNS 用于内部服务之间的通讯
DNS 配置
在部署 OpenShift 时我们会为所有的节点上都安装好 Dnsmasq(监听着53端口)。
$ cat /etc/resolv.conf
# nameserver updated by /etc/NetworkManager/dispatcher.d/99-origin-dns.sh
search cluster.local paas.99cloud.home
nameserver 172.16.60.83
主机的 DNS 指向了本机上运行的 Dnsmasq。
$ cat /etc/dnsmasq.d/origin-upstream-dns.conf
server=172.16.60.90
Dnsmasq 的上游服务器指向了外部的 DNS 服务器(DNS 服务商或使用 CoreDNS 为集群提供域名解析服务)。
$ cat /etc/origin/node/resolv.conf
nameserver 172.16.60.90
而内部的 SkyDNS 也指向了外部的 DNS 服务器作为默认 DNS 域名服务器。
DNS 查询流程
OpenShift 内部使用 SkyDNS,数据存储在 etcd 中。
我们首先看一下主节点上所有监听了53端口的进程:
$ netstat -tunlp | grep 53
tcp 0 0 172.16.60.83:53 0.0.0.0:* LISTEN 33210/dnsmasq
tcp 0 0 172.17.0.1:53 0.0.0.0:* LISTEN 33210/dnsmasq
tcp 0 0 127.0.0.1:53 0.0.0.0:* LISTEN 12277/openshift
tcp 0 0 10.128.0.1:53 0.0.0.0:* LISTEN 62167/dnsmasq
tcp 0 0 0.0.0.0:8053 0.0.0.0:* LISTEN 6392/openshift
127.0.0.1:53 就是真正的 OpenShift 内部 DNS。
Kubernetes 集群内部发布的 Service 对应的域名可以按照 service_name.name_space.svc 这个规则拼接起来。
$ curl -k https://apiserver.kube-service-catalog.svc/healthz
ok
$ oc get svc -n kube-service-catalog
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
apiserver ClusterIP 172.30.36.133 <none> 443/TCP 7h
controller-manager ClusterIP 172.30.189.41 <none> 443/TCP 7h
$ nslookup apiserver.kube-service-catalog.svc
Server: 172.16.60.83
Address: 172.16.60.83#53
Name: apiserver.kube-service-catalog.svc.cluster.local
Address: 172.30.36.133
$ nslookup apiserver.kube-service-catalog.svc 172.16.60.83
Server: 172.16.60.83
Address: 172.16.60.83#53
Name: apiserver.kube-service-catalog.svc.cluster.local
Address: 172.30.36.133
$ nslookup apiserver.kube-service-catalog.svc 127.0.0.1
Server: 127.0.0.1
Address: 127.0.0.1#53
Name: apiserver.kube-service-catalog.svc.cluster.local
Address: 172.30.36.133
对照着流程图,我们可以还原一个完整的 DNS 解析过程:
- 当访问 api server 服务健康状态的 API 时首先会查询 apiserver.kube-service-catalog.svc 这个(内部)域名对应的 IP 地址
- DNS 查询请求先来到主机已经配置好的 DNS 服务器,也就是 Dnsmasq
- Dnsmasq 随后会将查询请求向上递交给 SkyDNS,也就是集群内部的 DNS 服务器,这里能查到正确的 IP 地址
我们在管理 OpenShift 网络的 Pod 内部来查询一下 apiserver.kube-service-catalog.svc.cluster.local
$ oc get pods -n openshift-sdn
NAME READY STATUS RESTARTS AGE
ovs-7kpnv 1/1 Running 0 11h
ovs-7p75w 1/1 Running 0 11h
ovs-m6clw 1/1 Running 0 11h
sdn-7fz45 1/1 Running 0 11h
sdn-l9cq7 1/1 Running 0 11h
sdn-rmqvd 1/1 Running 0 11h
$ oc exec -it sdn-7fz45 -n openshift-sdn /bin/bash
[root@ocp-infra-1 origin]# dig apiserver.kube-service-catalog.svc.cluster.local
; <<>> DiG 9.9.4-RedHat-9.9.4-74.el7_6.1 <<>> apiserver.kube-service-catalog.svc.cluster.local
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 39256
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;apiserver.kube-service-catalog.svc.cluster.local. IN A
;; ANSWER SECTION:
apiserver.kube-service-catalog.svc.cluster.local. 30 IN A 172.30.36.133
;; Query time: 1 msec
;; SERVER: 172.16.60.83#53(172.16.60.83)
;; WHEN: Wed Jul 03 16:17:59 UTC 2019
;; MSG SIZE rcvd: 82
为什么需要内部 DNS?
以往虚拟机中的应用程序之间通讯所使用的宿主机 IP 通常不会轻易变化。但是在容器环境中,容器启动时会被分配新的 IP 地址。编排容器的 Kubernetes 需要静态 IP,提供服务 IP 的 Service 对象就是为了实现这个目的而创建的。Service 对象的域名是不会变化的(拼接规则),借助这个内部的域名,可以实现服务之间的稳定通讯而不用管背后 Pod 本身的 IP 是否被改变。
由于 Pod 的 IP 会变化,如果我们在应用程序或者配置中指定了 IP 地址,Pod 被重新创建时应用程序并不会被主动通知 IP 已经改变。出于这些原因,我们通常使用域名来避免在应用程序中写死 IP 地址。OpenShift 的内部 DNS 使用动态 DNS,无论何时 Pod 被重建,DNS 都将使用新纪录进行更新。