k8s入坑之路(10)kubernetes coredns詳解


概述

作為服務發現機制的基本功能,在集群內需要能夠通過服務名對服務進行訪問,那么就需要一個集群范圍內的DNS服務來完成從服務名到ClusterIP的解析。
DNS服務在kubernetes中經歷了三個階段。
第一階段,在kubernetes 1.2版本時,dns服務使用的是由SkyDNS提供的,由4個容器組成:kube2sky、skydns、etcd和healthz。etcd存儲dns記錄;kube2sky監控service變化,生成dns記錄;skydns讀取服務,提供查詢服務;healthz提供健康檢查
第二階段,在kubernetes 1.4版本開始使用kubedns,有3個容器組成:kubedns、dnsmasq和sidecar。kubedns監控service變化,並記錄到內存(存到內存提高性能)中;dnsmasq獲取dns記錄,提供dns緩存,提供dns查詢服務;sidecar提供健康檢查。
第三階段,從kubernetes 1.11版本開始,dns服務有coredns提供,coredns支持自定義dns記錄及配置upstream dns server,可以統一管理內部dns和物理dns。coredns只有一個coredns容器。下面是coredns的架構

 

 

 

coredns配置解析

下面是coredns的配置模板

.:53 {
        errors
        health {
           lameduck 5s
        }
        ready
        kubernetes cluster.local in-addr.arpa ip6.arpa {
           pods insecure
           fallthrough in-addr.arpa ip6.arpa
           ttl 30
        }
        hosts {
           172.23.1.3   hub.kellan.com
           fallthrough
        }
        prometheus :9153
        forward . /etc/resolv.conf {
           max_concurrent 1000
        }
        cache 30
        loop
        reload
        loadbalance
    }
coredns配置模板

coredns的主要功能是通過插件系統實現的。它實現了一種鏈式插件的結構,將dns的邏輯抽象成了一個個插件。常見的插件如下:

  • loadbalance:提供基於dns的負載均衡功能
  • loop:檢測在dns解析過程中出現的簡單循環問題
  • cache:提供前端緩存功能
  • health:對Endpoint進行健康檢查
  • kubernetes:從kubernetes中讀取zone數據
  • etcd:從etcd讀取zone數據,可以用於自定義域名記錄
  • file:從文件中讀取zone數據
  • hosts:使用/etc/hosts文件或者其他文件讀取zone數據,可以用於自定義域名記錄
  • auto:從磁盤中自動加載區域文件
  • reload:定時自動重新加載Corefile配置文件的內容
  • forward:轉發域名查詢到上游dns服務器
  • proxy:轉發特定的域名查詢到多個其他dns服務器,同時提供到多個dns服務器的負載均衡功能
  • prometheus:為prometheus系統提供采集性能指標數據的URL
  • pprof:在URL路徑/debug/pprof下提供運行是的西能數據
  • log:對dns查詢進行日志記錄
  • errors:對錯誤信息鏡像日志記錄

Pod的dns策略

上面已經描述了dns的服務端,那么pod有什么策略呢
目前的策略如下:

  • Default: 繼承Pod所在宿主機的DNS設置
  • ClusterFirst:優先使用kubernetes環境的dns服務,將無法解析的域名轉發到從宿主機繼承的dns服務器
  • ClusterFirstWithHostNet:和ClusterFirst相同,對於以hostNetwork模式運行的Pod應明確知道使用該策略
  • None: 忽略kubernetes環境的dns配置,通過spec.dnsConfig自定義DNS配置
    自定義Dns配置可以通過spec.dnsConfig字段進行設置,可以設置如下信息
    • nameservers:一組dns服務器的列表,最多可設置3個
    • searchs:一組用於域名搜索的dns域名后綴,最多6個
    • options:配置其他可選參數,例如ndots、timeout等
      例如:
 1 spec:
 2   dnsPolicy: "None"
 3   dnsConfig:
 4     nameservers:
 5       - 1.2.3.4
 6     searchs:
 7       - xx.ns1.svc.cluster.local
 8       - xx.daemon.com
 9     options:
10       - name: ndots
11         values: "2"

pod被創建后,容器內的/etc/resolv.conf會根據這個信息進行配置

