网络基础

介绍部分docker的网络驱动

bridge网络

docker0网桥

当在一台Linux系统的机器上装了Docker后,在宿主机上使用ifconfig命令可以看到多了一块名为docker0的网卡,我本地的docker0 IP是 172.17.0.0/16,宿主机上也多了一条路由:

#route -n

172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0
这条路由表示所有目的IP为 172.17.0.0/16的数据包都从docker0发出。使用docker创建一个容器,docker run -d busybox,进入到容器中查看网络设备信息ip addr:

1
2
3
4
5
6
7
8
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
77: eth0@if78: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever

该容器网卡eth0连接在 if78这个设备上(不同测试环境可能不一样),在宿主机上执行ip addr,查看网络设备:

1
2
3
4
5
6
...
78: veth3eb50a6@if77: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether 86:5a:5e:ea:1c:60 brd ff:ff:ff:ff:ff:ff link-netnsid 3
inet6 fe80::845a:5eff:feea:1c60/64 scope link
valid_lft forever preferred_lft forever
...

78号设备的设备名称是 veth3eb50a6,然后再执行命令brctl show

1
2
3
...
docker0 8000.0242f959ef4b no veth3eb50a6
...

可以发现设备 veth3eb50a6 连在网桥docker0上。

网桥是一个二层设备,veth3eb50a6和容器中的eth0相当于一根网线的两个端口,整个过程可以看做是:用一根网线把容器和网桥docker0连了起来。当创建容器时如果不指定容器连接到的网络,容器都将连到docker0上,那么容器之间是二层互通的,可以之间相互访问。

至于上边主机上为什么添加路由信息:主机通过路由,使其能够访问容器IP,它工作在三层。

docker多网桥测试

本小节测试容器加入不同的网桥,以及它们之间的连通性。

1
2
3
4
5
6
7
8
9
10
11
12
# 首先创建网络
[root@node ~]# docker network create backend
[root@node ~]# docker network create frontend

# 创建容器 c1,c2,c3,其中,c1,c2接入网桥backend,c2,c3接入网桥 frontend
[root@node ~]# docker run -d --name c1 --net backend busybox
[root@node ~]# docker run -d --name c2 --net backend busybox
[root@node ~]# docker run -d --name c3 --net frontend busybox
[root@node ~]# docker network connect frontend c2

# 从以上来看, c1,c2同时接入网桥backend两者二层连通,c2,c3同理接入网桥frontend。
# c2上插了两根网线,分别接入了backend和frontend。

分别进入 c1 c2 c3测试另外两个容器连通性,结果如下:

- c1 c2 c3
c1 - true false
c2 true - true
c3 false true -

符合预期。

此时在宿主机上使用 ip addr命令可以看到新增的两个网桥和ip,使用route命令可以看到对应的r转发到这两个容器的路由信息。

iptables

如果需要docker容器访问外部网络,则需要对宿主机进行配置:

  1. 允许Linux内核IP转发 sysctl net.ipv4.conf.all.forwarding=1
  2. 将iptables FORWARD的策略从DROP改为AACEPT

当访问外部时,对其做SNAT(源地址转化),对外部来说,就是宿主机在访问,外部感知不到容器的存在。

如果外部访问容器,则需要做端口映射,在启动容器时指定参数 -p 主机端口:容器端口,在iptables的nat和filter 的DOCKER链中会增加一条规则,将访问宿主机指定端口的流量转发到容器中,所以外界访问Docker容器是通过DNAT(目的地址转换)实现的。可以通过在filter的DOCKER链上添加规则来限制源IP的数据包访问容器。

overlay网络

docker中的overlay驱动使用IETF标准的VXLAN方式。

TODO

高级网络

Linux NetworkNamespace

TODO

容器跨主机访问方案

TODO