在k8s中搭建可解析hostname的DNS服務

2016-01-25更新node

上篇文章總結k8s中搭建hbase時,遇到Pod中hostname的DNS解析問題,本篇將經過修改kube2sky源碼來解決這個問題。linux

1 前言

kube2sky在Github上的項目(戳這裏)一直在更新,放在DockerHub平臺上的鏡像滯後較多,有從新構建的必要。雖然新版kube2sky加入了對Pod的DNS解析,域名格式爲<pod-ip-address>.<namespace>.pod.<cluster-name>,並不能直接經過hostname來訪問對應的Pod。所以對kube2sky源碼進行了修改,增長了對pod中容器的hostname的域名解析,以及集羣中運行kube-proxy的主機hostname的解析。git

2 kube2sky源碼修改與解析

修改後的kube2sky.go(戳這裏)github

kube2sky監控kubernetes中services、endpoints、pods、nodes的變化,將IP地址和域名的對應關係寫入到ETCD中;集羣中的skyDNS從ETCD中讀取這些對應關係進行域名解析。因此kube2sky和skyDNS間惟一的交流方式就是ETCD,增長hostname的解析即往ETCD中增長hostname與IP地址的對應關係。kube2sky經過訪問kube-apiserver來獲取集羣信息,同時經過watch函數來監聽IP地址是否發生了變化,若是發生了變化即更新ETCD中的記錄。golang

在源碼中有個細節能夠注意下:對於傳入的--domain參數,若是參數不帶最後一點,則程序中會自動加上這一點。即"--domain=domeos.sohu"和"--domain=domeos.sohu."是同樣的。docker

3 製做kube2sky鏡像

1) 安裝goapi

$ yum install go

2) 建立相應目錄app

$ mkdir /tmp/kube2sky
$ export GOPATH=/tmp/kube2sky
$ cd /tmp/kube2sky

3) 編譯安裝skyDNSdom

$ go get github.com/skynetservices/skydns
$ cd $GOPATH/src/github.com/skynetservices/skydns
$ go build -v
$ cp $GOPATH/bin/skydns /usr/bin

4) 安裝godeptcp

$ go get github.com/tools/godep
$ cp $GOPATH/bin/godep /usr/bin

5) 下載kube2sky編譯依賴

$ go get -d github.com/GoogleCloudPlatform/kubernetes/cluster/addons/dns/kube2sky

kube2sky依賴整個k8s項目,所以要在該項目下進行編譯。文件不少速度很慢,耐心等待。

結束後會發現報缺乏兩個依賴包,緣由是GFW的存在致使下不下來,所以須要手工下載並放到相應路徑下:

依賴包 下載地址 目錄位置 注意事項
golang.org/x/net https://github.com/golang/net $GOPATH/

src/golang.org/x/net

要將目錄名改一致
golang.org/x/crypto https://github.com/golang/crypto $GOPATH/

src/golang.org/x/crypto

要將目錄名改一致

 而後在$GOPATH目錄下再執行一次:

$ go get -d github.com/GoogleCloudPlatform/kubernetes/cluster/addons/dns/kube2sky

此時顯示已經正常下載。

6) 編譯kube2sky

進入 $GOPATH/src/github.com/GoogleCloudPlatform/kubernetes/cluster/addons/dns/kube2sky/ 目錄,用以前修改過的kube2sky.go替換此處的kube2sky.go。

使用docker container來編譯則直接:make kube2sky。

查看Makefile文件能夠發現其實是使用cgo來編譯的,因此也能夠直接在主機上編譯,但這種編譯出來的kube2sky程序與主機平臺相關:

$ GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -a -installsuffix cgo --ldflags '-w' ./kube2sky.go

編譯完成後在該目錄下即生成了kube2sky可執行文件。

7) 建立kube2sky鏡像

kube2sky的Dockerfile:

FROM private-registry.sohucs.com/sohucs/base-rh7:1.0
MAINTAINER openxxs <openxxs@gmail.com>
COPY kube2sky.go /
COPY kube2sky /
RUN chmod +x /kube2sky
CMD ["/kube2sky"]

skyDNS的Dockerfile:

FROM private-registry.sohucs.com/sohucs/base-rh7:1.0
MAINTAINER openxxs <openxxs@gmail.com>
COPY skydns /
RUN chmod +x /skydns
CMD ["/skydns"]

