OpenShift是一个企业就绪型Kubernetes容器平台,提供WebUI及网络、监控、日志收集、身份验证和授权、CI/CD、存储等解决方案,可以实现全栈自动化运维,基于Kubernetes而强于Kubernetes。OpenShift需订阅使用,社区版OKD是免费的。本文讲解OpenShift集群中的DNS ClusterOperator。
1,DNS的使用场景
OpenShift集群中,使用DNS有下面三个地方:
- Pod访问集群外的域名,比如“www.jianshu.com”
- Pod通过服务的域名访问集群中的服务,即服务发现功能,需要通过DNS得到Cluster IP从而访问到对应的服务
- 集群外部通过域名访问部署在OpenShift中的服务,需要DNS来解析服务的集群外域名
下面部分解释OpenShift 4是如何实现上述三个功能的(OpenShift 3使用了SkyDNS,有很大不同)
2,DNS工作原理
首先要知道Pod从哪里得到DNS服务的IP。在Linux系统中,DNS服务器的IP保存在文件“/etc/resolv.conf”中,Pod也不例外。任意选择运行在集群中的Pod,查看其“/etc/resolv.conf”文件,内容如下:
~ $ cat /etc/resolv.conf
search apache-exporter.svc.cluster.local svc.cluster.local cluster.local okd-infra.example.com
nameserver 172.30.0.10
options ndots:5
172.30.0.10是名为“dns-default”的Service的Cluster IP,
kind: Service
apiVersion: v1
metadata:
name: dns-default
namespace: openshift-dns
selfLink: /api/v1/namespaces/openshift-dns/services/dns-default
uid: b850c113-a15d-493f-8be8-5302217106aa
resourceVersion: '10820'
creationTimestamp: '2020-05-20T13:24:26Z'
labels:
dns.operator.openshift.io/owning-dns: default
ownerReferences:
- apiVersion: operator.openshift.io/v1
kind: DNS
name: default
uid: b2aadbb6-c743-43d6-b0b5-83e039b319ab
controller: true
spec:
ports:
- name: dns
protocol: UDP
port: 53
targetPort: dns
- name: dns-tcp
protocol: TCP
port: 53
targetPort: dns-tcp
- name: metrics
protocol: TCP
port: 9153
targetPort: metrics
selector:
dns.operator.openshift.io/daemonset-dns: default
clusterIP: 172.30.0.10
type: ClusterIP
sessionAffinity: None
status:
loadBalancer: {}
该服务的后端是以DaemonSet方式部署在每台宿主机上“dns-default-<id>” Pod,其中核心容器名字为“dns”,运行CoreDNS,完成所有的地址解析和转发工作(后面详细介绍)。
登录一台“dns-default-<id>” Pod,查看CoreDNS的配置文件(配置文件的含义可以参考官方文档,这里不做介绍),
sh-4.2# cat /etc/coredns/Corefile
.:5353 {
errors
health
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
upstream
fallthrough in-addr.arpa ip6.arpa
}
prometheus :9153
forward . /etc/resolv.conf {
policy sequential
}
cache 30
reload
}
请求内部域名由带“kubernetes”插件的CoreDNS处理,请求外部域名由“forward”插件处理。
<1> Pod访问外部域名
当集群内的Pod请求外部的域名如“www.toutiao.com”时,从上面的分析可知,请求需要发送到配置在文件“/etc/reslov.conf”中的DNS服务器,该文件的内容如下,
sh-4.2# cat /etc/resolv.conf
search okd-infra.example.com
nameserver 10.255.1.1
nameserver的IP和宿主机保持一致(实际文件就是拷贝宿主机的),这就简单了,当集群内的Pod需要访问外部的域名时,由外部的DNS服务器做解析,和普通的Linux服务器DNS请求原理一致。
<2> 集群服务发现
CoreDNS的“kubernetes”插件实现了基于DNS的服务发现(还有一种服务发现基于Pod中的环境变量),该插件解析的DNS name格式是这样的:<service_name>.<namespace>. svc .cluster.local,解析出的地址是“service_name”的Cluster IP。
比如位于“my-exporter”NameSpace中的服务“rocketmq-exporter”,登录集群内任意主机,通过集群内的DNS服务做解析,
[core@master-1 ~]$ dig rocketmq-exporter.my-exporter.svc.cluster.local @172.30.0.10
; <<>> DiG 9.11.20-RedHat-9.11.20-1.fc32 <<>> rocketmq-exporter.my-exporter.svc.cluster.local @172.30.0.10
;; global options: +cmd
;; Got answer:
;; WARNING: .local is reserved for Multicast DNS
;; You are currently testing what happens when an mDNS query is leaked to DNS
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 61833
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: f31e6b5240840234 (echoed)
;; QUESTION SECTION:
;rocketmq-exporter.my-exporter.svc.cluster.local. IN A
;; ANSWER SECTION:
rocketmq-exporter.my-exporter.svc.cluster.local. 5 IN A 172.30.15.144
;; Query time: 1 msec
;; SERVER: 172.30.0.10#53(172.30.0.10)
;; WHEN: Wed Oct 28 10:29:37 UTC 2020
;; MSG SIZE rcvd: 157
解析出的172.30.15.144就是服务“rocketmq-exporter”的Cluster IP,
[core@master-1 ~]$ oc get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
rocketmq-exporter ClusterIP 172.30.15.144 <none> 5557/TCP 2d1h
原理很简单,安装“kubernetes”插件的CoreDNS作为客户端请求kubernetes API Server,得到service、namespace、cluster domain,cluster IP等信息,然后将这些信息通过DNS A记录(或AAAA记录)的形式暴露出来给Pod访问。
<3> 外部访问集群内的服务
安装OpenShift 4需要一个安装配置文件“install-config.yaml”,其中“baseDomain”和“metadata.name”组成了从集群外访问内部服务的域名,如下,
aneirin@host-1:~$ cat install-config.yaml
apiVersion: v1
baseDomain: example.com
compute:
- hyperthreading: Enabled
name: worker
replicas: 0
controlPlane:
hyperthreading: Enabled
name: master
replicas: 3
metadata:
name: okd-infra
......
配置集群外使用的DNS服务,
.....
api IN A 10.1.95.9 ; haproxy IP
api-int IN A 10.1.95.9 ; haproxy IP
*.apps IN A 10.1.95.9 ; haproxy IP
笔者通过“bare metal”的方式安装OpenShift集群,这种搭建方式没有现成的“load balancer”可用,需要自己实现load balance功能,实际使用HAProxy。通过上面DNS的配置将访问集群的外部请求路由到HAProxy,服务后端是OpenShift的Router pod运行的宿主机,HAProxy配置片段,
......
#---------------------------------------------------------------------
frontend ingress-http
bind 10.1.95.9:80
default_backend ingress-http
mode tcp
#---------------------------------------------------------------------
backend ingress-http
balance source
mode tcp
server worker-1 10.1.99.14:80 check port 80
server worker-2 10.1.99.15:80 check port 80
#---------------------------------------------------------------------
frontend ingress-https
bind 10.1.95.9:443
default_backend ingress-https
mode tcp
#---------------------------------------------------------------------
backend ingress-https
balance source
mode tcp
server worker-1 10.1.99.14:443 check port 443
server worker-2 10.1.99.15:443 check port 443
#---------------------------------------------------------------------
......
Router Pod使用了宿主机网络,和宿主机使用同一个网络栈,所以像访问宿主机一样访问Router Pod。
这一部分和Operator DNS的关系不大,它属于集群Ingress的范畴,就不深入了。
3,DNS相关组件介绍
DNS Operator使用DaemonSet部署CoreDNS,这样保证集群中的每一个宿主机都有一个本地CoreDNS pod副本。DaemonSet部署的Pod含有三个容器:“dns”运行CoreDNS,完成核心的地址解析和转发服务,“dns-node-resolver”添加集群image registry的DNS name到宿主机的“/etc/hosts”文件,因为宿主机不请求集群的DNS服务,它没法知道image registry的IP地址,需要“dns-node-resolver”将image registry的地址信息加入宿主机的“/etc/hosts”文件,如下,最后一行就是“dns-node-resolver”添加的,
[core@master-1 ~]$ cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
172.30.238.6 image-registry.openshift-image-registry.svc \
image-registry.openshift-image-registry.svc.cluster.local # openshift-generated-node-resolver
还有一个名为 “kube-rbac-proxy”的容器和授权相关,不讲解。当Pod请求DNS name时,它不是直接请求本地的“dns-default-<id>” Pod,而是请求“openshift-dns”namespace中的“dns-default”服务,由该服务随机选择一个“dns-default-<id>” Pod完成查询,当然请求的“dns-default-<id>” Pod可能运行在别的宿主机上。
总结
本文对OpenShift 4集群DNS服务的原理和相关组件做简单介绍,Kubernetes同样有参考价值,有任何问题欢迎交流指正,也希望这篇文章能帮到正在努力前进的你。