場景描述:html
openstack私有云中的容器服務A(部署在openshift上)須要經過http訪問阿里雲中的B服務,中間須要通過openstack的nat網關,以及阿里雲的lb。但在訪問時發現訪問失敗,A服務沒法獲取B服務的http響應。node
問題分析:linux
容器中的服務A請求阿里雲的服務B時失敗,但在容器所在的node節點直接curl該url是成功的,說明底層網絡鏈接是通的。在A服務和B服務所在的node節點抓包發現,A服務發送http請求時,tcp鏈路是通的,但因爲沒有接收到B服務的http response,A服務判斷業務超時,發送tcp斷鏈docker
但在B服務端能夠看到,它其實已經正確回覆了A服務的http request。所以猜想報文可能被A服務的node或網關丟棄了。json
爲排除問題,將A服務部署在非openstack環境中,環境部署以下,發現A服務能夠正常訪問B服務,能夠排除阿里雲的問題。緩存
回到出問題的環境,出現網絡丟包的緣由通常出如今以下場景:網絡
本環境中網絡負載很小,且數據是能夠在兩端傳輸的,能夠排除1,2兩點。因爲使用curl能夠正常訪問服務B,能夠判斷A服務所在的node節點上的某些配置可能會致使丟包。仔細觀察A服務主動發出的報文和使用curl發出的報文,能夠發現二者在MSS上有所不一樣,A服務發出的MSS爲1460,而使用curl則是1260app
使用以下目錄將A服務所在的node節點從eth0發送的TCP的MSS設置爲1260,此時發現A服務能夠正常訪問B服務curl
iptables -t nat -I POSTROUTING -o eth0 -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu iptables -t nat -I POSTROUTING -o eth0 -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 1260
由此得出,該問題是由於A服務發出的MTU不正確致使的。使用ip link命令查看A服務所在節點的eth0的MTU,值爲1300。而A服務所在容器的eth0爲1500,這樣就致使了A服務發出的tcp報文的MSS大於它所在節點的MSS,B服務(MSS爲1460)發送的報文大於A服務所在集羣可接收大小以後會被網關或node節點丟棄tcp
修復方法:
在docker daemon中添加以下參數,重啓docker(必要時重啓node)便可將容器的mss修改成1260
# cat /etc/docker/daemon.json { "mtu": 1300 }
PS: