Docker一台服務器部署多容器,容器A無法通過宿主機外網ip訪問另外一個容器B分析


首先出現這個問題,都是iptables ---input chain 設置了默認Policy 為 Drop導致的(如果默認全都是 accept或者沒有其他拒絕策略,肯定是沒問題的。)

這是我服務器上的INPUT規則如下:

 

 3306 ,6379那幾個, 分別是mysql容器和 redis容器對應的端口號,第一行表示,input默認策略是 Drop。

這台服務器的結構很簡單,就是一張外網網卡, 直接接外網,eth0 ,  ip=101.*。*。*,   然后docker0網橋,  172.17.0.1  

此時,我新建了一個nginx容器, 做了端口映射, 9999--》 容器里的80,

 

容器啟動后, docker會自動在 Iptable添加相應的轉發規則的,如果從別的服務器上, 訪問   該容器服務器外網ip 101 : 9999, 其實是可以訪問成功的。

我們可以拿iptabels 分析一下。

從外面進來的數據包, 會首先走iptables的prerouting鏈, 但是在這里, nat表里是有一條規則的,

 

可以看到第一個粗紅框中 ,in out src dest 不是*就是0, 后面跟了一個 addrtype的模塊,match dest = local,

首先前面四個,肯定命中,剩下的,就是匹配目標ip是不是本機了, 既然是直接訪問宿主機的Ip,那就肯定 = local了,所以這條規則會命中, 從 prerouting鏈,jump到  docker鏈,即第二個粗紅框

這里,我們依然要挨個檢查,是否能命中規則(這里不太清楚,應該是執行完了,依然要返回調用方,即 prerouting) 

第一條,in = docker0,肯定不對, 我們只有一個外網網卡接口 eth0, 所以忽略,第二條, in 命中, 不是docker0, src和 dest不管了, 命中, dport就不對了, 是6379, 我們訪問的是9999,

一看, 最后一條命中了, targe是 dnat,即目標地址轉換, 轉換成  172.17.0.6,端口由 9999轉成80.

然后返回到 prerouting里, 這里貼一張圖,就很清晰的看到iptables都干了什么了。

 

 

剛才 ,從docker鏈判斷完了, 做了目標地址轉換后, 返回了 上面的那個紫框,  nat-prerouting, 然后要繼續往下執行, 判斷是否是本機IP(這里本機ip有連個,1.外網ip101****, 第二個是 docker0網橋上的ip  172.17.0。1,由於剛才把ip換成了172.17.0.6了,所以判斷是fale, 只能走forward鏈了, 不能走input了。(這也是為什么,最早的時候, 安裝docker,一定要提前把Ip_foward打開   = 1),foward鏈中也有幾個規則, 不過不影響大局,就不分析了。

這是一個正常的使用流程。

問題是, 我們再使用過程中 ,偶爾會出現,一個容器要訪問另一個容器,如果直接使用容器ip,會不太方便,而公網ip大家都知道,一般人肯定會用公網ip去訪問另一個容器, 這時候,如果Iptables不做更改,我們這里就出現了一個異常,

容器a訪問   101.*。*。*:9999, 居然連接超時,無響應。

我們仔細想一下,容器a的包,正常出去, 通過容器a的路由表, 肯定只能發送給網橋那個172.17.0.1的ip, 通過tcpdump抓包,我們可以看到  宿主機 docker0網卡有數據進來(廢話,容器的出包,也只能走這個網卡了)

 

 這就很簡單了,既然知道了是從docker0進來的,那就繼續走一邊iptables,就知道包到底被誰干掉了。

1. prerouting鏈, 是發給LOCAL的數據,命中,跳轉到 docker鏈, 這個時候, 跟從外面來的包就不一樣了,因為會命中  docker鏈 nat表的第一個規則 ,In 的確是  docker0, target = return,什么都沒干,就返回到了prerouting, 然后判斷host,發現是本機,不能歐foward鏈了,要走input,這個時候, input里的各種規則就起作用了, 咱們根本就沒有添加相應的rule,(只有原來的那些22啊, 3306之類的,9999是沒有的,所以就被默認drop了,導致無響應), 這么一分析,其實就清晰了, 所以如果要想讓9999對本機的容器(記住一定是本機的容器(因為容器的src ip無法匹配local的,不然  本機給本機發包, 感覺input沒攔截,這里沒太弄懂,不知道到底本機ip1to本機ip2到底忽略了什么))也能聯通, 只需要在input里增加一條 --dport 9999 -j accept的規則就好了 (而且source ip 可以為 172.17.0.0/24)這個段,不一定非要開全網的,因為  tcpdump抓的包明顯能看出來,不可能是非容器段的Ip的。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM