Docker系列 14 容器如何访问外部世界
相关命令
docker build -t localtcpdump .
docker run --rm -v /opt/bin:/target localtcpdump
docker run --rm -v /opt/bin:/target ulexus/install-tcpdump
docker run -it busybox
ip r
容器与外部世界通信。这里涉及两个方向:
- 容器访问外部世界
- 外部世界访问容器
容器访问外部世界
在我们当前的实验环境下,docker host 是可以访问外网的。
docker run -it busybox
ip r
ping -c 3 www.bing.com
容器默认就能访问外网
d0httpd1 位于 docker0 这个私有 bridge 网络中(172.17.0.0/16),当 d0httpd1 从容器向外 ping 时,数据包是怎样到达 bing.com 的呢?
这里的关键就是 NAT。我们查看一下 docker host 上的 iptables 规则:
$ iptables -t nas -S
...
-A POSTROUTING -s 172.18.0.0/16 ! -o br-d430eab46516 -j MASQUERADE
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
...
在 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 的路由表:
/ # ip r
default via 172.17.0.1 dev eth0
172.17.0.0/16 dev eth0 scope link src 172.17.0.3
默认路由通过 eth0 发出去,所以我们要同时监控 eth0 和 br-d430eab46516 上的 icmp(ping)数据包。
当 http2 ping bing.com 时,tcpdump 输出如下:
$ tcpdump -i docker0 -n icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on docker0, link-type EN10MB (Ethernet), capture size 262144 bytes
02:16:03.749073 IP 172.17.0.3 > 202.89.233.100: ICMP echo request, id 1792, seq 0, length 64
02:16:03.789452 IP 202.89.233.100 > 172.17.0.3: ICMP echo reply, id 1792, seq 0, length 64
02:16:04.749523 IP 172.17.0.3 > 202.89.233.100: ICMP echo request, id 1792, seq 1, length 64
02:16:04.789413 IP 202.89.233.100 > 172.17.0.3: ICMP echo reply, id 1792, seq 1, length 64
02:16:05.749962 IP 172.17.0.3 > 202.89.233.100: ICMP echo request, id 1792, seq 2, length 64
02:16:05.790665 IP 202.89.233.100 > 172.17.0.3: ICMP echo reply, id 1792, seq 2, length 64
docker0 收到 必须busybox 的 ping 包,源地址为容器 IP 172.17.0.3,这没问题,交给 MASQUERADE 处理。这时,在 eth0 上我们看到了变化:
# 机器没有设备 eth0
$ tcpdump -i eth0 -n icmp