-
先吐槽一下,最近研究k8s的dns,看了很多相關博客,發現很多都是一樣的內容,大部分都是轉載或者copy,也不驗證一下就發出來,給我無形中挖了很多坑。再次先譴責一下這些人!
-
開始正題!
-
使用場景:ubuntu16.04, kubernetes1.4及以上, 集羣沒有搭建CA等認證!其他場景僅作參考!
1.爲什麼要部署DNS
kubernetes 提供了 service 的概念可以通過 VIP(Service IP 是 virtual IP(VIP)) 訪問 pod 提供的服務,但是在使用的時候還有一個問題:怎麼知道某個應用的 VIP?比如我們有兩個應用,一個 app,一個 是 db,每個應用使用 rc或deployment進行管理,並通過 service 暴露出端口提供服務。app 需要連接到 db 應用,我們只知道 db 應用的名稱,但是並不知道它的 VIP 地址。這就涉及到了==服務發現==的問題了。
- 針對以上問題,k8s提供了三種==服務發現==的方法:
方法1.通過kubernetes 提供的 API 查詢
該方法較爲簡單,但問題較多。首先每個應用都要在啓動的時候編寫查詢依賴服務的邏輯,這本身就是重複和增加應用的複雜度;其次這也導致應用需要依賴 kubernetes,不能夠單獨部署和運行(當然如果通過增加配置選項也是可以做到的,但這又是增加複雜度)。
方法2.環境變量
K8S默認支持,這一方法是參照docker的。每個 pod 啓動時候,k8s會將之前存在的所有服務的 IP 和 port 信息通過環境變量的形式寫入到新啓動的pod中,這樣 pod中的應用可以通過讀取環境變量來獲取依賴服務的地址信息。但是有個很大的問題:依賴的服務必須在 pod 啓動之前就存在,不然就不會出現在環境變量中。
方法3.DNS(最理想的方案)
應用只需要知道服務的具體名字,不需要關心服務的實際的 ip 地址,中間的==服務名--IP==轉換由DNS自動完成。名字和 ip 之間的轉換就是 DNS 系統的功能。
2.DNS 版本介紹
DNS 服務不是獨立的系統服務,而是一種 ==addon== ,作爲==插件==來安裝的,不是 kubernetes 集羣必須的(==但是非常推薦安裝==)。可以把它看做運行在集羣上的應用,只不過這個應用比較特殊而已。 目前常用的DNS配置方式有兩種,在 1.3 之前使用 etcd + kube2sky + skydns + exechealthz的方式,在 1.3 之後可以使用 kubedns + dnsmasq +sidecar 的方式。
下面對這些組件功能進行介紹
- 1.3版本前
- etcd: DNS存儲
- kube2sky: 通過K8S API監視Service資源的變化,將service註冊到etcd
- skydns: 提供DNS域名解析服務,爲集羣中的Pod提供DNS查詢服務
- exechealthz: 提供對skydns服務的健康檢查功能
架構圖
- 1.3版本後
- kubedns: 通過K8S API監視Service資源的變化,並使用樹形結構在內存中保存DNS記錄
- dnsmasq: 提供DNS域名解析服務,爲集羣中的Pod提供DNS查詢服務
- exechealthz: 提供對kubedns和dnsmasq兩個服務的健康檢查功能,更加完善
架構圖
從中可以看出kubedns替代了 etcd和 kube2sky這兩個功能,爲dnsmasq提供查詢服務,使用樹形結構在內存中保存DNS記錄
dnsmasq在kube-dns插件中的作用: 通過kubedns容器獲取DNS規則,在集羣中提供DNS查詢服務 提供DNS緩存,提高查詢性能 降低kubedns容器的壓力、提高穩定性
3.搭建DNS
網上有很多搭建的教程,本人一一嘗試!發現都沒成功!很尷尬!可能是因爲k8s版本不同或k8s集羣搭建方式不同,又或者是引入了ServiceAccount 、token和認證等模塊。此處就不詳細介紹。 通過本人不懈努力(請允許我裝個B..),終於實現了一個精簡版DNS方案:kubedns + dnsmasq + exechealthz,具體的yaml文件可點擊這裏查看。
廢話不多說,直接上內容!
dns-rc.yaml
apiVersion: v1
kind: ReplicationController
metadata:
name: kube-dns-v15
namespace: kube-system
labels:
k8s-app: kube-dns
version: v15
kubernetes.io/cluster-service: "true"
spec:
replicas: 1
selector:
k8s-app: kube-dns
version: v15
template:
metadata:
labels:
k8s-app: kube-dns
version: v15
kubernetes.io/cluster-service: "true"
spec:
containers:
- name: kubedns
image: registry.cn-hangzhou.aliyuncs.com/sjq-k8s/kubedns-amd64:1.5
resources:
# TODO: Set memory limits when we've profiled the container for large
# clusters, then set request = limit to keep this container in
# guaranteed class. Currently, this container falls into the
# "burstable" category so the kubelet doesn't backoff from restarting it.
limits:
cpu: 100m
memory: 200Mi
requests:
cpu: 100m
memory: 100Mi
livenessProbe:
httpGet:
path: /healthz
port: 8080
scheme: HTTP
initialDelaySeconds: 60
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 5
readinessProbe:
httpGet:
path: /readiness
port: 8081
scheme: HTTP
# we poll on pod startup for the Kubernetes master service and
# only setup the /readiness HTTP server once that's available.
initialDelaySeconds: 30
timeoutSeconds: 5
args:
# command = "/kube-dns"
- --kube_master_url=http://192.168.122.10:8080
- --domain=cluster.local.
- --dns-port=10053
ports:
- containerPort: 10053
name: dns-local
protocol: UDP
- containerPort: 10053
name: dns-tcp-local
protocol: TCP
- name: dnsmasq
image: registry.cn-hangzhou.aliyuncs.com/sjq-k8s/dnsmasq:1.1
args:
- --cache-size=1000
- --no-resolv
- --server=127.0.0.1#10053
ports:
- containerPort: 53
name: dns
protocol: UDP
- containerPort: 53
name: dns-tcp
protocol: TCP
- name: healthz
image: registry.cn-hangzhou.aliyuncs.com/sjq-k8s/exechealthz-amd64:1.0
resources:
# keep request = limit to keep this container in guaranteed class
limits:
cpu: 10m
memory: 20Mi
requests:
cpu: 10m
memory: 20Mi
args:
- -cmd=nslookup kubernetes.default.svc.cluster.local 127.0.0.1 >/dev/null
- -port=8080
ports:
- containerPort: 8080
protocol: TCP
dnsPolicy: Default # Don't use cluster DNS.
其中的鏡像由於被牆,所以直接被我替換成了本人阿里雲上的鏡像,可以直接下載使用, 其中- --kube_master_url=http://192.168.122.10:8080 中的IP記得換成自己的master ip和port
dns-svc.yaml
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: 192.168.3.10
ports:
- name: dns
port: 53
protocol: UDP
- name: dns-tcp
port: 53
protocol: TCP
其中將clusterIP: 192.168.3.10 中的ip換成你實際定義的dns集羣ip。
創建rc和service
$ kubectl create -f skydns-rc.yaml
replicationcontroller "kube-dns-v15" created
$ kubectl create -f skydns-svc.yaml
service "kube-dns" created
查看是否running
$ kubectl get pod -n kube-system
NAME READY STATUS RESTARTS AGE
kube-dns-v15-32902 3/3 Running 0 2m
$
$ kubectl get svc -n kube-system
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kube-dns 192.168.3.10 <none> 53/UDP,53/TCP 7m
4.驗證dns是否有效
通過啓動一個帶有nslookup工具的busybox來驗證DNS服務是否能夠正常工作:
busybox.yaml
apiVersion: v1
kind: Pod
metadata:
name: busybox
namespace: default
spec:
containers:
- image: busybox
command:
- sleep
- "3600"
imagePullPolicy: IfNotPresent
name: busybox
restartPolicy: Always
啓動
$ kubectl create -f busybox.yaml
pod "busybox" created
pod成功運行後,通過kubectl exec <容器Id> nslookup進行測試
$ kubectl exec busybox -- nslookup kubernetes
Server: 192.168.3.10
Address 1: 192.168.3.10 kube-dns.kube-system.svc.cluster.local
Name: kubernetes
Address 1: 192.168.3.1 kubernetes.default.svc.cluster.local
成功!
如果測試的服務的命名空間不是default,那麼一定要加上命名空間,不然會報下面的錯誤
$ kubectl exec busybox -- nslookup kube-dns
nslookup: can't resolve 'kube-dns'
Server: 192.168.3.10
Address 1: 192.168.3.10 kube-dns.kube-system.svc.cluster.local
加上命名空間後
$ kubectl exec busybox -- nslookup kube-dns.kube-system
Server: 192.168.3.10
Address 1: 192.168.3.10 kube-dns.kube-system.svc.cluster.local
Name: kube-dns.kube-system
Address 1: 192.168.3.10 kube-dns.kube-system.svc.cluster.local
5.實際搭建截圖
創建成功圖
驗證成功圖
可能的問題
聲明!以上內容純屬個人原創!轉載請標註出處,謝謝!
如果本文有幫助到你,希望能動動小手點個贊。 如有錯誤請多指正!如有雷同!純屬巧合!