kubernetes+alpine+php特別容易出現訪問外網/解析外網地址的時候出現超時的問題.
原因
docker容器訪問外網的時候,整個完整路徑是這樣的.
容器-->主機-->外網-->主機-->容器
容器到主機之間的流量要經過源地址轉換(SNAT)才能順利流通.
SNAT就像是一個搬運工,把磚(流量)從容器搬到主機
如果一個主機上面運行多個容器,併發訪問外網(特別是PHP這種沒有連接池的)時向系統申請可用端口(nf_nat_l4proto_unique_tuple),不可用時+1,然後再申請,再校驗.這個過程一多,最終就會導致尋址超時.
說白了是個系統內核問題.
詳細的解釋見
記一次Docker/Kubernetes上無法解釋的連接超時原因探尋之旅
解決方案
最優解
節點升級到 5.1的Linux內核.
iptables升級到1.6.2以上
用基於IPVS模式,儘量少做SNAT/DNAT,支持隨機端口SNAT的網絡插件啓動kubernetes
或者用繞過SNAT的網絡插件插件方案,比如阿里雲的terway.但這個插件跟阿里雲綁定得比較深入,需要每臺機器額外購買一個彈性網卡.
次優解
用ds部署name sever,所有節點的DNS解析走節點上的name server,通過最小程度的SNAT+dns cache緩解此類問題.
僞解決方案(不能解決根本問題)
默認的pod的/etc/resolv.conf
一般長這樣
sh-4.2# cat /etc/resolv.conf
nameserver <kube-dns-vip>
search <namespace>.svc.cluster.local svc.cluster.local cluster.local localdomain
options ndots:5
這個配置的意思是,默認nameserver指向kube-dns/core-dns,所有查詢中,如果.的個數少於5個,則會根據search中配置的列表依次搜索,如果沒有返回,則最後再直接查詢域名本
身。ndots就是n個.(dots)的意思
舉個例子
sh-4.2# host -v baidu.com
Trying "baidu.com.<namespace>.svc.cluster.local"
Trying "baidu.com.svc.cluster.local"
Trying "baidu.com.cluster.local"
Trying "baidu.com.localdomain"
Trying "baidu.com"
......
重開socket
lifecycle:
postStart:
exec:
command:
- /bin/sh
- -c
- "/bin/echo 'options single-request-reopen' >> /etc/resolv.conf"
設置重開socket是規避容器併發A,AAAA查詢
2級域名直接走上層解析
參考kubernetes 使用基於 alpine 鏡像無法正常解析外網DNS 做的
直接運行 sed -i 's/options ndots:5/#options ndots:5/g' /etc/resolv.conf 會報錯
alpine的echo命令會吞換行符,而resolv.conf格式不對DNS解析會報錯
dnsConfig:
options:
- name: ndots
value: "2"
- name: single-request-reopen
去掉了options ndots:5
,變會默認值1,這樣的話,容器內部直接訪問還是沒問題的,走search列表,<svc>.<namespace>.svc.cluster.local
,還是能夠訪問。
而解析Google.com
,實際上是解析Google.com.
,.的數量超過1個,這時不走search列表,直接用上層DNS
綜上所述,去掉ndots/ndots設爲1 降低了頻繁DNS查詢的可能性。對於外網IP的解析有“奇效”。
但如果該主機運行其他容器(這不廢話嗎,一個節點不跑多個容器那還用啥kubernetes),其他容器也會併發地請求,SNAT的問題還是會出現,所以說修改/etc/resolv.conf
文件並不能解決根本問題
歪門邪道1
lifecycle:
postStart:
exec:
command:
- /bin/sh
- -c
- "head -n 2 /etc/resolv.conf > /etc/temp.conf;cat /etc/temp.conf > /etc/resolv.conf;rm -rf /etc/temp.conf"
歪門邪道2
initContainers:
- name: alpine
image: alpine
command:
- /bin/sh
- -c
- "head -n 2 /etc/resolv.conf > /etc/temp.conf;cat /etc/temp.conf > /etc/resolv.conf;rm -rf /etc/temp.conf"
衍生的問題
DNAT
容器訪問clusterIP(因爲是虛擬IP所以需要DNAT)也有可能出現這類超時的問題
注意Virtual domain的問題
non-headservice的域名格式是<svc>.<namespace>.svc.cluster.local
如果我們容器直接訪問<svc>.<namespace>.svc.cluster.local
,因爲默認DNS設置的問題,解析的次數反而更多。正確的方式是訪問<svc>
例子:假設test下面有個s的svc
host -v s
# 解析1次
host -v s.test.svc.cluster.local
# 解析4次
所以,訪問同namespace其他svc,直接用svc名去訪問即可,沒必要裝逼使用<svc>.<namespace>.svc.cluster.local
這種格式。
其他知識
dns記錄類型
- A記錄:地址記錄,用來指定域名的IPv4地址(如:8.8.8.8),如果需要將域名指向一個IP地址,就需要添加A記錄。
- CNAME: 如果需要將域名指向另一個域名,再由另一個域名提供ip地址,就需要添加CNAME記錄。
- TXT:在這裏可以填寫任何東西,長度限制255。絕大多數的TXT記錄是用來做SPF記錄(反垃圾郵件)。
- NS:域名服務器記錄,如果需要把子域名交給其他DNS服務商解析,就需要添加NS記錄。
- AAAA:用來指定主機名(或域名)對應的IPv6地址(例如:ff06:0:0:0:0:0:0:c3)記錄。
- MX:如果需要設置郵箱,讓郵箱能收到郵件,就需要添加MX記錄。
- 顯性URL:從一個地址301重定向到另一個地址的時候,就需要添加顯性URL記錄(注:DNSPod目前只支持301重定向)。
- 隱性URL:類似於顯性URL,區別在於隱性URL不會改變地址欄中的域名。
- SRV:記錄了哪臺計算機提供了哪個服務。格式爲:服務的名字、點、協議的類型,例如:_xmpp-server._tcp。
用到的命令
安裝方法:
yum install -y bind-utils
sudo apt-get install -y dnsutils
apk add bind-tools
dig
dig +trace +ndots=5 +search $host
host
host -v $host