K8s集群中的DNS服务(CoreDNS)详解

概述

官网文档:https://kubernetes.io/zh-cn/docs/concepts/services-networking/dns-pod-service/

在 Kubernetes(K8s)中,DNS 服务是实现服务发现和 Pod 通信的核心组件之一,用于解决集群内资源通过域名而非 IP 地址进行访问的需求。本文将详细解析 K8s DNS 服务的原理、组件、配置及应用场景。

K8s DNS的作用

服务发现

  • 允许 Pod 通过服务名称(Service Name)而非动态变化的 IP 地址访问其他服务,简化网络配置。
  • 支持跨命名空间(Namespace)的服务访问,通过域名后缀区分不同作用域。

Pod 通信

  • 每个 Pod 自动获取 DNS 配置,可直接通过主机名(Hostname)或服务名进行通信。

解耦服务依赖

  • 服务的 IP 地址变更时,DNS 会自动更新解析结果,避免手动维护 IP 列表。

核心组件:CoreDNS(替代传统 kube-dns)

K8s 早期使用kube-dns作为 DNS 服务器,目前默认采用CoreDNS,因其更轻量、灵活且支持插件机制。

CoreDNS的安装

如果使用kubeadm部署集群,CoreDNS 会自动部署在kube-system命名空间下,如果需要进行部署,可以使用下面的文件:

复制代码
kubectl apply -f https://github.com/kubernetes/kubernetes/blob/master/cluster/addons/dns/coredns/coredns.yaml.base

部署CoreDNS通常包含

  • StatefulSet/Deployment:定义 CoreDNS Pod 副本。

    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: coredns
    namespace: kube-system
    spec:
    replicas: 2 # 默认2个副本,确保高可用
    selector:
    matchLabels:
    k8s-app: kube-dns # 历史遗留标签,兼容旧版kube-dns
    template:
    metadata:
    labels:
    k8s-app: kube-dns
    spec:
    containers:
    - name: coredns
    image: coredns/coredns:v1.10.1 # CoreDNS版本
    args: [ "-conf", "/etc/coredns/Corefile" ]
    ports:
    - containerPort: 53
    name: dns
    protocol: UDP
    - containerPort: 53
    name: dns-tcp
    protocol: TCP
    volumeMounts:
    - name: config-volume
    mountPath: /etc/coredns
    volumes:
    - name: config-volume
    configMap:
    name: coredns
    items:
    - key: Corefile
    path: Corefile

  • Service:暴露 CoreDNS 服务,供集群内 Pod 访问(默认 IP 为10.96.0.10)。

    apiVersion: v1
    kind: Service
    metadata:
    name: kube-dns
    namespace: kube-system
    spec:
    selector:
    k8s-app: kube-dns
    clusterIP: 10.96.0.10 # 默认集群IP,Pod的nameserver配置指向此IP
    ports:
    - name: dns
    port: 53
    protocol: UDP
    - name: dns-tcp
    port: 53
    protocol: TCP

  • ConfigMap:存储 Corefile 配置。

    .:53 { #表示监听所有接口的 53 端口(DNS 标准端口)。
    errors # 记录错误日志
    health {
    lameduck 5s # 健康检查,延迟5秒标记不健康
    }
    ready # 提供 readiness 探针端点(/ready),指示 CoreDNS 是否准备好处理请求
    kubernetes cluster.local in-addr.arpa ip6.arpa {
    fallthrough in-addr.arpa ip6.arpa # 未匹配到K8s服务时,透传给下一个插件
    ttl 30 # DNS记录的TTL时间
    }
    prometheus :9153 # 暴露Prometheus监控指标
    forward . /etc/resolv.conf # 转发外部域名查询到宿主机的DNS服务器
    cache 30 # 缓存查询结果30秒
    loop # 检测配置循环引用
    reload # 自动重新加载配置变更
    loadbalance # 对A/AAAA记录进行负载均衡
    }

CoreDNS的组成

  • CoreDNS Pod:运行 CoreDNS 服务,监听 DNS 请求(默认端口 53)。

    [root@master ~]# kubectl get po -o wide -n kube-system
    NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
    coredns-787d4945fb-jb4t9 1/1 Running 1 (2d23h ago) 9d 100.117.144.135 node01 <none> <none>
    coredns-787d4945fb-z47x7 1/1 Running 1 (2d23h ago) 9d 100.117.144.138 node01 <none> <none>

  • Service 资源:为 CoreDNS Pod 暴露集群内部服务,名称为kube-dns(或coredns,取决于部署方式),IP 通常为10.96.0.10(集群 IP 范围)。

    [root@master ~]# 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 9d

    [root@master ~]# 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: 100.117.144.135:53,100.117.144.138:53
    Port: dns-tcp 53/TCP
    TargetPort: 53/TCP
    Endpoints: 100.117.144.135:53,100.117.144.138:53
    Port: metrics 9153/TCP
    TargetPort: 9153/TCP
    Endpoints: 100.117.144.135:9153,100.117.144.138:9153
    Session Affinity: None
    Events: <none>

  • ConfigMap 配置:通过 ConfigMap 定义 CoreDNS 的解析规则和插件。

    [root@master ~]# kubectl describe cm coredns -n kube-system
    Name: coredns
    Namespace: kube-system
    Labels: <none>
    Annotations: <none>

    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
    forward . /etc/resolv.conf {
    max_concurrent 1000
    }
    cache 30
    loop
    reload
    loadbalance
    }

    BinaryData

    Events: <none>

