精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

記一次容器環境下出現Address not available

OSC開源社區 ? 來源:阿里云云原生 ? 2023-08-03 10:43 ? 次閱讀

困惑的源地址

Cloud Native

pod 創建后一段時間一直是正常運行,突然有一天發現沒有新的連接創建了,業務上是通過 pod A 訪問 svc B 的 svc name 的方式,進入 pod 手動去 wget 一下,發現報錯了 Address not available,為何會報錯這個呢?

大概示例圖如下:



7e298742-3122-11ee-9e74-dac502259ad0.png



為什么會出現 Address not available,是什么地址不可用,查了很多資料,根據 POSIX(Portable Operating System Interface for UNIX)標準的錯誤定義中找到了相關的定義,同樣說的還不是很清楚。

錯誤代碼參考連接:[errno.3[1]]


EADDRNOTAVAIL               
    Address not available (POSIX.1-2001).

容易被忽視的內核參數

Cloud Native

通過 netstat -an 查看到連接 svc 的地址,其中 estab 狀態的連接數,已經到達了可用的隨機端口數量閾值,無法在新建連接了。

7e51de22-3122-11ee-9e74-dac502259ad0.png


最后通過修改了內核參數隨機端口 net.ipv4.ip_local_port_range 端口范圍才得以解決的。 我們可以知道 Linux 的內核定義的隨機端口 32768 ~ 60999,可能在業務設計場景中,比較容易被忽略的,我們都知道,每一個 TCP 連接都是由四元組(源 IP,源端口,目的 IP,目的端口)構成的,只要四元組中其中一個元組發生了變化,就可以創建一個 TCP 連接的。當一個 POD 要訪問一個固定的目的 IP + 目的端口的時候,那么每一個 TCP 連接的變量就只剩下源端口是隨機的了,所以如果在需求就是需要創建大量長連接的話,要么就調大內核隨機端口,要么就調整業務。

相關內核參考連接:[ip-sysctl.txt[2]]



ip_local_port_range - 2 INTEGERS
  Defines the local port range that is used by TCP and UDP to
  choose the local port. The first number is the first, the
  second the last local port number.
  If possible, it is better these numbers have different parity
  (one even and one odd value).
  Must be greater than or equal to ip_unprivileged_port_start.
  The default values are 32768 and 60999 respectively.

同樣的問題還可能出現什么類型的報錯呢?

Cloud Native

手動調小了 net.ipv4.ip_local_port_range,之后進行復現。

同樣的問題,分別嘗試了 curl,nc,wget 命令,報錯都不一樣,這就犯難了。 難道就不能統一一下嗎?

curl: (7) Couldn't connect to server

nc: bind: Address in use

wget: can't connect to remote host (1.1.1.1): Address not available

7e5be836-3122-11ee-9e74-dac502259ad0.png

那么就通過 strace 命令進程分析一下看看,跟蹤指定系統調用名稱 它們都會創建 socket(), 然后發現 wget/curl 命令是通過 connect() 函數,而 nc 命令先是是通過 bind() 函數調用, 如果報錯就不會繼續調用 connect() 函數了。 7e738400-3122-11ee-9e74-dac502259ad0.png

如圖,通過對 B/S 架構的分析如下,connect() 是在客戶端創建 socket 后建立的。


7e942dcc-3122-11ee-9e74-dac502259ad0.png

引發思考

Cloud Native

為什么 wget/curl 同樣調用的是 connect() 函數報錯的,為何報錯還是不一樣的?

每一個客戶端程序都會有自定義的 errorcode,在同樣的 connect() 函數報錯后 ,wget 是直接輸出了 POSIX 標準的錯誤定義 Address not available,而 curl 會輸出自己的定義錯誤碼和對應的提示信息 curl: (7) Couldn't connect to server,錯誤代碼是 7,curl 的報錯定義在 lib/strerror.c。

7eba84c2-3122-11ee-9e74-dac502259ad0.png7ed4c2c4-3122-11ee-9e74-dac502259ad0.png


為什么 connect() 函數和 bind() 函數報錯不一樣?

函數不同,錯誤的定義也就不同,從 POSIX 標準的錯誤定義都能找到。


EADDRINUSE               
    Address already in use (POSIX.1-2001).        
EADDRNOTAVAIL               
    Address not available (POSIX.1-2001).

是不是所有情況下都是這樣輸出呢?

Cloud Native

那么直接找了一臺 Centos7.9 的系統,安裝 curl 、wget、 nc 等工具,同樣改小端口范圍的情況下會出現如下報錯 Cannot assign requested address,從這里可以得知某些鏡像(alpine、busybox) 里,使用相同的命令工具對相同的情況下報錯會不同。因為這些鏡像里可能為了縮小整個鏡像大小,對于一些基礎命令都會選擇 busybox 工具箱(上面的 wget 和 nc 就來自于 busybox 工具箱里的,參考 busybox 文檔:Busybox Command Help[3])來使用,所以就造成在問題定位方面困擾了。

Linux 系統中用于包含與錯誤碼相關的定義:/usr/include/asm-generic/errno.h

7f050862-3122-11ee-9e74-dac502259ad0.png



#define  EADDRNOTAVAIL  99  /* Cannot assign requested address */

容器環境下,端口配置最佳實踐

Cloud Native

可修改范圍

理論上來是 0~65535 都能使用, 但是 0~1023 是特權端口,已經預留給一下標準服務,如 HTTP:80,SSH:22 等,只能特權用戶使用,同時也避免未授權的用戶通過流量特征攻擊等所以建議端口調大的話可以將隨機端口范圍限制在 1024-65535 之間。

如何正確配置 Pod 源端口

普通 Pod 源端口修改方法

從 kubernetes 社區得知可以通過安全上下文修改 securityContext[4],還有可以通過 initContainers 容器給特權模式 mount -o remount rw /proc/sys 的方式修改,此修改方式只會在 pod 的網絡命名空間中生效。

securityContext


...
securityContext:
  sysctls:       
    - name: net.ipv4.ip_local_port_range           
      value: 1024 65535

initContainers


      initContainers:
        - command:
            - /bin/sh
            - '-c'
            - |
              sysctl -w net.core.somaxconn=65535
              sysctl -w net.ipv4.ip_local_port_range="1024 65535"
          securityContext:
            privileged: true
...

hostnetwork 模式 pod 修改注意事項

1.22+ 集群以上就不建議修改 net.ipv4.ip_local_port_range,因為這會和 ServiceNodePortRange 產生沖突。 Kubernetes 的 ServiceNodePortRange 默認是 30000~32767,Kubernetes 1.22 及以后的版本,去除了 kube-proxy 監聽 NodePort 的邏輯,如果有監聽的話,應用程序在選用隨機端口的時候,會避開這些監聽中的端口。如果 net.ipv4.ip_local_port_range 的范圍和 ServiceNodePortRange 存在重疊,由于去掉了監聽 NodePort 的邏輯,應用程序在選用隨機端口的時候就可能選中重疊部分,比如 30000~32767,在當 NodePort 與內核 net.ipv4.ip_local_port_range 范圍有沖突的情況下,可能會導致偶發的 TCP 無法連接的情況,可能導致健康檢查失敗、業務訪問異常等問題。更多信息,請參見Kubernetes 社區 PR[5]

大量創建 svc 的時候減少創建監聽的步驟只是提交 ipvs/iptables 規則,這樣可以優化連接性能 。另一個就解決某些場景下出現大量的 CLOSE_WAIT 占用 TCP 連接等問題。在 1.22 版本之后就去掉了 PortOpener 邏輯。

kubernetes/pkg/proxy/iptables/proxier.go Line 1304 in f98f27b[6]



1304        proxier.openPort(lp, replacementPortsMap)

7f1968fc-3122-11ee-9e74-dac502259ad0.png

具體是如何沖突的呢? 測試環境是 k8s 1.22.10,kube-proxy 網絡模式 ipvs。以 kubelet 健康檢查為例,調整了節點的內核參數 net.ipv4.ip_local_port_range 為1 024~65535。

7f7e21f2-3122-11ee-9e74-dac502259ad0.png

部署 tcpdump 抓包,抓到有健康檢查失敗的事件后,停止抓包。

