kubernetes的timeout問題

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記錄類型

  1. A記錄:地址記錄,用來指定域名的IPv4地址(如:8.8.8.8),如果需要將域名指向一個IP地址,就需要添加A記錄。
  2. CNAME: 如果需要將域名指向另一個域名,再由另一個域名提供ip地址,就需要添加CNAME記錄。
  3. TXT:在這裏可以填寫任何東西,長度限制255。絕大多數的TXT記錄是用來做SPF記錄(反垃圾郵件)。
  4. NS:域名服務器記錄,如果需要把子域名交給其他DNS服務商解析,就需要添加NS記錄。
  5. AAAA:用來指定主機名(或域名)對應的IPv6地址(例如:ff06:0:0:0:0:0:0:c3)記錄。
  6. MX:如果需要設置郵箱,讓郵箱能收到郵件,就需要添加MX記錄。
  7. 顯性URL:從一個地址301重定向到另一個地址的時候,就需要添加顯性URL記錄(注:DNSPod目前只支持301重定向)。
  8. 隱性URL:類似於顯性URL,區別在於隱性URL不會改變地址欄中的域名。
  9. 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

參考鏈接:

  1. iptables中DNAT、SNAT和MASQUERADE的理解
  2. linux根文件系統 /etc/resolv.conf 文件詳解
  3. kube-dns per node #45363
  4. DNS intermittent delays of 5s #56903
  5. Racy conntrack and DNS lookup timeouts
  6. /etc/resolv.conf
  7. /etc/resolv.conf search和ndots配置
  8. DNS for Services and Pods
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章