容器网络(二)docker容器访问外部网络及对外提供服务

由于docker容器访问外部网络及对外提供服务都使用到iptable,我们先了解下iptable的基础知识。

一、Iptables

1、iptables的链

iptables有5条默认的链,分别为:

  • INPUT
  • OUTPUT
  • PREROUTING
  • FORWARD
  • POSTROUTING

2、iptables的表

  • iptables有4张表,分别为:
  • filter表,负责过滤功能
  •  nat表,网络地址转换功能
  • managle表,拆解报文,做出修改,并重新封装 的功能
  • raw表,关闭nat表上启用的连接追踪机

3、链表的关系

链中的规则属于四种表的其中一种

4、常见的数据流向

容器网络(二)docker容器访问外部网络及对外提供服务

  • 到本机某进程的报文: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、数据包的流程图如下

容器网络(二)docker容器访问外部网络及对外提供服务

三、容器对外提供服务

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

容器网络(二)docker容器访问外部网络及对外提供服务