看到 kubelet 是用節點 IP(192.168.66.27)+隨機端口 32582 向 pod 發起了 TCP 握手 podIP(192.168.66.65)+80,但是 pod 在 TCP 握手時回 SYN ACK 給 kubelet 的時候,目標端口是 32582,卻一直在重傳。因為這個隨機端口剛好是某一個服務的nodeport,所以優先被 IPVS 攔截給規則后端的服務,但這個后端服務 (192.168.66.9) 并沒有發起和 podIP(192.168.66.65)TCP 建連,所以后端服務 (192.168.66.9) 直接是丟棄的。那么 kubelet 就不會收到 SYN ACK 回應,TCP 無法建聯,所以導致健康檢查失敗。 這個報文看 kubelet 發起 TCP 握手,pod 回 syn ack 的時候一直重傳。


7f9366de-3122-11ee-9e74-dac502259ad0.png


實際是發送到了 32582 這個 svc 的后端 pod 了,直接是丟棄。


7fbf524e-3122-11ee-9e74-dac502259ad0.png7fd6a26e-3122-11ee-9e74-dac502259ad0.png

增加前置判斷

所以 hostnework 可以加上一個判斷,通過 initContainers 容器修改的時候,如果 podIP 和 hostIP 不相等才修改 net.ipv4.ip_local_port_range 參數,避免誤操作導致修改節點的內核參數。



      initContainers:
        - command:
            - /bin/sh
            - '-c'
            - |
              if [ "$POD_IP" != "$HOST_IP" ]; then
              mount -o remount rw /proc/sys
              sysctl -w net.ipv4.ip_local_port_range="1024 65535"
              fi
          env:
            - name: POD_IP
              valueFrom:
                fieldRef:
                  apiVersion: v1
                  fieldPath: status.podIP
            - name: HOST_IP
              valueFrom:
                fieldRef:
                  apiVersion: v1
                  fieldPath: status.hostIP
          securityContext:
            privileged: true
...

如何正確配置 NodePort 范圍

在 Kubernetes中,APIServer 提供了 ServiceNodePortRange 參數(命令行參數 --service-node-port-range),該參數是用于限制 NodePort 或 LoadBalancer 類型的 Service 在節點上所監聽的 NodePort 端口范圍,該參數默認值為 30000~32767。在 ACK Pro 集群中,您可以通過自定義 Pro 集群的管控面參數修改該端口范圍。具體操作,請參見自定義 ACK Pro 集群的管控面參數[7]

8003c776-3122-11ee-9e74-dac502259ad0.png


80158fd8-3122-11ee-9e74-dac502259ad0.png

在修改 NodePort 端口范圍時必須十分謹慎。務必保證 NodePort 端口范圍與集群節點上 Linux 內核提供的 net.ipv4.ip_local_port_range 參數中的端口范圍不沖突。該內核參數 ip_local_port_range 控制了 Linux 系統上任意應用程序可以使用的本地端口號范圍。ip_local_port_range 的默認值為 32768~60999,Nodeport 默認值為 30000~32767。

ACK 集群在默認配置情況下,ServiceNodePortRange 參數和 ip_local_port_range 參數不會產生沖突。如果您此前為了提升端口數量限制調整了這兩個參數中任意一個,導致兩者范圍出現重合,則可能會產生節點上的偶發網絡異常,嚴重時會導致業務健康檢查失敗、集群節點離線等。建議您恢復默認值或同時調整兩個端口范圍到完全不重合。

調整端口范圍后,集群中可能存在部分 NodePort 或 LoadBalancer 類型的 Service 仍在使用 ip_local_port_range 參數端口范圍內的端口作為 NodePort。此時您需要對這部分 Service 進行重新配置以避免沖突,可通過 kubectl edit 的方式直接將 spec.ports.nodePort 字段的值更改為未被占用的 NodePort。

審核編輯:湯梓紅
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 內核
    +關注

    關注

    3

    文章

    1363

    瀏覽量

    40228
  • 容器
    +關注

    關注

    0

    文章

    494

    瀏覽量

    22044
  • 代碼
    +關注

    關注

    30

    文章

    4746

    瀏覽量

    68348
  • Address
    +關注

    關注

    0

    文章

    6

    瀏覽量

    7561