nodelocaldns

架構圖如下

 

 

下面是nodelocaldns的configmap的示例

cluster.local:53 {
        errors
        cache {
            success 9984 30
            denial 9984 5
        }
        reload
        loop
        bind 169.254.25.10
        forward . 10.233.0.3 {
            force_tcp
        }
        prometheus :9253
        health 169.254.25.10:9254
    }
    in-addr.arpa:53 {
        errors
        cache 30
        reload
        loop
        bind 169.254.25.10
        forward . 10.233.0.3 {
            force_tcp
        }
        prometheus :9253
    }
    ip6.arpa:53 {
        errors
        cache 30
        reload
        loop
        bind 169.254.25.10
        forward . 10.233.0.3 {
            force_tcp
        }
        prometheus :9253
    }
    .:53 {
        errors
        cache 30
        reload
        loop
        bind 169.254.25.10
        forward . /etc/resolv.conf
        prometheus :9253
    }
View Code
可以看到配置和coredns是相仿的,就不再贅述。
但是這里要進一步說明下,通過配置可以看出除了cluster.local(即kubernetes集群的解析)外都使用節點的/etc/resolv.conf文件的nameserver。如果將自定義解析加到coredns上是沒有效果的,所以需要修改nodelocaldns的配置,將其他域名的解析轉到coredns上才行。

1   #forward . /etc/resolv.conf
2   forward . 10.233.0.3 {
3             force_tcp
4         }

Service

Service 通過標簽選擇 pod,將各 pod 的 ip 保存到它的 endpoints 屬性中。Service 的收到的請求會被均攤到這一組 endpoints 上。

DNS

在 k8s 中做服務發現,最常用的方式是通過 DNS 解析。

在我們的 k8s 集群配置了 dns 服務(最常用的是 coredns)的前提下,我們就可以直接通過全限定域名(FQDN)來訪問別的服務。

全限定域名的格式如下:

 

1 # 格式
2 <service-name>.<namespace>.svc.cluster.local  # 域名 .svc.cluster.local 是可自定義的
3 
4 # 舉例:訪問 default 名字空間下的 nginx 服務
5 nginx.default.svc.cluster.local

如果兩個服務在同一個名字空間內,可以省略掉后面的 .<namespace>.svc.cluster.local,直接以服務名稱為 DNS 訪問別的服務

P.S. DNS 服務發現的實現方式:修改每個容器的 /etc/resolv.conf,使容器訪問 k8s 自己的 dns 服務器。而該 dns 服務器知道系統中的所有服務,所以它能給出正確的響應。

SRV 記錄

Service 除了會使用最常見的 A 記錄做 Pod 的負載均衡外,還提供一種 SRV 記錄,這種類型的服務被稱為 Headless Service.

將 Service 的 spec.ClusterIP 設為 None,得到的就是一個 Headless Service。

普通的 Service 擁有自己的 ClusterIP 地址,service name 會被 DNS 解析到這個虛擬的 ClusterIP(A 記錄或 CNAME 記錄),然后被 kubectl proxy 轉發到具體的 Pod。

而 Headless Service 沒有自己的 ClusterIP(這個值被指定成了 None),service name 只提供 SRV 記錄的 DNS 解析,返回一個 Pods 的 ip/dns 列表。

SRV 記錄最常見的用途,是在有狀態集群中,給集群的所有 Pod 提供互相發現的功能。

最佳實踐

  1. 總是使用 Deployment,避免直接使用 ReplicaSet/Pod
  2. 為 Pod 的 Port 命名(比如命名成 http/https),然后在 Service 的 targetPort 中通過端口名稱(http/https)來指定目標端口(容器端口)。
    • 更直觀,也更靈活
  3. 應用通過 dns 查找/發現其他服務
    • 同一名字空間下的應用,可以直接以服務名稱為域名發現別的服務,如通過 http://nginx 訪問 nginx
  4. Service 配置會話親和性為 ClientIP 可能會更好(會話將被同一個 pod 處理,不會發生轉移)
  5. 配置 externalTrafficPolicy: Local 可以防止不必要的網絡跳數,但是可能會導致 pod 之間的流量分配不均。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM