kubernetes域名解析服务CoreDNS

  k8s dns组件历史简介

  kubernetes的DNS组件历史有三个,分别是skydns、kube-dns和coredns;在k8s 1.3版本之前使用的是skydns,之后的版本到1.17及之间的版本都是使用的kube-dns,1.18开始至今主要使用coredns;这些dns组件在k8s当中,主要作用就是解析k8s中service name所对应的IP地址,即在k8s内部做service name解析,使得我们在k8s内部访问各自服务名称能够拿到对应服务后面pod的IP地址;当然这些dns组件除了可以解析内部service name,它也能解析互联网域名;

  CoreDNS简介

  CoreDNS是一个可扩展的DNS服务器,支持标准DNS,标准(但不广泛) 采用基于TLS的DNS和基于gRPC协议的非标准DNS。它的主要特点是插件系统,它允许您执行任何操作来响应可以在Go中编码的DNS查询。Miek Gieben在2016年编写了CoreDNS 的初始版本,在此之前他还写过SkyDNS,以及一个用Go语言编写的DNS函数库Go DNS。与它的继任者CoreDNS一样,SkyDNS的主要目的也是支持服务发现。Miek非常欣赏一个基于Go的网络服务器架构 Caddy,所以他就选用Caddy构建了CoreDNS。CoreDNS继承了Caddy的主要优点是简单的配置语法、强大的基于插件的架构以及 Go 语言。在k8s中,CoreDNS作为一个服务发现的配置中心,我们在K8s中创建的Service和Pod都会在其中自动生成相应的DNS记录。k8s服务发现的特性,使CoreDNS很适合作为企业云原生环境的DNS服务器,保障企业容器化和非容器化业务服务的稳定运行。

  CoreDNS项目托管在github地址:https://github.com/coredns/coredns

  官方网站:https://coredns.io

  插件介绍:https://coredns.io/plugins/;

  CoreDNS运行原理与插件

  提示:如上图所示,CoreDNS是基于Caddy框架实现模块化设计,每个插件实现不同的功能,如forward插件实现转发功能,etcd插件实现去etcd中获取zone信息,file插件实现在某个文件中获取zone信息, Kubernetes插件实现集群服务发现;

  提示:外部DNS请求到达CoreDNS后,根据插件调用链依次处理DNS请求。

  coredns在k8s之上的部署清单

apiVersion: v1
kind: ServiceAccount
metadata:
  name: coredns
  namespace: kube-system
  labels:
      kubernetes.io/cluster-service: "true"
      addonmanager.kubernetes.io/mode: Reconcile
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  labels:
    kubernetes.io/bootstrapping: rbac-defaults
    addonmanager.kubernetes.io/mode: Reconcile
  name: system:coredns
rules:
- apiGroups:
  - ""
  resources:
  - endpoints
  - services
  - pods
  - namespaces
  verbs:
  - list
  - watch
- apiGroups:
  - ""
  resources:
  - nodes
  verbs:
  - get
- apiGroups:
  - discovery.k8s.io
  resources:
  - endpointslices
  verbs:
  - list
  - watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"
  labels:
    kubernetes.io/bootstrapping: rbac-defaults
    addonmanager.kubernetes.io/mode: EnsureExists
  name: system:coredns
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: system:coredns
subjects:
- kind: ServiceAccount
  name: coredns
  namespace: kube-system
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: coredns
  namespace: kube-system
  labels:
      addonmanager.kubernetes.io/mode: EnsureExists
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 {
        forward . 223.6.6.6 {
            max_concurrent 1000
        }
        cache 600
        loop
        reload
        loadbalance
    }
        myserver.online {
          forward . 172.16.16.16:53
        }

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: coredns
  namespace: kube-system
  labels:
    k8s-app: kube-dns
    kubernetes.io/cluster-service: "true"
    addonmanager.kubernetes.io/mode: Reconcile
    kubernetes.io/name: "CoreDNS"