CoreDNS域名解析规则

K8s集群中Pod之间通过域名互相访问需要遵守特定的规则,规则如下

复制代码
<service-name>.<namespace>.svc.<cluster-domain>
  • service-name:表示service的名称
  • namespace:service所在的命名空间
  • cluster-domain:集群的域名,默认为cluster.local

cluster-domain从哪儿获取?

复制代码
[root@master ~]# grep clusterDomain /var/lib/kubelet/config.yaml 
clusterDomain: cluster.local

CoreDNS实战案例

验证同一个命名空间下的CoreDNS访问

创建两个Pod和Service

复制代码
## 第一个Pod和 Service
[root@master ~/coredns]# cat test-1.yaml
apiVersion: v1
kind: Pod
metadata:
  name: dns-target-pod
  labels:
    app: dns-test
spec:
  containers:
  - name: busybox
    image: busybox
    command: ["sh", "-c", "while true; do sleep 3600; done"]
---
apiVersion: v1
kind: Service
metadata:
  name: dns-target-service
spec:
  type: ClusterIP
  selector:
    app: dns-test
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80

[root@master ~/coredns]# kubectl apply -f test-1.yaml
pod/dns-target-pod unchanged
service/dns-target-service created

# 第二个Pod和Service
[root@master ~/coredns]# cat test-2.yaml
apiVersion: v1
kind: Pod
metadata:
  name: dns-source-pod
  labels:
    app: dns-source-test
spec:
  containers:
  - name: busybox
    image: busybox
    command: ["sh", "-c", "while true; do sleep 3600; done"]
---
apiVersion: v1
kind: Service
metadata:
  name: dns-source-service
spec:
  type: ClusterIP
  selector:
    app: dns-source-test
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80

[root@master ~/coredns]# kubectl apply -f test-2.yaml
pod/dns-source-pod created
service/dns-source-service created

# 检查一下
[root@master ~/coredns]# kubectl get po,svc
NAME                 READY   STATUS    RESTARTS   AGE
pod/dns-source-pod   1/1     Running   0          111s
pod/dns-target-pod   1/1     Running   0          8s

NAME                         TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)   AGE
service/dns-source-service   ClusterIP   10.96.0.192   <none>        80/TCP    81s
service/dns-target-service   ClusterIP   10.96.3.51    <none>        80/TCP    3m56s

验证DNS

复制代码
[root@master ~/coredns]# kubectl exec -it pod/dns-source-pod -- sh
/ # nslookup dns-target-service.default.svc.cluster.local
Server:         10.96.0.10
Address:        10.96.0.10:53


Name:   dns-target-service.default.svc.cluster.local
Address: 10.96.3.51

验证在不同命名空间下的DNS访问

示例:

复制代码
# 创建一个新的命名空间
[root@master ~/coredns]# kubectl create ns coredns
namespace/coredns created
[root@master ~/coredns]# kubectl get ns coredns
NAME      STATUS   AGE
coredns   Active   15s

创建Pod和Service进行验证

复制代码
[root@master ~/coredns]# cat test-3.yaml
apiVersion: v1
kind: Pod
metadata:
  name: dns-coredns-pod
  namespace: coredns
  labels:
    app: dns-coredns-test
spec:
  containers:
  - name: busybox
    image: busybox
    command: ["sh", "-c", "while true; do sleep 3600; done"]
---
apiVersion: v1
kind: Service
metadata:
  name: dns-coredns-service
  namespace: coredns
spec:
  type: ClusterIP
  selector:
    app: dns-coredns-test
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80

[root@master ~/coredns]# kubectl apply -f test3.yaml
pod/dns-coredns-pod created
service/dns-coredns-service created

[root@master ~]# kubectl get all -n coredns
NAME                  READY   STATUS    RESTARTS   AGE
pod/dns-coredns-pod   1/1     Running   0          4m36s

NAME                          TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)   AGE
service/dns-coredns-service   ClusterIP   10.96.0.119   <none>        80/TCP    4m36s

进行验证

复制代码
[root@master ~/coredns]# kubectl exec -it dns-target-pod -- sh
/ # nslookup dns-coredns-service.coredns.svc.cluster.local
Server:         10.96.0.10
Address:        10.96.0.10:53

Name:   dns-coredns-service.coredns.svc.cluster.local
Address: 10.96.0.119