使用docker時有時遇到問題,查閱相關問題,解決方法時重啟docker服務。實際測試可以解決問題,那docker daemon重啟,究竟改變了什么?
如docker run時遇到如下問題:
docker: Error response from daemon: driver failed programming external connectivity on endpoint node1 (9cedc114be35eb86cd6f7f7bb4f11f93b5f8d2c0745afc72664cef8e96aad439): iptables failed: iptables --wait -t filter -A DOCKER ! -i docker0 -o docker0 -p tcp -d 172.17.0.2 --dport 3000 -j ACCEPT: iptables: No chain/target/match by that name. (exit status 1).
docker daemon啟動過程會初始化一系列的iptables規則以及修改部分內核參數(如net.ipv4.ip_forward)。
經過對比分析,可以看到docker啟動,分別在filter和nat建立了名為DOCKER的chain,
在forward轉發鏈增加了一些ACCEPT規則,在nat增加了postrouting和prerouting以及output的規則。
- filter表中的forward主要是對容器和宿主機以及本機容器之間數據包的放行。
- 上面的docker run報錯就是因為沒有filter和nat中的DOCKER chain導致的,感興趣的同學可以手動清空iptables然后手動創建這兩個chain,會發現可以run端口映射的容器了,因為docker run增加的規則就是在這兩個表中的DOCKER chain下添加的。
- 再說一下nat表的
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
這條規則。
這條規則是處理docker的SNAT地址偽裝用的。具體含義是將容器網絡網段發送到外部的數據包(!-o docker0)偽裝成宿主機的ip,就是講數據包的原來的容器ip換成了宿主機ip,做了一次snat。對於這個我們也踩過坑,不經snat轉換的容器數據包被我們其他節點的防火牆給攔截了(限制非vm網段的ip),導致訪問失敗。 - -A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
這條的含義是把目標地址類型屬於主機系統的本地網絡地址的數據包,在數據包進入NAT表PREROUTING鏈時,都讓它們直接jump到一個名為DOCKER的鏈。
容器數據包發送到host外就需要nat規則以實現docker地址偽裝成主機ip。如沒有此規則,數據包以docker地址發送,而docker地址是局域網地址,不能接收到回應數據包。