docker系列(三) docker的网络模式之内部通信
简介
关于docker的安装文档,请参照上篇文章<docker系列二在宿主机上的安装和卸载>,本文主要针对docker中容器间的通信方式之内部通信进行说明。
容器间的通信
自从docker容器出现,容器的网络通信一直是众人关注的焦点,而容器的网络方案又可以分为两大部分:
- 单主机的容器间通信;
- 跨主机的容器间通信。
单主机Docker网络通信
我们在使用docker run创建 Docker 容器时,可以使用--network=选项指定容器的网络模式,Docker 有以下 4 种网络模式:
- host 模式,使用--network=host指定,不支持多主机;
- bridge 模式,使用--network=bridge指定,默认设置,不支持多主机;
- container 模式,使用--network=container:NAME_or_ID指定,即joiner 容器,不支持多主机;
- none 模式,使用--network=none指定,不支持多主机。
bridge模式
bridge之使用默认网桥
当Docker进程启动时,会在主机上创建一个名为docker0的虚拟网桥,此主机上启动的Docker容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中。从docker0子网中分配一个 IP 给容器使用,并设置 docker0 的 IP 地址为容器的默认网关。在主机上创建一对虚拟网卡veth pair设备,Docker 将 veth pair 设备的一端放在新创建的容器中,并命名为eth0(容器的网卡),另一端放在主机中,以vethxxx这样类似的名字命名,并将这个网络设备加入到 docker0 网桥中。可以通过brctl show命令查看。安装brctl命令:
yum install -y bridge-utils
[root@linux-node4 ~]# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.0242d84b7159 no
bridge模式是 docker 的默认网络模式,不写–net参数,就是bridge模式。使用docker run -p时,docker 实际是在iptables做了DNAT规则,实现端口转发功能。可以使用iptables -t nat -vnL查看。bridge模式如下图所示:
实验过程如下:
- 步骤一:创建两个容器
docker run --name docker1 nginx:1.13.12 docker run -d --name docker2 nginx:1.13.12
- 步骤二:查看机器上多了两个veth虚拟网卡,查看网络地址如我们之前说的一样
[root@linux-node4 ~]#
[root@linux-node4 ~]# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.0242d84b7159 no veth8c72f4a
vethf15e034
[root@linux-node4 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
75539117a127 nginx:1.13.12 "nginx -g 'daemon of…" About an hour ago Up About an hour 80/tcp docker2
69f1c16d206c nginx:1.13.12 "nginx -g 'daemon of…" About an hour ago Up About an hour 80/tcp docker1
[root@linux-node4 ~]# docker inspect 75539117a127 |grep 172.17
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.3",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.3",
bridge之使用自定义网桥
使用自定义的网桥
docker network create -d bridge my-net4 --subnet=192.168.100.1/24
创建一个自定义网桥-d指定模式为bridge,也可以为overlay,--subnet指定子网范围;
创建两个容器,并连接到我们自建的网桥:
[root@linux-node4 ~]# docker run -d --name=my_test1 --network my-net4 nginx:1.13.12
ffc47de3992c52730ff2590b4b3903fe737521b9c713170d19b747fa2941c8b1
查看容器的网络地址,验证其ip地址是否是我们自定义的网络。
[root@linux-node4 ~]# docker inspect ffc47de3992 |grep 192
"Gateway": "192.168.100.1",
"IPAddress": "192.168.100.2",
注意同一个网桥内的网络是相互可以通信的,本篇不做过多说明。
host模式
如果启动容器的时候使用host模式,那么这个容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个 Network Namespace。容器将不会虚拟出自己的网卡,配置自己的 IP 等,而是使用宿主机的 IP 和端口。但是,容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的。 Host模式如下图所示:
验证步骤如下:
创建一个网络类型为host的容器
docker run -d --net=host --name=my_host1 nginx:1.13.12
因为nginx容器本身的端口号是80,所以我们直接使用本地的接口来访问宿主机的ip和端口号。
[root@linux-node4 ~]# !curl
curl http://127.0.0.1:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
如果使用这种网络模式的时候注意不要一个容器启动多个实例,会引起端口冲突不能起来,这种网络模型是无法使用nat转化的。
host模式有利也有弊,主要包括以下缺点:
- 容器没有隔离、独立的网络栈:容器因为与宿主机共享网络而争抢资源,并且容易崩溃也可能导致主机崩溃,这在生产环境是不允许发生的;
- 端口资源:docker host上已经使用的端口就不能再使用了
host模式的优点如下:- 可以直接使用宿主机ip与外界通信,无需额外进行nat转换,由于容器与外部通信,不再需要使用bridge等方式转发或者进行数据包的封装,性能上有很大优势。
container模式
这个模式指定新创建的容器和已经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过 lo 网卡设备通信。 Container模式示意图:
我们还是通过实验来验证这个结论吧,上文我们已经创建了一个自定义网桥的容器,链接到这个容器里面即可
[root@linux-node4 ~]# docker run -d --name docker_con3 --net=container:ffc47de3992c busybox sleep 6000
933dd7fce1a67883869a6235c3a4f7835c983e079592087734715d05f6bd755e
进入容器内部验证网络是否跟预期一致:
[root@linux-node4 ~]# docker exec -it 933dd7fce1a6 sh
/ # ip addr
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
33: eth0@if34: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:c0:a8:64:02 brd ff:ff:ff:ff:ff:ff
inet 192.168.100.2/24 brd 192.168.100.255 scope global eth0
valid_lft forever preferred_lft forever
/ # route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 192.168.100.1 0.0.0.0 UG 0 0 0 eth0
192.168.100.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
None模式
使用none模式,Docker 容器拥有自己的 Network Namespace,但是,并不为Docker 容器进行任何网络配置。也就是说,这个 Docker 容器没有网卡、IP、路由等信息。需要我们自己为 Docker 容器添加网卡、配置 IP 等。 None模式示意图:
[root@linux-node4 ~]# docker run -d --net=none --name docker_none2 busybox sleep 6000
247fb9eace8b5dedcb47b7f2015eb06f18d4eb67eb323560dcfaaf7ef1069773
网络情况验证:
[root@linux-node4 ~]# docker exec -it 247fb9eace8b /bin/sh
/ # ip addr
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
/ # route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
/ #