Docker網絡(host、bridge、none)詳細介紹
Docker容器間通信
前面我們已經解決了容器間通信的問題,接下來討論容器如何與外部世界通信。
這裏涉及兩個方向:
(1)容器訪問外部世界。
(2)外部世界訪問容器。
容器訪問外部世界
在我們當前的實驗環境下,docker host是可以訪問外網的
我們看一下容器是否也能訪問外網呢?
可見,容器默認就能訪問外網。
請注意:這裏外網指的是容器網絡以外的網絡環境,並非特指Internet.
現象很簡單,但更重要的:我們應該理解現象下的本質。
在上面的例子中,busybox位於dockero這個私有bridge網絡中(172.17.0.0/16),當busybox從容器向外ping時,數據包是怎樣到達bing.com的呢?
這裏的關鍵就是NAT,我們查看一下docker host上的iptables規則
在NAT表中,有這麼一條規則:
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
其含義是:如果網橋docker0收到來自172.17.0.0/16網段的外出包,把它交給MASQUERADE處理。而且MASQUERADE的處理方式是將
包的原地址替換成host的地址發送出去,機 做了一次網絡地址轉換(NAT)
下面我們通過tcpdump查看地址是如何轉換的。先查看docker host的路由表
默認路由通過ens192發出去,所以我們同時要監控ens192和docker0上的icmp(ping)的數據包。
當busybox ping www.baidu.com時,tcpdumo輸出如下
tcpdump -i docker0 -n icmp
docker0收到busybox的ping包,源地址爲容器的IP:172.17.0.2,這沒問題,交給MASQUERADE處理。這時,在看ens192的變化。
ping包的源地址變成ens192的192.168.1.100
這就是iptables的NAT規則的處理結果,從而保證數據包能夠到達外網。
下面這張圖來說明結果。
- (1)busybox發送ping包:172.17.0.2 > www.bing.com。
- (2)dockero收到包,發現是發送到外網的,交給NAT處理。
- (3)NAT將源地址換成ens192的IP:10.0.2.15 >www.bing.com.
- (4)ping從 ens192出去,達www.bing.como
通過NAT,docker實現了容器對外網的訪問。
外部世界訪問容器
下面我們來討論另一個方向:外網如何訪問到容器?
答案是:端口映射。
docker可將容器對外提供服務的端口映射到host的某個端口,外網通過該端口訪問容器。容器啓動時通過-p參數映射端口
[root@kvm ~]# docker run -d -p 80 httpd
6b89d7e3f47a425256af6934689c0009fbbad9099bf31c2e6148a6cb236a9655
[root@kvm ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6b89d7e3f47a httpd "httpd-foreground" 5 seconds ago Up 2 seconds 0.0.0.0:32768->80/tcp stoic_bartik
78de9710bce0 busybox "sh" 19 minutes ago Up 19 minutes hei
[root@kvm ~]# docker port 6b89d7e3f47a
80/tcp -> 0.0.0.0:32768
容器啓動後,可通過docker ps或者docker port查看到host映射的端口。在上面的例子中,httpd容器的80端口被映射到host 32768上,這樣就可以通過<host ip>:<32773>訪問容器的Web服務了
除了映射動態端口,也可在-p中指定映射到host某個特定端口,例如可將80端口映射到host的8080端口
[root@kvm ~]# docker run -d -p 8080:80 httpd
8d7db7b2c7a6fc03cd219d6d3c07f15261d8a12efda3be25fdb60576c91c1a7e
[root@kvm ~]# curl 192.168.1.100:8080
<html><body><h1>It works!</h1></body></html>
[root@kvm ~]#
每一個映射的端口,host都會啓動一個docker-proxy進程來處理訪問容器的流量。
以0.0.0.0:32773-280/tcp爲例分析整個過程
- (1)docker-proxy監聽host的32773端口。
- (2)當curl訪問10.0.2.15:32773時,docker-proxy轉發給容器172.170.2:80。
- (3)httpd容器響應請求並返回結果。