Kubernetes DNS部署

在kubernetes中每一個service都會被分配一個虛擬IP,每一個Service在正常情況下都會長時間不會改變,這個相對於pod的不定IP,對於集羣中APP的使用相對是穩定的。但是Service的信息注入到pod目前使用的是環境變量的方式,並且十分依賴於pod(rc)和service的創建順序,這使得這個集羣看起來又不那麼完美,於是kubernetes以插件的方式引入了DNS系統,利用DNS對Service進行一個映射,這樣我們在APP中直接使用域名進行引用,避免了之前的變量氾濫問題,也避免了創建順序的尷尬局面。

這裏寫圖片描述

skyDNS: 提供DNS解析服務
etcd:用於skyDNS的存儲
kube2sky:連接Kubernetes和skyDNS

1. skydns配置文件

創建DNS服務的RC配置文件,在這個RC配置中包含了3個Container的定義

[root@docker1 dns]# cat skydns-rc.yaml | grep -v '#'
apiVersion: v1
kind: ReplicationController
metadata:
  name: kube-dns-v9
  namespace: kube-system
  labels:
    k8s-app: kube-dns
    version: v9
    kubernetes.io/cluster-service: "true"
spec:
  replicas: 1
  selector:
    k8s-app: kube-dns
    version: v9
  template:
    metadata:
      labels:
        k8s-app: kube-dns
        version: v9
        kubernetes.io/cluster-service: "true"
    spec:
      containers:
      - name: etcd
        image: kube-registry:5000/etcd
        resources:
          limits:
            cpu: 100m
            memory: 50Mi
        command:
        - /usr/local/bin/etcd
        - -data-dir
        - /var/etcd/data
        - -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
        volumeMounts:
        - name: etcd-storage
          mountPath: /var/etcd/data
      - name: kube2sky
        image: kube-registry:5000/kube2sky
        resources:
          limits:
            cpu: 100m
            memory: 50Mi
        args:
        - -domain=cluster.local
        - -kube_master_url=http://192.168.123.201:8080
      - name: skydns
        image: kube-registry:5000/skydns
        resources:
          limits:
            cpu: 100m
            memory: 50Mi
        args:
        - -machines=http://localhost:4001
        - -addr=0.0.0.0:53
        - -domain=cluster.local
        ports:
        - containerPort: 53
          name: dns
          protocol: UDP
        - containerPort: 53
          name: dns-tcp
          protocol: TCP
      volumes:
      - name: etcd-storage
        emptyDir: {}

(1)kube2sky容器需要訪問Kubernetes Master,需要配置Master所在物理主機的IP地址和端口
(2)kube2sky容器和skydns容器的啓動參數-domain,設置Kubernetes集羣中Service所屬的域名,本例中爲cluster.local。啓動後,kube2sky會監聽Kubernetes,當有新的Service創建時,就會生成相應的記錄並保存到etcd中。kube2sky爲每個Service生成兩條記錄:

<service_name>.<namespace_name>.<domain>
<service_name>.<namespace_name>.svc.<domain>

(3)skydns的啓動參數-addr=0.0.0.0:53表示使用本機TCP和UDP的53端口提供服務。

創建DNS服務的Service配置文件如下:

[root@docker1 dns]# cat skydns-svc.yaml | grep -v '#'
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.254.0.3
  ports:
  - name: dns
    port: 53
    protocol: UDP
  - name: dns-tcp
    port: 53
    protocol: TCP

注意:skydns服務使用的clusterIP需要我們指定一個固定的IP地址,每個Node的Kubelet進程都將使用這個IP地址,不能通過Kubernetes自動分配。
另外,這個IP地址需要在kube-apiserver啓動參數–service-cluster-ip-range指定的IP地址範圍內。

2. 修改每個Node上的Kubelet啓動參數

–cluster_dns=10.254.0.3 爲DNS服務的ClusterIP地址
–cluster_domain=cluster.local 爲DNS服務中設置的域名

修改/etc/kubernetes/kubelet:

# vim /etc/kubernetes/kubelet
KUBELET_ARGS="--cluster_dns=10.254.0.3 --cluster_domain=cluster.local"

或者修改/usr/lib/systemd/system/kubelet.service

[root@docker2 ~]# cat /usr/lib/systemd/system/kubelet.service 
[Unit]
Description=Kubernetes Kubelet Server
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=docker.service
Requires=docker.service

[Service]
WorkingDirectory=/var/lib/kubelet
EnvironmentFile=-/etc/kubernetes/config
EnvironmentFile=-/etc/kubernetes/kubelet
ExecStart=/usr/bin/kubelet --cluster_dns=10.254.0.3 --cluster_domain=cluster.local \
        $KUBE_LOGTOSTDERR \
        $KUBE_LOG_LEVEL \
        $KUBELET_API_SERVER \
        $KUBELET_ADDRESS \
        $KUBELET_PORT \
        $KUBELET_HOSTNAME \
        $KUBE_ALLOW_PRIV \
        $KUBELET_ARGS
Restart=on-failure

