2016-01-25更新
上篇文章總結k8s中搭建hbase時,遇到Pod中hostname的DNS解析問題,本篇將通過修改kube2sky源碼來解決這個問題。
1 前言
kube2sky在Github上的項目(戳這里)一直在更新,放在DockerHub平台上的鏡像滯后較多,有重新構建的必要。雖然新版kube2sky加入了對Pod的DNS解析,域名格式為<pod-ip-address>.<namespace>.pod.<cluster-name>,並不能直接通過hostname來訪問對應的Pod。因此對kube2sky源碼進行了修改,增加了對pod中容器的hostname的域名解析,以及集群中運行kube-proxy的主機hostname的解析。
2 kube2sky源碼修改與解析
修改后的kube2sky.go(戳這里)
kube2sky監控kubernetes中services、endpoints、pods、nodes的變化,將IP地址和域名的對應關系寫入到ETCD中;集群中的skyDNS從ETCD中讀取這些對應關系進行域名解析。所以kube2sky和skyDNS間唯一的交流方式就是ETCD,增加hostname的解析即往ETCD中增加hostname與IP地址的對應關系。kube2sky通過訪問kube-apiserver來獲取集群信息,同時通過watch函數來監聽IP地址是否發生了變化,如果發生了變化即更新ETCD中的記錄。
在源碼中有個細節可以注意下:對於傳入的--domain參數,如果參數不帶最后一點,則程序中會自動加上這一點。即"--domain=domeos.sohu"和"--domain=domeos.sohu."是一樣的。
3 制作kube2sky鏡像
1) 安裝go
$ yum install go
2) 創建相應目錄
$ mkdir /tmp/kube2sky $ export GOPATH=/tmp/kube2sky $ cd /tmp/kube2sky
3) 編譯安裝skyDNS
$ go get github.com/skynetservices/skydns $ cd $GOPATH/src/github.com/skynetservices/skydns $ go build -v
$ cp $GOPATH/bin/skydns /usr/bin
4) 安裝godep
$ 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訪問成功!