1. 程式人生 > >kube-dns介紹

kube-dns介紹

近期研究了一個kube-dns多次重啟的問題,順便了解了一下kube-dns的原理,在此與大家分享。

注:本文內容均基於k8s 1.2.2版本

原理簡介

kube-dns用來為kubernetes service分配子域名,在叢集中可以通過名稱訪問service。通常kube-dns會為service賦予一個名為“service名稱.namespace.svc.cluster.local”的A記錄,用來解析service的cluster ip。

在實際應用中,如果訪問default namespace下的服務,則可以通過“service名稱”直接訪問。如果訪問其他namespace下的服務,則可以通過“service名稱.namespace”訪問。

我們可以通過以下yaml檔案來建立一個pod:

apiVersion: v1
kind: Pod
metadata:
  name: busybox
  namespace: default
spec:
  containers:
  - image: busybox
    command:
      - sleep
      - "3600"
    imagePullPolicy: IfNotPresent
    name: busybox
  restartPolicy: Always

查詢kubernetes service:

$ kubectl exec busybox -- nslookup kubernetes.default
Server: 10.0.0.10 Address 1: 10.0.0.10 Name: kubernetes.default Address 1: 10.0.0.1

配置

kube-dns服務可以手動建立,參考https://github.com/kubernetes/kubernetes/tree/v1.2.2/cluster/addons/dns 下的skydns-rc.yaml.in和skydns-svc.yaml.in。在skydns-svc中設定kube-dns的cluster ip,在skydns-rc中設定本地域名。通常設定為10.0.0.10和cluster.local。之後通過kubectl create便可以建立kube-dns服務了。

kubelet相應的引數為:

--cluster-dns=<DNS service ip>
--cluster-domain=<default local domain>

k8s會為每個容器提供預設的/etc/resolv.conf配置,內容為:

search default.svc.cluster.local svc.cluster.local cluster.local
nameserver 10.0.0.10
options ndots:5

當我們在容器中訪問服務時,系統會將search記錄與我們指定的名稱拼接,並在nameserver中解析dns。如使用上述配置,當使用“service名稱”訪問服務時,最終會使用default.svc.cluster.local這條search記錄拼接完整的服務名稱,當使用“service名稱.namespace”時,最終會使用svc.cluster.local這條search記錄。cluster.local這條記錄是為了相容舊版本的服務,因為svc子域名在早期版本是沒有的。

pod組成

kube-dns pod由四個容器組成,skydns、etcd、kube2sky和healthz:

  • skydns用來提供dns查詢服務,它使用etcd作為儲存。dns記錄需要使用etcd api或etcdctl新增到etcd中。
  • etcd用來為skydns提供儲存服務。
  • kube2sky是k8s與skydns之間的橋樑,它會監聽k8s service的修改,並生成對應的dns記錄儲存到etcd中。此外還會在啟動成功後監聽8081埠,以便k8s readiness probe呼叫。
  • healthz用來檢測skydns的可用性,它會定期執行nslookup指令訪問skydns。
  • kube2sky主要使用了k8s.io/kubernetes/pkg/controller/framework的NewInformer方法來監聽service,並設定了新增、刪除、修改事件的回撥,在回撥中修改etcd儲存的dns記錄。
  • NewInformer方法的其中一個返回值是k8s.io/kubernetes/pkg/client/cache的Store例項,可看做是一個本地快取。當監聽的資源發生變更時,k8s.io/kubernetes/pkg/controller/framework會將Store例項自動更新,這樣當事件觸發時可以在回撥中使用Store例項來查詢資源而不用實時查詢k8s API,從而提高效率。
  • 事件監聽是通過對應資源的watch API和定期呼叫list API來實現的,watch API提供了流式的通知功能,呼叫list API可以週期性的全量查詢,避免遺漏通知。
  • 每隔一段時間(period引數,預設2秒)執行指定的shell指令(cmd引數)
  • 提供一個http服務(port引數,預設監聽8080埠)來查詢最近一次shell指令的執行情況,執行失敗或超時(latency引數,預設30秒)返回503錯誤。
  • 查詢地址為host:port/healthz
  • 高版本的healthz還提供了quiet引數,可以減少不必要的日誌輸出。

kube-dns pod使用healthz提供的http服務設定了liveness probe來實現活性檢測。這次碰到的重啟問題就是由於healthz執行nslookup超時導致活性檢查失敗而觸發了重啟(最近測試伺服器貌似資源不足了,經常卡出翔)。

除錯

1.我們可以在叢集中使用busybox建立的pod來檢查service的dns是否生效,可參考第一節中的示例。

2.也可以訪問kube-dns pod中的etcd容器來檢視dns記錄,使用以下指令進入到容器中:

$ kubectl exec -ti -c etcd <kube-dns-pod-name> --namespace=kube-system -- sh

在容器中執行etcdctl get或etcdctl ls來檢視資料,dns所有記錄都存在/skydns目錄下。skydns會將域名順序倒置並使用“/”替換“.”來生成etcd key的路徑,例如kube-dns.kube-system.svc.cluster.local對應的路徑為local/cluster/svc/kube-system/kube-dns/。在該路徑下會有一個自動生成的隨機名稱的檔案,檢視該檔案就可以看到dns記錄了。

$ etcdctl ls /skydns/local/cluster/svc/kube-system/kube-dns

/skydns/local/cluster/svc/kube-system/kube-dns/21172049

$ etcdctl get /skydns/local/cluster/svc/kube-system/kube-dns/21172049

{"host":"10.0.0.10","priority":10,"weight":10,"ttl":30,"targetstrip":0}

3.如需要除錯kube2sky,可以修改原始碼之後新建一個帶有kube2sky和etcd容器的pod,kube2sky會自動查詢k8s叢集資訊並寫入到etcd中,這樣不會影響kube-system名稱空間下的kube-dns服務,還可以檢視etcd記錄是否正確以及列印除錯日誌。