[Install]
WantedBy=multi-user.target

3. 創建skydns Pod和服務

通過kubectl create完成RC和Service的創建:

[root@docker1 dns]# kubectl create -f skydns-rc.yaml 
replicationcontrollers/kube-dns-v9
[root@docker1 dns]# kubectl create -f skydns-svc.yaml 
services/kube-dns

創建完成後,查看到系統創建的RC、Pod和Service都已創建成功:

然後我們創建一個普通的Service,以redis-master服務爲例:

[root@docker1 redis_yaml]# cat redis-master-service.yaml 
apiVersion: v1
kind: Service
metadata:
  name: redis-master
  labels:
    name: redis-master
spec:
  selector:
    name: redis-master
  ports:
  - port: 6379
    targetPort: 6379

查看創建出來的Service:

[root@docker1 redis_yaml]# kubectl create -f redis-master-service.yaml 
[root@docker1 redis_yaml]# kubectl get services
NAME           LABELS                                    SELECTOR            IP(S)          PORT(S)
redis-master   name=redis-master             name=redis-master   10.254.7.160   6379/TCP

4. 通過DNS查找Service

使用一個帶有nslookup工具的Pod來驗證DNS服務是否能夠正常工作:

[root@docker1 demo]# cat busybox.yaml 
apiVersion: v1
kind: Pod
metadata: 
    name: busybox
    namespace: default
spec:
    containers:
      - image: kube-registry:5000/busybox
        command:
          - sleep
          - "3600"
        imagePullPolicy: IfNotPresent
        name: busybox
    restartPolicy: Always

運行kubectl create -f busybox.yaml完成創建。
在該容器成功啓動後,通過kubectl exec nslookup 進行測試:

[root@docker1 demo]# kubectl exec busybox -- nslookup redis-master
Server:    10.254.0.3
Address 1: 10.254.0.3
Name:      redis-master
Address 1: 10.254.7.160

可以看到,通過DNS服務器10.254.0.3成功找到了名爲”redis-master”服務的IP地址:10.254.7.160
如果某個Service屬於自定義的命名空間,那麼進行Service查找時,需要帶個namespace的名字。下面以查看kube-dns服務爲例:

[root@docker1 demo]# kubectl exec busybox -- nslookup kube-dns.kube-system
Server:    10.254.0.3
Address 1: 10.254.0.3
Name:      kube-dns.kube-system
Address 1: 10.254.0.3

如果僅使用”kube-dns”來進行查找,則將會失敗:
nslookup: can’t resolve ‘kube-dns’

查看多個容器組成的Pod時,要添加-c選項指定容器的名稱

# kubectl logs kube-dns-v9-curdr --namespace=kube-system
Error from server: a container name must be specified for pod kube-dns-v9-curdr
# kubectl logs kube-dns-v9-curdr -c skydns --namespace=kube-system

5. DNS服務的工作原理解析

(1)kube2sky容器應用通過調用Kubernetes Master的API獲得集羣中所有Service的信息,並持續監控新Service的生成,然後定稿etcd中。
查看etcd存儲的Service信息

# kubectl exec kube-dns-v9-evgl6 -c etcd --namespace=kube-system etcdctl ls /skydns/local/cluster
/skydns/local/cluster/default
/skydns/local/cluster/svc
/skydns/local/cluster/kube-system

可以看到在skydns鍵下面,根據我們配置的域名(cluster.local)生成了local/cluster子鍵,接下來是namespace(default和kube-system)和svc(下面也按namespace生成子鍵)。

查看redis-master服務對應的鍵值:

# kubectl exec kube-dns-v9-evgl6 -c etcd --namespace=kube-system etcdctl get /skydns/local/cluster/default/redis-master
{"host":"10.254.7.160","priority":10,"weight":10,"ttl":30,"targetstrip":0}

可以看到,redis-master服務對應的完整域名爲redis-master.default.cluster.local,並且其IP地址爲10.254.7.160。

(2)根據Kubelet啓動參數的設置(–cluster_dns),Kubelet會在每個新創建的Pod中設置DNS域名解析配置文件/etc/resolv.conf文件,在其中增加了一條nameserver配置和一條search配置:

nameserver 10.254.0.3
nameserver 202.96.128.86
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5

通過名字服務器10.254.0.3訪問的實際上是skydns在53端口上提供的DNS解析服務。

(3)應用程序就能夠像訪問網站域名一樣,僅僅通過服務的名字就能訪問到服務了。
例如,設置redis-slave的啓動腳本爲:
redis-server –slaveof redis-master 6379
創建redis-slave的Pod並啓動它。
之後,我們可以登錄redis-slave容器中查看,其通過DNS域名服務找到了redis-master的IP地址10.254.7.160,併成功建立了連接。
通過DNS設置,對於其他Service(服務)的查詢將可以不再依賴系統爲每個Pod創建的環境變量,而是直接使用Service的名字就能對其進行訪問,使得應用程序中的代碼更簡潔了。


參考資料
書:Kubernetes權威指南 P250

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章