Docker网络
在Docker中,容器作为一种虚拟化形式,通常是与 Docker 主机以及其它容器隔离的系统,但是它们之间又需要进行数据交换。为了实现多个容器之间的协作和数据交换,我们需要将它们连接在一起,这就是网络的作用。
Docker网络模式
安装Docker后,会自动创建三种类型的网络,分别是:bridge、host、none,可通过如下命令查看:
1 | docker network ls |
bridge模式
这是Docker的默认模式,在Docker server启动时,会在宿主机上创建一个名为docker0的虚拟网桥。
Docker会从RFC1918所定义的私有IP网段中,选择一个和宿主机不同的IP地址和子网分配给docker0(通常是172.17.0.0/16这个网段)。可通过如下命令查看:
1 | ip addr show docker0 |
此后,连接到docker0的容器就从这个子网中选择一个未占用的IP使用,同一桥接网络中的容器可以使用这些 IP 地址相互通信。
例如我运行一个redis,再运行一个mysql,可通过如下命令查看:
1 | docker network inspect bridge|grep -aG20 Containers |
此时就会打印容器的相关配置:
1 | "Containers": { |
每当运行一个容器时,新建的容器会自动桥接到这个接口,同时Docker 守护进程会创建一对对等虚拟设备接口 veth pair,将其中一个接口设置为容器的 eth0 接口(容器的网卡),另一个接口放置在宿主机的命名空间中,以类似 vethxxx 这样的名字命名,从而将宿主机上的所有容器都连接到这个内部网络上。
由于Docker网桥是宿主机虚拟出来的,并不是真实的网络设备,那么就表示外部网络无法直接通过Container IP访问到容器内部。想要外部网络访问容器,需要通过-p参数来映射端口,然后访问宿主机:映射端口即可,例如:
1 | docker run -d --name mysql -p 3306:3306 mysql/mysql-server:latest |
容器内是可以访问外网的,和网络模式无关。
宿主机与容器之间是可以通信的,反之,容器与宿主机也是可以通信的:
1 | # 宿主机 ping 容器 |
同一个宿主机上,容器之间也是可以互相通信的,因为每个容器都连接到一个共享的桥接网络。
None模式
启动容器时加上--net=none选项即可以创建None类型网络的容器,None类型的网络,即没有网络,Docker不会设置容器内网络的任何信息,不会对网络进行任何配置.
也就是说,这个网络模式下的Docker 容器没有网卡、IP、路由等信息。只有lo回环网络,因此这种类型的网络没有办法联网,封闭的网络能很好的保证容器的安全性。一些对安全性要求高并且不需要联网的应用可以考虑使用none网络模式。
host模式
宿主机ip地址:192.168.0.164 broadcast:192.168.0.255 指定容器使用host网络模式方式:只需在用docker run命令运行容器的时候加上 --network=host 选项即可。
需要注意的是启动时指定--network=host,如果还指定了-p或-P,那这个时候就会有以下警告,并且通过-p或-P设置的参数将不会起到任何作用,端口号会以主机端口号为主,重复时则递增。例如,如果容器要使用端口3306,而主机上已经有程序在使用3306,Docker会尝试使用3307。
host模式容器不会虚拟出自己的网卡,而是与物理机共享网络,容器没有自己的IP,直接用宿主机IP,下图可以看出在容器中执行ip addr看到的是其宿主机的所有网卡。甚至连hostname也是host的。
host 模式的优点是:容器可以使用宿主机的网卡和外界的通信,不需要转发拆包,性能好。
但 host 模式也有非常严重的缺点:直接占用宿主机端口,会与宿主机其他应用竞争宿主机的网络资源,因此无法用在生产环境。
host模式的网络互通:
- 容器和外网:外部通过宿主机IP:容器端口即可访问容器。
- 容器和宿主机:host模式下,宿主机的IP就是容器的IP,因此可以互访。
- 同一个宿主机上的多个容器:同一个宿主机的多个容器的IP都是宿主机IP,相当于一台宿主机上部署的各类服务,当然是能访问的。
Docker自定义网络
在使用过程中,通常都会使用自定义网络。
创建网络
在docker中,创建网络如下所示:
1 | docker network create app-network |
查看创建的网络
1 | docker network ls |
如果想要使用这个网络,那么在创建容器时,使用--net app-network来指定。
连接网络
通过 docker network connect 网络名称 容器名称 为容器连接新的网络模式。
1 | docker network connect app-network mysql |
通过docker inspect 容器名称查看信息,发现mysql容器多绑定了一个网络
1 | "Networks": { |
断开网络
通过docker network disconnect 网络名称 容器名称命令断开网络。例如:
1 | docker network disconnect app-network mysql |
再次查看容器,发现Networks少了刚才连接的网络
1 | "Networks": { |
删除网络
通过docker network rm 网络名称来删除自定义网络,删除成功后会返回网络模式名称
1 | docker network rm app-network |
容器之间的网络通信
连接在同一个网桥
这样是可以直接通信的。相当于手机和电脑连接到同一个路由器上, 互相可以通信。但是因为容器的IP并不是固定的,所以几乎不会使用容器的IP地址去通信。
使用容器名称通信
这个技术时Docker 1.10开始,在docker daemon中内嵌了一个DNS Server,使得容器可以直接通过容器名称去通信。需要在创建容器的时候指定--name
但是,Docker DNS有限制,只能在user-defined(自定义)网络中使用。默认的bridge是无法使用的。
在同属于一个自定义网桥的两个容器中,是可以直接通过容器名称去通信
不同网桥之间通信
如果需要默认的bridge的容器也要和自定义网桥例如app-network访问,那么就需要上述提到的命令docker network connect 网桥名称 容器名称来实现了。