spec:
  # replicas: not specified here:
  # 1. In order to make Addon Manager do not reconcile this replicas parameter.
  # 2. Default is 1.
  # 3. Will be tuned in real time if DNS horizontal auto-scaling is turned on.
  replicas: 2
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1
  selector:
    matchLabels:
      k8s-app: kube-dns
  template:
    metadata:
      labels:
        k8s-app: kube-dns
    spec:
      securityContext:
        seccompProfile:
          type: RuntimeDefault
      priorityClassName: system-cluster-critical
      serviceAccountName: coredns
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                  - key: k8s-app
                    operator: In
                    values: ["kube-dns"]
              topologyKey: kubernetes.io/hostname
      tolerations:
        - key: "CriticalAddonsOnly"
          operator: "Exists"
      nodeSelector:
        kubernetes.io/os: linux
      containers:
      - name: coredns
        image: harbor.ik8s.cc/baseimages/coredns:1.9.4
        imagePullPolicy: IfNotPresent
        resources:
          limits:
            memory: 256Mi 
            cpu: 200m
          requests:
            cpu: 100m
            memory: 70Mi
        args: [ "-conf", "/etc/coredns/Corefile" ]
        volumeMounts:
        - name: config-volume
          mountPath: /etc/coredns
          readOnly: true
        ports:
        - containerPort: 53
          name: dns
          protocol: UDP
        - containerPort: 53
          name: dns-tcp
          protocol: TCP
        - containerPort: 9153
          name: metrics
          protocol: TCP
        livenessProbe:
          httpGet:
            path: /health
            port: 8080
            scheme: HTTP
          initialDelaySeconds: 60
          timeoutSeconds: 5
          successThreshold: 1
          failureThreshold: 5
        readinessProbe:
          httpGet:
            path: /ready
            port: 8181
            scheme: HTTP
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            add:
            - NET_BIND_SERVICE
            drop:
            - all
          readOnlyRootFilesystem: true
      dnsPolicy: Default
      volumes:
        - name: config-volume
          configMap:
            name: coredns
            items:
            - key: Corefile
              path: Corefile
---
apiVersion: v1
kind: Service
metadata:
  name: kube-dns
  namespace: kube-system
  annotations:
    prometheus.io/port: "9153"
    prometheus.io/scrape: "true"
  labels:
    k8s-app: kube-dns
    kubernetes.io/cluster-service: "true"
    addonmanager.kubernetes.io/mode: Reconcile
    kubernetes.io/name: "CoreDNS"
