容器与外部网络的访问,这里涉及2个问题:
- 容器访问外部世界
- 外部世界访问容器
容器访问外部世界
root@JD:~# iptables -t nat -S
-P PREROUTING ACCEPT
-P INPUT ACCEPT
-P OUTPUT ACCEPT
-P POSTROUTING ACCEPT
-N DOCKER
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
-A DOCKER -i docker0 -j RETURN
在 NAT 表中,有这么一条规则:
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
其含义是:如果网桥 docker0 收到来自 172.17.0.0/16 网段的外出包,把它交给 MASQUERADE 处理。而 MASQUERADE 的处理方式是将包的源地址替换成 host 的地址发送出去,即做了一次网络地址转换(NAT)
-
容器内ping百度
root@JD:~# docker run -it busybox / # ping www.baidu.com PING www.baidu.com (106.120.159.141): 56 data bytes 64 bytes from 106.120.159.141: seq=0 ttl=48 time=27.228 ms 64 bytes from 106.120.159.141: seq=1 ttl=48 time=27.242 ms 64 bytes from 106.120.159.141: seq=2 ttl=48 time=27.172 ms 64 bytes from 106.120.159.141: seq=3 ttl=48 time=27.263 ms 64 bytes from 106.120.159.141: seq=4 ttl=48 time=27.083 ms 64 bytes from 106.120.159.141: seq=5 ttl=48 time=27.147 ms
-
在docker0上抓icmp
root@JD:~# 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 22:53:51.665408 IP 172.17.0.2 > 106.120.159.142: ICMP echo request, id 1536, seq 0, length 64 22:53:51.693649 IP 106.120.159.142 > 172.17.0.2: ICMP echo reply, id 1536, seq 0, length 64 22:53:52.665515 IP 172.17.0.2 > 106.120.159.142: ICMP echo request, id 1536, seq 1, length 64 22:53:52.693792 IP 106.120.159.142 > 172.17.0.2: ICMP echo reply, id 1536, seq 1, length 64
-
在eth0上抓icmp
root@JD:~# tcpdump -i eth0 -n icmp tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes 22:53:54.665744 IP 192.168.0.3 > 106.120.159.142: ICMP echo request, id 1536, seq 3, length 64 22:53:54.693804 IP 106.120.159.142 > 192.168.0.3: ICMP echo reply, id 1536, seq 3, length 64 22:53:55.665827 IP 192.168.0.3 > 106.120.159.142: ICMP echo request, id 1536, seq 4, length 64 22:53:55.693894 IP 106.120.159.142 > 192.168.0.3: ICMP echo reply, id 1536, seq 4, length 64
docker0 收到 容器 的 ping 包,源地址为容器 IP 172.17.0.2,这没问题,交给 MASQUERADE 处理,ping 包的源地址变成了eth0 的 IP 192.168.0.3
-
处理步骤:
- 容器发送 ping 包:172.17.0.2 > www.baidu.com。
- docker0 收到包,发现是发送到外网的,交给 NAT 处理。
- NAT 将源地址换成 eth0的 IP:192.168.0.3 > www.baidu.com。
- ping 包从 eth0 发送出去,到达 www.baidu.com。
外部世界访问容器
docker 可将容器对外提供服务的端口映射到 host 的某个端口,外网通过该端口访问容器。
root@JD:~# docker run -d -p 80 httpd
92854d59dfa5c7311603df918d102c3d0da4373678d2ab3d835185a5392b666e
root@JD:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
92854d59dfa5 httpd "httpd-foreground" 5 seconds ago Up 4 seconds 0.0.0.0:32768->80/tcp epic_joliot
root@JD:~# curl 192.168.0.3:32768
<html><body><h1>It works!</h1></body></html>
每一个映射的端口,host 都会启动一个 docker-proxy 进程来处理访问容器的流量。
root@JD:~# ps -aux | grep docker-proxy
root 21849 0.0 0.0 108196 2608 ? Sl 23:20 0:00 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 32768 -container-ip 172.17.0.2 -container-port 80
root 22119 0.0 0.0 14224 976 pts/2 S+ 23:21 0:00 grep --color=auto docker-proxy
- 处理步骤
- docker-proxy 监听 host 的 32773 端口。
- 当 curl 访问 10.0.2.15:32773 时,docker-proxy 转发给容器 172.17.0.2:80。
- httpd 容器响应请求并返回结果。
网友评论