Preface
此篇文章是 Kubernetes Pod-DNS 系列文章第二篇 此系列文會從使用者的用法到一些問題的發掘,最後透過閱讀程式碼的方式去分析這些問題
相關的文章連結如下
- [Kubernetes] DNS setting in your Pod
- [Kubernetes] DNS Setting with Dockerd(原始碼分析上)
- [Kubernetes] DNS Setting with Dockerd(原始碼分析下)
正文
在前篇文章
[Kubernetes] DNS setting in your Pod 中已經詳細介紹了如何針對 Pod 去設定自己想要的 DNS 規則。
但是最近遇到一個有趣的狀況,當 Pod 內設定其 dnsPolicy 為 Default 時,則 Pod 內 /etc/resolv.conf 的數值卻會因為系統上面不同的設定而有不同的結果。
根據研究與實驗觀察後,這些東西最後會跟兩個東西有很密切的關係,分別是運行節點上 /etc/resolv.conf 內的資料以及該機器上 dockerd 運行的參數有關
直接先講結論
kubernetes 會先嘗試使用節點上 /etc/resolv.conf 的資料,但是若發現 /etc/resolv.conf 是空的,這時候就會去依賴 dockerd 幫忙產生的 /etc/resolv.conf

針對這個問題接下來會分成兩篇文章來解釋 其中本篇是上篇,主軸在於介紹問題,並且透過實驗觀察結果進行歸納。 之後會有下篇,比較硬派一點,直接透過觀察原始碼的方式來驗證本篇的觀察結果
環境版本
- docker:
- 17.06.2-ce, build cec0b72
- kubernetes:
- v1.10.0
- os:
- Ubuntu 16.04, Linux 4.4.0-128-generic
問題描述
首先,我觀察到這個問題主要是在不同的Kubernetes 集群中,我發現我自己部署的 Deployment/Pod 某些情況下卻沒有辦法解析外部的 DNS 名稱,譬如 google.com.
這些
kubernetes集群可能是採用不同方式安裝的,如 kubespray, kubeadm
這些 Pod 都採用預設的 DNS 設定,所以都會採用 ClusterFirst 的機制讓 kube-dns 來處理這些 DNS 請求。
為了釐清這個問題,我就開始針對 kube-dns 裡面的 dnsmasq 這個容器進行研究。
我研究的方向是 dnsmasq 容器內 /etc/resolv.conf 的資料,我觀察到在不同的安裝環境下,dnsmasq 內 /etc/resolv.conf 內的資料有很多種可能性
以我自己的環境下,我看到不同 kubernetes 集群內 kube-dns 裡面 dnsmasq 此容器內的 /etc/resolv.conf 有下列變化
root@node-1:~$ kubectl -n kube-system exec kube-dns-5466774c4f-r9k4w cat /etc/resolv.conf
search default.svc.cluster.local svc.cluster.local
nameserver 10.233.0.3
options ndots:2 timeout:2 attempts:2
root@node-1:~$ kubectl -n kube-system exec kube-dns-5466774c4f-r9k4w cat /etc/resolv.conf
8.8.8.8
root@node-1:~$ kubectl -n kube-system exec kube-dns-5466774c4f-r9k4w cat /etc/resolv.conf
10.5.23.1
思路
首先 dnsmasq 這個容器本身採用的是 dnsPolicy:default 這個選項來操作, 所以我認為這個部分應該會跟該節點本身的 /etc/resolv.conf 有關
所以進行了下列兩個實驗
- /etc/resolv.conf 裡面有資料
- /etc/resolv.conf 裡面沒有資料
觀察結果
維持 /etc/resolv.conf
首先觀察到,在所有的集群內,只要 /etc/resolv.conf 有資料的話,則 dnsmasq 的 /etc/resolv.conf 都會是一致的

但是接下來若將 /etc/resolv.conf 給清空,這時候不同集群表現出來的結果卻完全不同了。
清空 /etc/resolv.conf
第一種案例如下,dnsmasq 內的則是自動的被捕上了 8.8.8.8 以及 8.8.4.4

第二種案例如下,dnsmasq 內的則是自動的被捕上了跟 kubernetes kube-dns 有關的資訊,這些資料看起來就跟 dnsPolicy:clusterFirst 完全一樣

歸納結果
總和以上原因,目前可以至少知道,只要 /etc/resolv.conf 有資料的話, dnsmasq 內的 /etc/resolv.conf 就會與該資料一致。
但是若 /etc/resolv.conf 沒有資料的話, 則 dnsmasq 內的 /etc/resolv.conf 目前卻出現兩種可能性。
思路(二)
接下來為了釐清這個問題,就開始認真的翻文件以及相關的程式碼,最後終於找到了影響的原因
相關的程式碼會在下篇文章解釋一切的來龍去脈
另外一個會影響數值的就是 dockerd 本身啟動的參數
根據上述兩個有差異的 kubernetes 集群去分析,發現這兩個 kubernetes 集群內本身運行的 dockerd 有參數上的差異
其中一個是非常乾淨,單純的設定連線資訊,另外一個則是設定了很多DNS 的數值
如下圖

而且可以發現這些參數的數值都跟上述 dnsmaq 裡面的數值完全一致

歸納結果
目前觀察的結果,當 kubernetes 創見 Pod 且 dnsPolicy=default 時,其內部容器 /etc/resolv.conf 的數值會受到兩個參數影響
- 該節點上本身的 /etc/resolv.conf
- 該節點上 dockerd 運行的 dns 參數
| node\dockerd | 有設定 DNS | 沒設定 DNS |
|---|---|---|
| 有數值 | node | node |
| 沒有數值 | dockerd | 8.8.8.8 |
基本上只要節點上的 /etc/resolv.conf 有資料,就直接採用
若節點上的 /etc/resolv.conf 沒有資料,則會根據 dockerd 本身有沒有額外的 DNS 參數 來決定,若有則使用,沒有則採用 8.8.8.8 以及 8.8.4.4
將上述的結果用更完整的說法就是
kubernetes 會先嘗試使用 /etc/resolv.conf 的資料,但是若發現 /etc/resolv.conf 是空的,這時候就會去依賴 dockerd 幫忙產生的 /etc/resolv.conf