kubernetes 簡介:kube-dns 和服務發現

服務發現

kubernetes 提供了 service 的概念能夠經過 VIP 訪問 pod 提供的服務,可是在使用的時候還有一個問題:怎麼知道某個應用的 VIP?好比咱們有兩個應用,一個 app,一個 是 db,每一個應用使用 rc 進行管理,並經過 service 暴露出端口提供服務。app 須要鏈接到 db 應用,咱們只知道 db 應用的名稱,可是並不知道它的 VIP 地址。css

最簡單的辦法是從 kubernetes 提供的 API 查詢。但這是一個糟糕的作法,首先每一個應用都要在啓動的時候編寫查詢依賴服務的邏輯,這自己就是重複和增長應用的複雜度;其次這也致使應用須要依賴 kubernetes,不可以單獨部署和運行(固然若是經過增長配置選項也是能夠作到的,但這又是增長負責度)。html

開始的時候,kubernetes 採用了 docker 使用過的方法——環境變量。每一個 pod 啓動時候,會把經過環境變量設置全部服務的 IP 和 port 信息,這樣 pod 中的應用能夠經過讀取環境變量來獲取依賴服務的地址信息。這種方式服務和環境變量的匹配關係有必定的規範,使用起來也相對簡單,可是有個很大的問題:依賴的服務必須在 pod 啓動以前就存在,否則是不會出如今環境變量中的。git

更理想的方案是:應用可以直接使用服務的名字,不須要關心它實際的 ip 地址,中間的轉換可以自動完成。名字和 ip 之間的轉換就是 DNS 系統的功能,所以 kubernetes 也提供了 DNS 方法來解決這個問題。github

部署 DNS 服務

DNS 服務不是獨立的系統服務,而是一種 addon ,做爲插件來安裝的,不是 kubernetes 集羣必須的(可是很是推薦安裝)。能夠把它看作運行在集羣上的應用,只不過這個應用比較特殊而已。sql

DNS 有兩種配置方式,在 1.3 以前使用 etcd + kube2sky + skydns 的方式,在 1.3 以後可使用 kubedns + dnsmasq 的方式。docker

修改 kubelet 啓動參數

無論以什麼方式啓動,對外的效果是同樣的。要想使用 DNS 功能,還須要修改 kubelet的啓動配置項,告訴 kubelet,給每一個啓動的 pod 設置對應的 DNS 信息,一共有兩個參數:--cluster_dns=10.10.10.10 --cluster_domain=cluster.local,分別是 DNS 在集羣中的 vip 和域名後綴,要和 DNS rc 中保持一致。bootstrap

skydns

下面是這種方式的部署配置文件:api

apiVersion: v1
kind: ReplicationController
metadata:
  labels:
    k8s-app: kube-dns
    kubernetes.io/cluster-service: "true" name: kube-dns namespace: kube-system spec: replicas: 1 selector: k8s-app: kube-dns template: metadata: labels: k8s-app: kube-dns kubernetes.io/cluster-service: "true" spec: containers: - name: etcd command: - /usr/local/bin/etcd - "-listen-client-urls" - "http://127.0.0.1:2379,http://127.0.0.1:4001" - "-advertise-client-urls" - "http://127.0.0.1:2379,http://127.0.0.1:4001" - "-initial-cluster-token" - skydns-etcd image: "gcr.io/google_containers/etcd:2.0.9" resources: limits: cpu: 100m memory: 50Mi - name: kube2sky args: - "-domain=cluster.local" - "-kube_master_url=http://10.7.114.81:8080" image: "gcr.io/google_containers/kube2sky:1.11" resources: limits: cpu: 100m memory: 50Mi - name: skydns args: - "-machines=http://localhost:4001" - "-addr=0.0.0.0:53" - "-domain=cluster.local" image: "gcr.io/google_containers/skydns:2015-03-11-001" livenessProbe: exec: command: - /bin/sh - "-c" - "nslookup kubernetes.default.svc.cluster.local localhost >/dev/null" initialDelaySeconds: 30 timeoutSeconds: 5 ports: - containerPort: 53 name: dns protocol: UDP - containerPort: 53 name: dns-tcp protocol: TCP resources: limits: cpu: 100m memory: 50Mi dnsPolicy: Default 

