由于docker容器访问外部网络及对外提供服务都使用到iptable,我们先了解下iptable的基础知识。
一、Iptables
1、iptables的链
iptables有5条默认的链,分别为:
- INPUT
- OUTPUT
- PREROUTING
- FORWARD
- POSTROUTING
2、iptables的表
- iptables有4张表,分别为:
- filter表,负责过滤功能
- nat表,网络地址转换功能
- managle表,拆解报文,做出修改,并重新封装 的功能
- raw表,关闭nat表上启用的连接追踪机
3、链表的关系
链中的规则属于四种表的其中一种
4、常见的数据流向
- 到本机某进程的报文:PREROUTING --> INPUT
- 由本机转发的报文:PREROUTING --> FORWARD --> POSTROUTING
- 由本机的某进程发出报文(通常为响应报文):OUTPUT --> POSTROUTING
二、容器访问外部网络
1、容器访问外部网络是通过iptable的snat实现访问外部网络的
# docker run -it busybox / # ping www.baidu.com PING www.baidu.com (14.215.177.39): 56 data bytes 64 bytes from 14.215.177.39: seq=0 ttl=50 time=3.459 ms 64 bytes from 14.215.177.39: seq=1 ttl=50 time=3.432 ms ^C --- www.baidu.com ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 3.432/3.445/3.459 ms / # ifconfig eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:02 inet addr:172.17.0.2 Bcast:172.17.255.255 Mask:255.255.0.0 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:6 errors:0 dropped:0 overruns:0 frame:0 TX packets:6 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:989 (989.0 B) TX bytes:426 (426.0 B)
查看nat表
# iptables -t nat -S …… -A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE ……
nat表规则表明,对于源地址为172.17.0.0/16段,出口网卡不是docker0的数据包进行nat转换
2、数据包的流程图如下
三、容器对外提供服务
1、Docker容器是通过dnat映射或docker-proxy服务对外提供访问的
# docker run -d -p 8080:80 httpd //-p 8080:80表示将访问宿主机8080端口的数据包转发到容器80端口的服务。 # netstat -tlunp|grep 8080 tcp6 0 0 :::8080 :::* LISTEN 11718/docker-proxy # iptables -S -t nat …… -A DOCKER ! -i docker0 -p tcp -m tcp --dport 8080 -j DNAT --to-destination 172.17.0.2:80 …… # curl "http://127.0.0.1:8080" <html><body><h1>It works!</h1></body></html>
2、使用dnat还是docker-proxy?
先给结论
场景 |
转发 |
外部服务器访问10.30.20.87:8080 |
通过iptables nat规则访问 |
本机访问10.30.20.87:8080 |
通过iptables nat规则访问 |
本机访问127.0.0.1:8080 |
通过docker-proxy 转发 |
本机上的容器访问10.30.20.87:8080 |
通过docker-proxy 转发 |
完整的nat表
# 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 POSTROUTING -s 172.17.0.2/32 -d 172.17.0.2/32 -p tcp -m tcp --dport 80 -j MASQUERADE -A DOCKER -i docker0 -j RETURN -A DOCKER ! -i docker0 -p tcp -m tcp --dport 8080 -j DNAT --to-destination 172.17.0.2:80
1、外部服务器访问10.30.20.87:8080
匹配到DNAT规则,访问到容器 -A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER -A DOCKER ! -i docker0 -p tcp -m tcp --dport 8080 -j DNAT --to-destination 172.17.0.2:80
2、本机访问10.30.20.87:8080
匹配到DNAT规则,访问到容器 -A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER -A DOCKER ! -i docker0 -p tcp -m tcp --dport 8080 -j LOG --log-prefix DOCKER-DNAT
3、本机访问127.0.0.1:8080
没有匹配到任何iptable,走docker-proxy
4、本机上的容器访问10.30.20.87:8080
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER -A DOCKER -i docker0 -j RETURN 最后走的docker-proxy