構建並放入私有倉庫中:

$ cd kube2sky/build/path
$ docker build
-t private-registry.sohucs.com/domeos/kube2sky:1.1 .

$ docker push private-registry.sohucs.com/domeos/kube2sky:1.1
$ cd skydns/build/path 

$ docker build
-t
private-registry.sohucs.com/domeos/skydns:1.0 .

$ docker push
private-registry.sohucs.com/domeos/skydns:1.0

4 部署skyDNS

啓動kubelet時加DNS配置參數:--cluster_dns=172.16.40.1 --cluster_domain=domeos.sohu。這裏嘗試過加多個--cluster_dns地址,但只有最後加的配置有效。在部署時嘗試過service形式部署和HostPort形式部署,對於集羣內的域名解析兩種方式均可以正常工做。若是但願在主機節點上也使用這套DNS解析,HostPort形式更適合。

1)以service形式部署

與上篇文章的部署方式不一樣,本文再也不將ETCD、kube2sky和skyDNS放在同一個Pod中,而是獨立出來。例子以下:

apiVersion: v1
kind: Service
metadata:
  name: skydns-svc
  labels:
    app: skydns-svc
    version: v9
spec:
  selector:
    app: skydns
    version: v9
  type: ClusterIP
  clusterIP: 172.16.40.1
  ports:
    - name: dns
      port: 53
      protocol: UDP
    - name: dns-tcp
      port: 53
      protocol: TCP
---
apiVersion: v1
kind: ReplicationController
metadata:
  name: skydns
  labels:
    app: skydns
    version: v9
spec:
  replicas: 1
  selector:
    app: skydns
    version: v9
  template:
    metadata:
      labels:
        app: skydns
        version: v9
    spec:
      containers:
        - name: skydns
          image: private-registry.sohucs.com/domeos/skydns:1.0
          command:
            - "/skydns"
          args:
            - "--machines=http://10.16.42.200:4012"
            - "--domain=domeos.sohu"
            - "--addr=0.0.0.0:53"
          ports:
            - containerPort: 53
              name: dns-udp
              protocol: UDP
            - containerPort: 53
              name: dns-tcp
              protocol: TCP
---
apiVersion: v1
kind: ReplicationController
metadata:
  name: kube2sky
  labels:
    app: kube2sky
    version: v9
spec:
  replicas: 1
  selector:
    app: kube2sky
    version: v9
  template:
    metadata:
      labels:
        app: kube2sky
        version: v9
    spec:
      containers:
        - name: kube2sky
          image: private-registry.sohucs.com/domeos/kube2sky:1.1
          command:
            - "/kube2sky"
          args:
            - "--etcd-server=http://10.16.42.200:4012"
            - "--domain=domeos.sohu"
            - "--kube_master_url=http://10.16.42.200:8080"

上述yaml文件中建立了服務地址爲172.16.40.1的DNS服務,並建立了與之對應的kube2sky和skyDNS的RC。skyDNS中的--machines參數爲ETCD的地址,這裏直接用k8s集羣的ETCD;--domain爲域名的後綴;--addr爲域名服務的地址和端口。kube2sky中--etcd-server爲ETCD地址,--kube_master_url爲k8s的apiserver地址。

$ kubectl create -f dns.yaml
$ kubectl get pods | grep -E "skydns|kube2sky"

kube2sky-yylub                                                    1/1       Running          0          1d

skydns-dteml                                                      1/1       Running          0          1d

  $ kubectl get service | grep skydns

skydns-svc                172.16.40.1      <none>        53/UDP,53/TCP      app=skydns,version=v9       1d

能夠看到skyDNS已經正常運行了。

2)以HostPort形式部署

apiVersion: v1
kind: ReplicationController
metadata:
  name: skydns
  labels:
    app: skydns
    version: v9
spec:
  replicas: 1
  selector:
    app: skydns
    version: v9
  template:
    metadata:
      labels:
        app: skydns
        version: v9
    spec:
      containers:
        - name: skydns
          image: private-registry.sohucs.com/domeos/skydns:1.0
          command:
            - "/skydns"
          args:
            - "--machines=http://10.16.42.200:4012"
            - "--domain=domeos.sohu"
            - "--addr=0.0.0.0:53"
          ports:
            - containerPort: 53
              hostPort: 53
              name: dns-udp
              protocol: UDP
            - containerPort: 53
              hostPort: 53
              name: dns-tcp
              protocol: TCP
      dnsPolicy: ClusterFirst
