4种网络类型
Docker 安装时会自动在 host 上创建三个网络,我们可用 docker network ls 命令查看:
none网络
none 网络就是什么都没有的网络。挂在这个网络下的容器除了 lo,没有其他任何网卡。容器创建时,可以通过 —network=none 指定使用 none 网络。
对安全性要求高并且不需要联网的应用可以使用 none 网络。
[root@instance-7degfn ~]# docker run -it --network=none busyboxUnable to find image 'busybox:latest' locallylatest: Pulling from library/busyboxb71f96345d44: Pull completeDigest: sha256:0f354ec1728d9ff32edcd7d1b8bbdfc798277ad36120dc3dc683be44524c8b60Status: Downloaded newer image for busybox:latest/ # ifconfiglo Link encap:Local Loopbackinet addr:127.0.0.1 Mask:255.0.0.0UP LOOPBACK RUNNING MTU:65536 Metric:1RX packets:0 errors:0 dropped:0 overruns:0 frame:0TX packets:0 errors:0 dropped:0 overruns:0 carrier:0collisions:0 txqueuelen:1RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
host 网络
连接到 host 网络的容器共享 Docker host 的网络栈,容器的网络配置与 host 完全一样。可以通过 —network=host 指定使用 host 网络。
[root@instance-7degfn ~]# docker run -it --network=host busybox/ # ip l1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:002: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast qlen 1000link/ether fa:16:3e:fd:07:43 brd ff:ff:ff:ff:ff:ff3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueuelink/ether 02:42:7f:d2:4d:94 brd ff:ff:ff:ff:ff:ff9: veth7f5a9f9@if8: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue master docker0link/ether c6:ce:08:10:d5:e5 brd ff:ff:ff:ff:ff:ff13: veth4e45597@if12: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue master docker0link/ether 96:7a:0e:d7:97:d0 brd ff:ff:ff:ff:ff:ff
直接使用 Docker host 的网络最大的好处就是性能,如果容器对网络传输效率有较高要求,则可以选择 host 网络。当然不便之处就是牺牲一些灵活性,比如要考虑端口冲突问题,Docker host 上已经使用的端口就不能再用了。
Docker host 的另一个用途是让容器可以直接配置 host 网路。比如某些跨 host 的网络解决方案,其本身也是以容器方式运行的,这些方案需要对网络进行配置,比如管理 iptables
bridge 网络
Docker 安装时会创建一个 命名为 docker0 的 linux bridge。如果不指定—network,创建的容器默认都会挂到 docker0 上。
创建1个容器,这时看到1个新的网络接口 veth10f829c 被挂到了 docker0 上,veth10f829c就是新创建容器的虚拟网卡。
下面看一下容器的网络配置。
容器有一个网卡 eth0@if43。 eth0@if43 和 veth10f829c 是一对 veth pair。veth pair 是一种成对出现的特殊网络设备,可以把它们想象成由一根虚拟网线连接起来的一对网卡,网卡的一头(eth0@if43)在容器中,另一头(veth10f829c)挂在网桥 docker0 上,其效果就是将 eth0@if43 也挂在了 docker0 上。
我们还看到 eth0@if34 已经配置了 IP 172.17.0.2,为什么是这个网段呢?让我们通过 docker network inspect bridge 看一下 bridge 网络的配置信息:
原来 bridge 网络配置的 subnet 就是 172.17.0.0/16,并且网关是 172.17.0.1。这个网关在哪儿呢?大概你已经猜出来了,就是 docker0。
主机上的网卡配置:
容器创建时,docker 会自动从 172.17.0.0/16 中分配一个 IP,这里 16 位的掩码保证有足够多的 IP 可以供容器使用。
user-defined 网络
Docker 提供三种 user-defined 网络驱动:bridge, overlay 和 macvlan。
overlay 和 macvlan 用于创建跨主机的网络
我们可通过 bridge 驱动创建类似前面默认的 bridge 网络,例如:
查看一下当前 host 的网络结构变化:
新增了一个网桥 br-eaed97dc9a77,这里 eaed97dc9a77 正好新建 bridge 网络 my_net 的短 id。执行 docker network inspect 查看一下 my_net 的配置信息:
这里 172.18.0.0/16 是 Docker 自动分配的 IP 网段。
我们可以自己指定 IP 网段吗?
答案是:可以。
只需在创建网段时指定 —subnet 和 —gateway 参数:
这里我们创建了新的 bridge 网络 my_net2,网段为 172.22.16.0/24,网关为 172.22.16.1。
与前面一样,网关在 my_net2 对应的网桥 br-5d863e9f78b6 上:
容器要使用新的网络,需要在启动时通过 —network 指定:
容器分配到的 IP 为 172.22.16.2。
到目前为止,容器的 IP 都是 docker 自动从 subnet 中分配,我们能否指定一个静态 IP 呢?
答案是:可以,通过—ip指定。
注:只有使用 —subnet 创建的网络才能指定静态 IP。
my_net 创建时没有指定 —subnet,如果指定静态 IP 报错如下:
好了,我们来看看当前 docker host 的网络拓扑结构。
容器间通信
单主机的容器间通信
同一网络中的容器、网关之间都是可以通信的。
两个 busybox 容器都挂在 my_net2 上,能够互通。
确实,如果 host 上对每个网络的都有一条路由,同时操作系统上打开了 ip forwarding,host 就成了一个路由器,挂接在不同网桥上的网络就能够相互通信。下面我们来看看 docker host 满不满足这些条件呢?
https://mp.weixin.qq.com/s?__biz=MzIwMTM5MjUwMg==&mid=2653587690&idx=1&sn=770e7bbd74377f84bd5e8ee0f42ca194&chksm=8d3080f3ba4709e5f3a8fe9b666a5db5b246746271952828eed2d6d34cb19076d5cde2aeb6a7&scene=21#wechat_redirect
https://mp.weixin.qq.com/s?__biz=MzIwMTM5MjUwMg==&mid=2653587693&idx=1&sn=0f0b0b7e41d8edb0ed5f8a0b4224a0db&chksm=8d3080f4ba4709e22f4baf33de67fedd4f351784c77d97a97a6477a6a522ef5faaa90e612550&scene=21#wechat_redirect
跨主机的容器间通信
外部世界与容器相互访问
容器访问外部世界
容器默认就能访问外网。
在上面的例子中,busybox 位于 docker0 这个私有 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)。
https://mp.weixin.qq.com/s?__biz=MzIwMTM5MjUwMg==&mid=2653587698&idx=1&sn=2c5daabe40993a1296f16d2ae2f1e0d0&chksm=8d3080ebba4709fda09412d98e5e0c42d9d3e14ac862bbaf648af655b5b62edf03d10b07c6a0&scene=21#wechat_redirect
外部世界访问容器
端口映射
docker 可将容器对外提供服务的端口映射到 host 的某个端口,外网通过该端口访问容器。容器启动时通过-p参数映射端口:
容器启动后,可通过 docker ps 或者 docker port 查看到 host 映射的端口。在上面的例子中,httpd 容器的 80 端口被映射到 host 32773 上,这样就可以通过 
除了映射动态端口,也可在 -p 中指定映射到 host 某个特定端口,例如可将 80 端口映射到 host 的 8080 端口:
每一个映射的端口,host 都会启动一个 docker-proxy 进程来处理访问容器的流量:
以 0.0.0.0:32773->80/tcp 为例分析整个过程:
- docker-proxy 监听 host 的 32773 端口。
- 当 curl 访问 10.0.2.15:32773 时,docker-proxy 转发给容器 172.17.0.2:80。
- httpd 容器响应请求并返回结果。
