k8s與debug--解決conntrack insert failed

咱們通常的項目中,大多數已經容器化部署。服務之間訪問,即同一個集羣的東西向流量,直接經過 service 訪問。而南北向流量,是經過 ingress 來解決。git

Screen-Shot-2019-04-17-at-10.58.43-AM-1024x769.png

在東西向流量訪問中,有一些大流量和高併發的業務,尤爲是在pod擴縮的時候,常常出現丟包而致使接口錯誤率比較高。咱們service 的backend 選擇的是iptabels。因此咱們懷疑是iptables帶來的問題。github

首先懷疑是端口複用,當端口耗盡的時候,沒有多餘的端口用於SNAT操做,就會出現數據包都丟棄或是拒絕的狀況。咱們看了一下conntrack表, 可是實際值遠遠沒有達到上限值。網絡

conntrack -S 發現大量的 nf_conntrack insert failed 錯誤。併發

這個問題在k8s早期,仍是比較常見的。負載均衡

NAT代碼在POSTROUTING鏈上hook了兩次。首先,經過更改源IP和PORT(IP或PORT)來修改數據包結構,而後,若是未在中間丟棄數據包,則將轉換記錄在conntrack表中。若是存在衝突,這意味着SNAT端口分配和表中的插入之間存在延遲,就會致使 nf_conntrack insert failed,結果致使數據包丟失less

不少網絡組件已經支持了 NF_NAT_RANGE_PROTO_RANDOM_FULLY, 好比Flanneldom

經過 NF_NAT_RANGE_PROTO_RANDOM_FULLY,能夠大大減小插入錯誤的數量。在具備默認假裝規則和鏈接到同一主機的10至80個線程的Docker測試虛擬機上,conntrack表中插入失敗的發生率爲2%至4%。
在內核中強制採用徹底隨機性後,錯誤降至0(後來在實時羣集中接近0)。高併發

咱們生產環境使用的是EKS,關於ENI也實現了相似的方案。對於ENI,在其部署選型中,有個配置項 AWS_VPC_K8S_CNI_RANDOMIZESNAT測試

翻譯官方文檔大體內容以下:google

指定SNAT iptables規則是否應將鏈接的出端口隨機化。當AWS_VPC_K8S_CNI_EXTERNALSNAT = false 時,應使用此選項。啓用後(hashrandom),--random標誌將添加到SNAT iptables規則。要使用僞隨機數生成而不是基於散列(即--random-fully),請使用prng做爲環境變量。對於不支持--random-徹底的舊版本的iptables,此選項將退回到--random。若是您依賴於出站鏈接的順序端口分配,請禁用(無)此功能。

固然出於生產環境穩定性,咱們在已經有的集羣當中選擇了另一個方案--繞過iptables。

如何繞過?

咱們知道pod網絡自己就是相通的, 大體實現方案有隧道,路由等。

pasted image 0.png

咱們能夠獲取到Pod列表,而後作客戶端負載均衡。因爲咱們這些項目自己協議就是grpc,service的4層負載均衡是沒有意義的,因此咱們的客戶端已經實現了客戶端負載均衡。

在Kubernetes中,有一種稱爲headless服務的特定服務。Headless服務不會爲底層Pod提供單個IP和負載平衡,而只是具備DNS配置,該配置爲咱們提供了一個A記錄,其中包含與標籤選擇器匹配的全部Pod的Pod IP地址。

