在 Kubernetes 集群中,服务发现是核心功能之一,而 CoreDNS 作为 Kubernetes 集群的 DNS 解析组件,承担着内部域名解析的重要职责。本文将详细介绍 CoreDNS 的工作原理、配置方式以及实际应用场景。
一、Kubernetes 服务发现方式
Kubernetes 提供了两种主要的服务发现方式:
- 基于环境变量的方式
- 基于内部域名的方式
在实际应用中,基于内部域名的方式更为常用。自 Kubernetes 1.11 版本起,kubeadm 已经使用 CoreDNS 替代了官方的 kubedns 作为默认的 DNS 解析组件。
二、Kubernetes 域名解析原理
当在 Kubernetes 中通过域名访问服务时,例如服务 A 访问服务 B,同一 Namespace 下可直接使用 curl b,跨 Namespace 则需要使用 curl b.default 这样的形式。这背后的原理与容器内的 resolv.conf 文件配置密切相关。
容器内的 /etc/resolv.conf 文件通常包含以下内容:
shell
cat /etc/resolv.conf
nameserver 10.10.0.3
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
其中:
nameserver指向的是 CoreDNS Service 的 ClusterIP(虚拟 IP)search定义了域名搜索路径options ndots:5设定了触发搜索的域名点数阈值
当 Pod 的 DNS 策略为 ClusterFirst 时,所有域名解析(包括内部和外部域名)都会经过 CoreDNS 处理。
三、Pod DNS 策略
Kubernetes 中 Pod 的 DNS 策略有四种类型:
-
Default:Pod 继承所在主机的 DNS 配置
-
ClusterFirst :K8s 默认设置,先在集群的 CoreDNS 中查询,查不到再使用主机的上游 DNS
yaml
dnsPolicy: ClusterFirst -
ClusterFirstWithHostNet:对于使用 hostNetwork 的 Pod,DNS 配置规则与 ClusterFirst 一致
-
None :忽略 K8s 环境的 DNS 配置,仅使用 Pod 的 dnsConfig 设置
yaml
dnsPolicy: "None" dnsConfig: nameservers: - 114.114.114.114 searches: - default.svc.cluster.local options: - name: ndots value: "5"
四、CoreDNS 解析规则
每个 Pod 中的 /etc/resolv.conf 文件定义了 DNS 查询规则,以下是一个示例配置:
shell
[root@mypod /]# cat etc/resolv.conf
search default.svc.test.com svc.test.com test.com
nameserver 169.254.25.10
options ndots:5
关键配置解析
-
nameserver:集群中的 DNS 服务器 IP,通常是 CoreDNS 的 ClusterIP
-
search:域名搜索域,解析时会将查询的域名依次与这些域组合进行查询。例如查询 "nginx" 时,会按以下顺序尝试:
plaintext
nginx.default.svc.test.com. -> nginx.svc.test.com. -> nginx.test.com. -
options ndots:定义触发搜索的域名点数阈值(默认为 5):
- 当查询的域名包含的点 "." 小于 5 时,先走 search 域,再用绝对域名
- 当查询的域名包含点数大于或等于 5 时,先用绝对域名,再走 search 域
例如:
-
访问
a.b.c.e.f.g(6 个点)时:plaintext
a.b.c.e.f.g. -> a.b.c.e.f.g.default.svc.test.com. -> ... -
访问
a.b.c.e.(4 个点)时:plaintext
a.b.c.e.default.svc.test.com. -> a.b.c.e.svc.test.com. -> ... -> a.b.c.e.
五、Pod 之间的通信方式
1. 通过 Service 名称通信
在 Kubernetes 中,Pod 之间通过 Service 访问时,会经过 DNS 域名解析获取 IP 地址。Kubernetes 服务的完整域名格式为:<service-name>.<namespace>.svc.test.com
示例 :部署一个名为 nginx-svc 的 Service:
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: docker.io/library/nginx:latest
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
spec:
selector:
app: nginx
ports:
- port: 80
protocol: TCP
targetPort: 80
type: ClusterIP
在其他 Pod 中访问该服务:
shell
[root@mypod /]# ping nginx-svc
PING nginx-svc.default.svc.test.com (10.10.23.221) 56(84) bytes of data.
64 bytes from nginx-svc.default.svc.test.com (10.10.23.221): icmp_seq=1 ttl=64 time=0.152 ms
跨 Namespace 访问时需要指定 Namespace:
shell
[root@mypod /]# ping harbor-core.harbor
PING harbor-core.harbor.svc.test.com (10.10.30.184) 56(84) bytes of data.
64 bytes from harbor-core.harbor.svc.test.com (10.10.30.184): icmp_seq=1 ttl=64 time=0.095 ms
2. 通过 hostname 和 subdomain 通信
可以通过 spec.hostname 和 spec.subdomain 字段自定义 Pod 的主机名和子域名:
yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: web
spec:
hostname: nginx
subdomain: subdomain-test
containers:
- name: nginx
image: docker.io/library/nginx:latest
---
apiVersion: v1
kind: Service
metadata:
name: subdomain-test
spec:
selector:
app: web
ports:
- port: 80
targetPort: 80
其他 Pod 可以通过 nginx.subdomain-test 访问该 Pod:
shell
[root@mypod /]# ping nginx.subdomain-test
PING nginx.subdomain-test.default.svc.test.com (10.10.92.25) 56(84) bytes of data.
64 bytes from nginx.subdomain-test.default.svc.test.com (10.10.92.25): icmp_seq=1 ttl=62 time=1.91 ms
六、CoreDNS 配置文件(Corefile)
CoreDNS 采用插件化架构,其配置文件为 Corefile,存储在 kube-system 命名空间的 coredns ConfigMap 中。
默认配置
yaml
apiVersion: v1
data:
Corefile: |
.:53 {
errors
health {
lameduck 5s
}
ready
kubernetes test.com in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
prometheus :9153
forward . /etc/resolv.conf {
max_concurrent 1000
}
cache 30
loop
reload
loadbalance
}
kind: ConfigMap
metadata:
name: coredns
namespace: kube-system
配置解析
- 基础插件 :
errors(错误日志)、health(健康监测)等 - kubernetes 插件 :处理 Kubernetes 内部域名解析
test.com:指定集群域名后缀pods insecure:允许查询 Pod IP 对应的域名ttl 30:设置 DNS 记录的 TTL 为 30 秒
- forward 插件 :将非集群内部域名转发到
/etc/resolv.conf中配置的 DNS 服务器 - 其他插件 :
prometheus:提供监控指标cache:启用缓存(30 秒)loop:检测转发循环reload:允许配置自动更新loadbalance:提供简单的负载均衡
七、添加外部域名解析
通过修改 CoreDNS 配置,可以添加外部域名的解析规则:
-
获取当前配置:
shell
kubectl get cm coredns -n kube-system -o yaml > coredns-configmap.yaml -
编辑配置,添加 hosts 插件:
yaml
data: Corefile: | .:53 { errors health { lameduck 5s } ready kubernetes cluster.local in-addr.arpa ip6.arpa { pods insecure fallthrough in-addr.arpa ip6.arpa } hosts { 10.151.30.11 git.k8s.local fallthrough } prometheus :9153 forward . /etc/resolv.conf { max_concurrent 1000 } cache 30 loop reload loadbalance } -
应用配置:
shell
kubectl apply -f coredns-configmap.yaml -
重启 CoreDNS Pod:
shell
kubectl delete pod -n kube-system -l k8s-app=kube-dns -
验证配置:
shell
[root@k8s-master ~]# dig @10.96.0.10 git.k8s.local ; <<>> DiG 9.11.36-RedHat-9.11.36-14.el8_10 <<>> @10.96.0.10 git.k8s.local ; (1 server found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 51965 ;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1 ;; QUESTION SECTION: ;git.k8s.local. IN A ;; ANSWER SECTION: git.k8s.local. 30 IN A 10.151.30.11
通过以上配置,Kubernetes 集群内的 Pod 就可以解析自定义的外部域名了。