nodeName: bx-42-197 hostNetwork:
true restartPolicy: Always --- apiVersion: v1 kind: ReplicationController metadata: name: kube2sky labels: app: kube2sky version: v9 spec: replicas: 1 selector: app: kube2sky version: v9 template: metadata: labels: app: kube2sky version: v9 spec: containers: - name: kube2sky image: private-registry.sohucs.com/domeos/kube2sky:1.1 command: - "/kube2sky" args: - "--etcd-server=http://10.16.42.200:4012" - "--domain=domeos.sohu" - "--kube_master_url=http://10.16.42.200:8080" dnsPolicy: ClusterFirst restartPolicy: Always

HostPort形式並不須要建立service,建立skyDNS時須要設置hostNetwork屬性爲true,同時設置nodeName以指定skyDNS運行在哪一個節點上(例子中指定爲bx-42-197的節點上)。在啓動kubelet時的--cluster_dns參數值爲bx-42-197的IP地址,即--cluster_dns=10.16.42.197。這裏要注意skyDNS佔用了53端口,所以bx-42-197的53端口必須是可用的。同時,須要手工將skyDNS的服務地址和search域寫入到各個node節點的/etc/resolv.conf文件中,內容以下:

nameserver 10.16.42.197
search default.svc.domeos.sohu svc.domeos.sohu domeos.sohu 

5 測試

查看ETCD中的相關記錄主要有三類:

$ etcdctl --peers=10.16.42.200:4012 ls --recursive /skydns
......
# 這一類爲pod的DNS記錄,下例中kafka-1-wkfa1爲pod的名字,而19d074a1爲運行在pod中的一個container的hostname
/skydns/sohu/domeos/kafka-1-wkfa1
/skydns/sohu/domeos/kafka-1-wkfa1/19d074a1
......
# 這一類爲service的DNS記錄
/skydns/sohu/domeos/svc/default/kafka-svc-1
/skydns/sohu/domeos/svc/default/kafka-svc-1/b56639fb
......
# 這一類爲主機的DNS記錄

  /skydns/sohu/domeos/bx-42-198

  /skydns/sohu/domeos/bx-42-198/adc8794b

  ......

$ etcdctl --peers=10.16.42.200:4012 get /skydns/sohu/domeos/kafka-1-wkfa1/19d074a1 
{
"host":"172.28.0.12","priority":10,"weight":10,"ttl":30}
$ etcdctl
--peers=10.16.42.200:4012 get /skydns/sohu/domeos/svc/default/kafka-svc-1/b56639fb
{
"host":"172.16.50.1","priority":10,"weight":10,"ttl":30}
$ etcdctl --peers=10.16.42.200:4012 get /skydns/sohu/domeos/bx-42-198/adc8794b
{"host":"10.16.42.198","priority":10,"weight":10,"ttl":30}

能夠看到Pod的hostname和主機節點的hostname被加入了記錄,service的DNS記錄依舊保留。

經過 docker exec 進入任一運行中的container進行測試:

$ docker exec -it 0d0874df9e15 /bin/sh
# 查看resolv.conf文件,能夠看到DNS服務被加進來了
$ cat /etc/resolv.conf
nameserver 172.16.40.1
nameserver 192.168.132.1
search default.svc.domeos.sohu svc.domeos.sohu domeos.sohu
options ndots:5
# 測試解析其它container的hostname,解析成功
$ ping kafka-1-wkfa1 -c 1
PING kafka-1-wkfa1.domeos.sohu (172.28.0.12) 56(84) bytes of data.
# 測試解析k8s的service,解析成功
$ ping kafka-svc-1 -c 1
PING kafka-svc-1.default.svc.domeos.sohu (172.16.50.1) 56(84) bytes of data.
# 測試解析主機的hostname,解析成功
$ ping bx-42-198 -c 1
PING bx-42-198.domeos.sohu (10.16.42.198) 56(84) bytes of data.

經過hostname訪問成功!

相關文章
相關標籤/搜索