spec:
  selector:
    k8s-app: kube-dns
  clusterIP: 10.100.0.2
  ports:
  - name: dns
    port: 53
    protocol: UDP
  - name: dns-tcp
    port: 53
    protocol: TCP
  - name: metrics
    port: 9153
    protocol: TCP

  提示:上述主要定义了coredns在k8s之上的授权和准入控制以及coredns pods、插件和service相关部署清单;这里需要说明一点,coredns作为k8s的域名解析服务以及服务发现组件,在k8s上它无需对k8s资源做任何修改操作,只拥有读取和watch权限;即只要对应pod信息或service信息发生变动都会触发coredns来获取数据,从而实现对应pods或service资源变动能及时反馈在coredns的a记录中;

  CoreDNS在k8s之上实现服务发现逻辑

  我知道在k8s集群之上,所有k8s资源信息(如,configmap,secret,service等),pod状态信息都存放在etcd数据库中;而连接etcd只有apiserver才可以,所以coredns要想实现在k8s之上服务发现,首先要连接到k8s集群;即通过k8sapiserver连接到etcd的中获取对应service和pod的相关信息,生成dns a记录;那coredns是怎么连接到k8s集群之上的呢?在部署coredns插件时,我们会在k8s上先创建一个sa(ServiceAccount)资源,即服务账号,然后创建一个Cluster Role,这个clusterrole主要就是对coredns做准入控制和授权、最后创建一个clusterrolebingding将clusterrole和serviceaccout做绑定;有了上述的三个资源,对应coredns就有权限通过apiserver连接至etcd集群获取service和对应pod等资源的相关信息;服务发现主要是基于对etcd中pod信息和service信息的watch机制实现的,应用上述授权后,k8s上的pod或service资源变动都会触发coredns来更新数据;对于k8s集群来说,其他任何第三方客户端来连接k8s集群都是通过apiserver对外提供的服务来实现的;在k8s上apiserver提供服务的接口有两种,一种是基于监听宿主机端口通过验证客户端证书的方式,这种一般常用于集群外部客户端连接管理k8s集群使用;除此之外,k8s集群内部会也会有一个kubernetes的服务,它是以k8s service资源的方式提供服务,即在k8s内部通过cluster IP 的方式生成iptables或ipvs规则来转发内部客户端连接k8s的请求至对应master主机apiserver监听的端口之上;如下

  提示:在k8s内部通过访问10.100.0.1这个地址的443端口,就能实现将请求转发各master之上的apiserver监听的6443端口上;

  CoreDNS配置

  coredns插件功能描述

  errors:该插件主要用于将错误信息标准输出;

  health:该插件主要用于在CoreDNS的http://localhost:8080/health端口提供CoreDNS服务的健康报告;

  ready:该插件监听在tcp的8181端口,当coredns的插件都已准备就绪时,访问该接口会返回200状态码ok;

  kubernetes:该插件主要用于coredns连接k8s集群获取pods,namespaces,services,endpoints等信息,以及CoreDNS 将基于 kubernetes service name进行DNS查询并返回查询记录给客户端;该插件也是实现在k8s之上服务发现的关键;  kubernetes cluster.local这个配置就是coredns收到cluster.local的查询都会转发至kubenetes进行查询;

  prometheus:该插件主要用于收集CoreDNS的度量指标数据以Prometheus的key-value的格式在http://localhost:9153/metrics 的url上提供;

  forward:该插件主要用于将那些不是k8s集群内部的其他任何域名的查询请求转发到预定义的dns服务器上;

  cache:该插件主要用于启用service解析缓存,单位为秒;

  loop:该插件主要用于检测域名解析是否有死循环,如果发现解析是死循环,则强制终止coredns进程,让k8s重建coredns pod;

  reload:该插件主要用于检测corefile是否更改,在重新编辑configmap配置文件后,默认2分钟会自动加载对应configmap配置文件;

  loadbalance:该插件主要定义轮训DNS域名解析, 如果一个域名存在多个记录则轮训解析;

  扩展:基于nodeLocal DNScache相关说明

  提示:本地dns缓存的主要作用是大规模集群pod或service资源的频繁改动导致dns查询而带来的性能损耗;它的工作原理就是在pod进行dns解析时,会首先联系localdns,如果缓存命中,则返回,然后对应pod拿着返回的信息去和对应IP地址通信,只有当localdns本地没有缓存,此时localdns才会向上转发;简单讲这种方式主要用来分担coredns压力和提高pod查询效率缩短查询路径;这里需要注意一点,在k8s中,虽然使用的是coredns,但是coredns对应服务名称为kube-dns,这个是历史遗留,其他第三方插件都是使用这个名称,所以就保留了这个kube-dns的服务名称;

  pod基于coredns进行域名解析

  解析kubenetes服务

  提示:在pod内部执行解析kubenetes服务,首先通过/etc/resolv.conf文件中的搜索域将对应域名全部补齐,然后再将这个全域名名称再coredns中进行查询,最终coredns通过连接apiserver到etcd中检索kubernetes服务IP地址返回给nslookup客户端;

  解析kube-dnsIP地址

  提示:默认情况下,pod的dns搜索域只会在pod所在名称空间下搜索,如果我们查询的域名跨名称空间,需要手动给出对应名称空间名称,即包含服务名,名称空间的域名; 

posted @ 2023-05-06 12:47  Linux-1874  阅读(1007)  评论(0编辑  收藏  举报