docker系列(三) docker的网络模式之内部通信

简介

关于docker的安装文档,请参照上篇文章<docker系列二在宿主机上的安装和卸载>,本文主要针对docker中容器间的通信方式之内部通信进行说明。

容器间的通信

自从docker容器出现,容器的网络通信一直是众人关注的焦点,而容器的网络方案又可以分为两大部分:

  1. 单主机的容器间通信;
  2. 跨主机的容器间通信。

单主机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 {
         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
/ # 
原文地址:https://www.cnblogs.com/chenxiba/p/11327933.html