原文標題:記一次容器環境下出現Address not available

文章出處:【微信號:OSC開源社區,微信公眾號:OSC開源社區】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    【freeRTOS開發筆記】一次坑爹的freeTOS升級

    【freeRTOS開發筆記】一次坑爹的freeTOS-v9.0.0升級到freeRTOS-v10.4.4
    的頭像 發表于 07-11 09:15 ?4557次閱讀
    【freeRTOS開發筆記】<b class='flag-5'>記</b><b class='flag-5'>一次</b>坑爹的freeTOS升級

    使用HAProxy軟件的一次學習過程介紹

    一次學習過程
    發表于 06-13 10:48

    一次網站設計稿的方法

    一次網站設計稿
    發表于 06-16 09:43

    一次電池為什么不能被充電?

    一次電池為什么不能被充電? 一次電池不能被充電再生是構成一次電池體系的本性所決定的,因為一次電池的電極反應不可逆,也就是說,放電后的放電產
    發表于 10-28 15:29 ?5815次閱讀

    循環充放電一次就是少一次壽命嗎?

    循環充放電一次就是少一次壽命嗎?     循環就是使用,我們是在使用電池,關心的是使
    發表于 11-11 13:59 ?844次閱讀

    電池循環充放電一次就是少一次壽命嗎?

    電池循環充放電一次就是少一次壽命嗎? 循環就是使用,我們是在使用電池,關心的是使用的時間,為了衡量充電電池
    發表于 09-06 11:05 ?3593次閱讀

    一次CH552不識別無法下載解決辦法

    一次CH552不識別解決辦法插入鏈接與圖片如何插入段漂亮的代碼片生成個適合你的列表創建個表格設定內容居中、居左、居右SmartyPa
    發表于 01-12 19:15 ?5次下載
    <b class='flag-5'>記</b><b class='flag-5'>一次</b>CH552不識別無法下載解決辦法

    電氣一次識圖基礎

    電氣一次識圖基礎
    的頭像 發表于 11-12 11:24 ?2100次閱讀

    一次消諧如何接線

    一次消諧如何接線 一次消諧器是種用于消除電力系統中諧波的裝置,通常需要與電容器和電抗器組合使用。在安裝一次消諧器時,需要注意以下接線步驟:
    的頭像 發表于 03-22 16:50 ?2030次閱讀

    選擇一次消諧器時需要考慮的些重要標準

    器,而低電壓系統則更適合使用二消諧器。 2. 電容器容量:大容量電容器適用于一次消諧器,而小型電容器則更適合使用二
    的頭像 發表于 06-27 13:52 ?664次閱讀

    一次調頻和二調頻的概念 一次調頻可以實現無差調節?

    一次調頻和二調頻的概念 一次調頻可以實現無差調節? 一次調頻和二調頻的概念 1.
    的頭像 發表于 10-17 16:15 ?8945次閱讀

    一次消諧裝置的種類介紹

    使用環境可以分為戶內用和戶外用!般戶內用的居多,如果用于戶外,采購時需要特殊說明! 一次消諧裝置根據電壓互感器的絕緣性能,需要分為:半絕緣一次消諧器和全絕緣
    的頭像 發表于 11-15 11:08 ?529次閱讀

    超級電容器和飛輪電池都屬于一次電池嗎

    超級電容器(也稱為超級電容或電化學電容器)和飛輪電池都是儲能技術,但它們不屬于一次電池。
    的頭像 發表于 04-24 17:06 ?955次閱讀

    一次消諧器的構造

    今天來給大家介紹一下一次消諧器的構造。 一次消諧器是種用于消除電力系統中的諧波及無功功率的裝置,它由感性元件和電容器構成,感性元件用于吸收系統中的無功功率,而電
    的頭像 發表于 05-30 14:55 ?366次閱讀

    一次電池分類以及應用場景詳解

    01 一次電池簡介 一次電池即原電池(primarycell、primarybattery)(俗稱干電池),是放電后不能再充電使其復原的電池,通電電池有正極、負極電解以及容器和隔膜等組成。
    的頭像 發表于 09-30 17:52 ?453次閱讀
    <b class='flag-5'>一次</b>電池分類以及應用場景詳解