不過該方案須要注意:

  • coredns 須要配置梯度擴縮。具體就是使用 cluster-proportional-autoscaler
  • 配置ndots。咱們知道設置pod的dnsPolicy爲ClusterFirst以後,全部的dns解析請求,都會請求到coredns。默認的ndots:5, 會致使接口的延時變大,不少時間浪費在dns請求上。經過抓包分析:

    ndots爲5的時候:

    03:52:25.216518 IP access-6bf77d68df-sm87n.42375 > kube-dns.kube-system.svc.cluster.local.domain: 11402+ A? www.baidu.com.tsa.svc.cluster.local. (53)
    03:52:25.216916 IP access-6bf77d68df-sm87n.40506 > kube-dns.kube-system.svc.cluster.local.domain: 64764+ PTR? 10.0.100.10.in-addr.arpa. (42)
    03:52:25.217360 IP kube-dns.kube-system.svc.cluster.local.domain > access-6bf77d68df-sm87n.42375: 11402 NXDomain*- 0/1/0 (146)
    03:52:25.217489 IP access-6bf77d68df-sm87n.42327 > kube-dns.kube-system.svc.cluster.local.domain: 39517+ A? www.baidu.com.svc.cluster.local. (49)
    03:52:25.217660 IP kube-dns.kube-system.svc.cluster.local.domain > access-6bf77d68df-sm87n.40506: 64764*- 1/0/0 PTR kube-dns.kube-system.svc.cluster.local. (118)
    03:52:25.217877 IP kube-dns.kube-system.svc.cluster.local.domain > access-6bf77d68df-sm87n.42327: 39517 NXDomain*- 0/1/0 (142)
    03:52:25.217906 IP access-6bf77d68df-sm87n.48023 > kube-dns.kube-system.svc.cluster.local.domain: 56925+ A? www.baidu.com.cluster.local. (45)
    03:52:25.218056 IP kube-dns.kube-system.svc.cluster.local.domain > access-6bf77d68df-sm87n.48023: 56925 NXDomain*- 0/1/0 (138)
    03:52:25.218102 IP access-6bf77d68df-sm87n.35164 > kube-dns.kube-system.svc.cluster.local.domain: 13509+ A? www.baidu.com.ap-southeast-1.compute.internal. (63)
    03:52:25.219213 IP kube-dns.kube-system.svc.cluster.local.domain > access-6bf77d68df-sm87n.35164: 13509 NXDomain 0/0/0 (63)
    03:52:25.219280 IP access-6bf77d68df-sm87n.56466 > kube-dns.kube-system.svc.cluster.local.domain: 22697+ A? www.baidu.com. (31)
    03:52:25.221500 IP kube-dns.kube-system.svc.cluster.local.domain > access-6bf77d68df-sm87n.56466: 22697 4/0/0 CNAME www.a.shifen.com., CNAME www.wshifen.com., A 45.113.192.101, A 45.113.192.102 (181)
    03:52:25.223936 IP access-6bf77d68df-sm87n.59668 > kube-dns.kube-system.svc.cluster.local.domain: 33885+ PTR? 101.192.113.45.in-addr.arpa. (45)
    03:52:25.225784 IP kube-dns.kube-system.svc.cluster.local.domain > access-6bf77d68df-sm87n.59668: 33885 NXDomain 0/1/0 (122)

    ndots爲2的時候:

    04:06:19.030624 IP access-d6f56b8db-2gxfd.34877 > kube-dns.kube-system.svc.cluster.local.domain: 21513+ A? www.baidu.com. (31)
    04:06:19.032784 IP kube-dns.kube-system.svc.cluster.local.domain > access-d6f56b8db-2gxfd.34877: 21513 4/0/0 CNAME www.a.shifen.com., CNAME www.wshifen.com., A 45.113.192.102, A 45.113.192.101 (181)
    04:06:19.035098 IP access-d6f56b8db-2gxfd.53602 > kube-dns.kube-system.svc.cluster.local.domain: 37598+ PTR? 102.192.113.45.in-addr.arpa. (45)
    04:06:19.036743 IP kube-dns.kube-system.svc.cluster.local.domain > access-d6f56b8db-2gxfd.53602: 37598 NXDomain 0/1/0 (122)

    對於一些外部域名,默認ndots爲5,每次解析都要所有搜索一遍。ndots爲2的時候 只搜索一次。

    FQDN是完整域名,通常來講,域名最終以.結束表示是FQDN,例如google.com.是FQDN,但google.com不是。

    對FQDN,操做系統會直接查詢DNS server。那麼非FQDN呢?這裏就要用到search和ndots了。

    ndots表示的是域名中必須出現的.的個數,若是域名中的.的個數不小於ndots,則該域名爲一個FQDN,操做系統會直接查詢;若是域名中的.的個數小於ndots,操做系統會在search搜索域中進行查詢。

    例如上面的例子,ndots爲5,查詢的域名google.com不以.結尾,且.的個數少於5,所以操做系統會依此在default.svc.cluster.local svc.cluster.local cluster.local lan四個域中進行了搜索,其中前面3個搜索域是由kubernetes注入的,最後的lan是操做系統默認的搜索域。

    ndots默認值爲1,也就是說,只要域名中有一個.,操做系統就會認爲是絕對域名,直接查詢。

    ndots上限爲15。

  • coredns 配置文件增長forward插件。

    forward . /etc/resolv.conf

    將外部的域名按照/etc/resolv.conf的解析規則解析。

總結

固然終極方案service mesh這種服務治理方案是最好的,若是是南北向流量,其實使用ingress就能夠避免iptables。

相關文章
相關標籤/搜索