這裏有兩個須要根據實際狀況配置的地方:緩存

  • kube_master_url: kube2sky 會用到 kubernetes master API,它會讀取裏面的 service 信息
  • domain:域名後綴,默認是 cluster.local,你能夠根據實際須要修改爲任何合法的值

而後是 Service 的配置文件:bash

apiVersion: v1
kind: Service
metadata:
  name: kube-dns
  namespace: kube-system labels: k8s-app: kube-dns kubernetes.io/cluster-service: "true" kubernetes.io/name: "KubeDNS" spec: selector: k8s-app: kube-dns clusterIP: 10.10.10.10 ports: - name: dns port: 53 protocol: UDP - name: dns-tcp port: 53 protocol: TCP 

這裏須要注意的是 clusterIP: 10.10.10.10 這一行手動指定了 DNS service 的 IP 地址,這個地址必須在預留的 vip 網段。手動指定的緣由是爲了固定這個 ip,這樣啓動 kubelet 的時候配置 --cluster_dns=10.10.10.10 比較方便,不須要再動態獲取 DNS 的 vip 地址。

有了這兩個文件,直接建立對象就行:

$ kubectl create -f ./skydns-rc.yml $ kubectl create -f ./skydns-svc.yml [root@localhost ~]# kubectl get svc,rc,pod --namespace=kube-system NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE svc/kube-dns 10.10.10.10 <none> 53/UDP 1d NAME DESIRED CURRENT READY AGE rc/kube-dns 1 1 1 41m NAME READY STATUS RESTARTS AGE po/kube-dns-twl0q 3/3 Running 0 41m 

kubeDNS

在 kubernetes 1.3 版本以後,kubernetes 改變了 DNS 的部署方式,變成了 kubeDNS + dnsmasq,沒有了 etcd 。在這種模式下,kubeDNS 是原來 kube2sky + skyDNS + etcd,只不過它把數據都保存到本身的內存,而不是 kv store 中;dnsmasq 的引進是爲了提升解析的速度,由於它能夠配置 DNS 緩存。

這種部署方式的完整配置文件這裏就不貼出來了,我放到了 github gist 上面,有興趣能夠查看。建立方法也是同樣 kubectl create -f ./skydns-rc.yml

測試 DNS 可用性

無論那種部署非常,kubernetes 對外提供的 DNS 服務是一致的。每一個 service 都會有對應的 DNS 記錄,kubernetes 保存 DNS 記錄的格式以下:

<service_name>.<namespace>.svc.<domain> 

每一個部分的字段意思:

  • service_name: 服務名稱,就是定義 service 的時候取的名字
  • namespace:service 所在 namespace 的名字
  • domain:提供的域名後綴,好比默認的 cluster.local

在 pod 中能夠經過 service_name.namespace.svc.domain 來訪問任何的服務,也可使用縮寫 service_name.namespace,若是 pod 和 service 在同一個 namespace,甚至能夠直接使用 service_name

NOTE:正常的 service 域名會被解析成 service vip,而 headless service 域名會被直接解析成背後的 pods ip。

雖然不會常常用到,可是 pod 也會有對應的 DNS 記錄,格式是 pod-ip-address.<namespace>.pod.<domain>,其中 pod-ip-address 爲 pod ip 地址的用 - 符號隔開的格式,好比 pod ip 地址是 1.2.3.4 ,那麼對應的域名就是 1-2-3-4.default.pod.cluster.local

咱們運行一個 busybox 來驗證 DNS 服務可以正常工做:

/ # nslookup whoami Server: 10.10.10.10 Address 1: 10.10.10.10 Name: whoami Address 1: 10.10.10.175 / # nslookup kubernetes Server: 10.10.10.10 Address 1: 10.10.10.10 Name: kubernetes Address 1: 10.10.10.1 / # nslookup whoami.default.svc Server: 10.10.10.10 Address 1: 10.10.10.10 Name: whoami.default.svc Address 1: 10.10.10.175 / # nslookup whoami.default.svc.transwarp.local Server: 10.10.10.10 Address 1: 10.10.10.10 Name: whoami.default.svc.transwarp.local Address 1: 10.10.10.175 

能夠看出,若是咱們在默認的 namespace default 建立了名爲 whoami 的服務,如下全部域名都能被正確解析:

whoami whoami.default.svc whoami.default.svc.cluster.local 

每一個 pod 的 DNS 配置文件以下,能夠看到 DNS vip 地址以及搜索的 domain 列表:

/ # cat /etc/resolv.conf search default.pod.cluster.local default.svc.cluster.local svc.cluster.local cluster.local nameserver 10.10.10.10 options ndots:5 options ndots:5 

kubernetes DNS 原理解析

咱們前面介紹了兩種不一樣 DNS 部署方式,這部分講講它們內部的原理。

kube2sky 模式

這種模式下主要有三個容器在運行:

[root@localhost ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 919cbc006da2 172.16.1.41:5000/google_containers/kube2sky:1.12 "/kube2sky /kube2sky " About an hour ago Up About an hour k8s_kube2sky.80a41edc_kube-dns-twl0q_kube-system_ea1f5f4d-15cf-11e7-bece-080027c09e5b_1bd3fdb4 73dd11cac057 172.16.1.41:5000/jenkins/etcd:live "etcd -data-dir=/var/" About an hour ago Up About an hour k8s_etcd.4040370_kube-dns-twl0q_kube-system_ea1f5f4d-15cf-11e7-bece-080027c09e5b_b0e5a99f 0b10ae639989 172.16.1.41:5000/jenkins/skydns:20150703-113305 "bootstrap.sh" About an hour ago Up About an hour k8s_skydns.73baf3b1_kube-dns-twl0q_kube-system_ea1f5f4d-15cf-11e7-bece-080027c09e5b_2860aa6d 

這三個容器的做用分別是:

  • etcd:保存全部的 DNS 數據
  • kube2sky: 經過 kubernetes API 監聽 Service 的變化,而後同步到 etcd
  • skyDNS:根據 etcd 中的數據,對外提供 DNS 查詢服務

kubeDNS 模式

這種模式下,kubeDNS 容器替代了原來的三個容器的功能,它會監聽 apiserver 並把全部 service 和 endpoints 的結果在內存中用合適的數據結構保存起來,並對外提供 DNS 查詢服務。

  • kubeDNS:提供了原來 kube2sky + etcd + skyDNS 的功能,能夠單獨對外提供 DNS 查詢服務
  • dnsmasq: 一個輕量級的 DNS 服務軟件,能夠提供 DNS 緩存功能。kubeDNS 模式下,dnsmasq 在內存中預留一塊大小(默認是 1G)的地方,保存當前最經常使用的 DNS 查詢記錄,若是緩存中沒有要查找的記錄,它會到 kubeDNS 中查詢,並把結果緩存起來

每種模式均可以運行額外的 exec-healthz 容器對外提供 health check 功能,證實當前 DNS 服務是正常的。

  • exec-healthz:運行某個命令,根據結果來對外提供 /healthz 結果

總結

推薦使用 kubeDNS 的模式來部署,由於它有着如下的好處:

  • 不須要額外的存儲,省去了額外的維護和數據保存的工做
  • 更好的性能。經過 dnsmasq 緩存和直接把 DNS 記錄保存在內存中,來提升 DNS 解析的速度

參考資料

http://cizixs.com/2017/04/11/kubernetes-intro-kube-dns

http://jingyan.baidu.com/article/72ee561a6e2460e16138dff7.html

源碼分析

http://blog.csdn.net/u010278923/article/details/70173635

相關文章
相關標籤/搜索