当我们在单台物理机或虚拟机中运行多个docker容器应用时,这些容器之间是如何进行通信的呢,或者外界是如何访问这些容器的? 这里就涉及了单机容器网络相关的知识。docker 安装后默认

情况下会在宿主机上创建三种类型的网络,我们可以通过:docker network ls 查看,如下所示:

docker network ls
NETWORK ID NAME DRIVER SCOPE
8ad1446836a4 bridge bridge local
3be441aa5d9f host host local
e0542a92df5c none null local

下面将分别介绍这三种网络:

1. none

none网络,只有回环网络,容器内部只挂载了lo虚拟网卡,创建了该网络的容器是不能跟外界进行通信的。我们可以通过--network=none 指定none网络,下面创建一个none网络的容器,并查看

容器里的网络设备。

[root@VM_0_12_centos ~]# docker run -dit --net=none --name=bbox3 busybox
7c97d179f742bcd280d2f436427b18b2381c9588773ca612cd71bf840e0db2ea
[root@VM_0_12_centos ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7c97d179f742 busybox "sh" seconds ago Up seconds bbox3
进入容器只有lo网卡 

[root@VM_0_12_centos ~]# docker exec -it bbox3 sh
/ # ifconfig
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU: Metric:
RX packets: errors: dropped: overruns: frame:
TX packets: errors: dropped: overruns: carrier:
collisions: txqueuelen:
RX bytes: (0.0 B) TX bytes: (0.0 B)
访问外界网络
/ # ping www.baidu.com
ping: bad address 'www.baidu.com' 可以ping通本地回环网络
/ # ping 127.0.0.1
PING 127.0.0.1 (127.0.0.1): data bytes
bytes from 127.0.0.1: seq= ttl= time=0.068 ms
bytes from 127.0.0.1: seq= ttl= time=0.051 ms
bytes from 127.0.0.1: seq= ttl= time=0.067 ms
bytes from 127.0.0.1: seq= ttl= time=0.068 ms
bytes from 127.0.0.1: seq= ttl= time=0.071 ms
^C
--- 127.0.0.1 ping statistics ---
packets transmitted, packets received, % packet loss
round-trip min/avg/max = 0.051/0.065/0.071 ms 无法ping通外部
/ # ping 192.168.1.201
PING 192.168.1.201 (192.168.1.201): data bytes
ping: sendto: Network is unreachable

none 网络使用场景一般比较少见,主要应用于安全性比较高的场景,且不需要与外部进行通信的任务。

2. host 网络 

使用host网络的容器,会与宿主机共享网络栈,如共享ip与端口,优点:性能高,缺点:存在端口号冲突,多个容器无法对外暴露相同端口号。

容器使用host网络可以通过--net=host指定:如下所示:

给容器指定host网络模式
[root@VM_0_12_centos ~]# docker run -dit --net=host --name=nginx1 nginx
48e1df0c535193bfdef92f718de2c76427d88a371f14be1274022288cbe4ece6
可以通过宿主机ip与端口号访问容器应用。

[root@VM_0_12_centos ~]# telnet 172.26.0.12
Trying 172.26.0.12...
Connected to 172.26.0.12.
Escape character is '^]'.
在容器中可以看到 host 的所有网络设备

[root@VM_0_12_centos ~]# docker exec -it nginx1 ifconfig
docker0: flags=<UP,BROADCAST,MULTICAST> mtu
inet 172.17.0.1 netmask 255.255.0.0 broadcast 0.0.0.0
ether ::::: txqueuelen (Ethernet)
RX packets bytes (0.0 B)
RX errors dropped overruns frame
TX packets bytes (0.0 B)
TX errors dropped overruns carrier collisions eth0: flags=<UP,BROADCAST,RUNNING,MULTICAST> mtu
inet 172.26.0.12 netmask 255.255.240.0 broadcast 172.26.15.255
ether :::5d:: txqueuelen (Ethernet)
RX packets bytes (43.7 GiB)
RX errors dropped overruns frame
TX packets bytes (47.2 GiB)
TX errors dropped overruns carrier collisions lo: flags=<UP,LOOPBACK,RUNNING> mtu
inet 127.0.0.1 netmask 255.0.0.0
loop txqueuelen (Local Loopback)
RX packets bytes (4.7 KiB)
RX errors dropped overruns frame
TX packets bytes (4.7 KiB)
TX errors dropped overruns carrier collisions

从host网络与宿主机共享网络栈特性可以得出,host网络能够支持容器的跨主机通信,不同容器之间的通信其实就是不同宿主机之间的不同端口之间的通信。这种方式的很大的弊端就是存在端口

号冲突,同一宿主机多个容器不能暴露同一端口号。其次,这种网络模式并没有充分发挥容器的隔离特性,容器与容器之间其实与宿主机共享网络栈。在大规模部署场景下,容器网络模式不会定义成

host模式。

3. bridge网络模式

默认情况下,我们不指定--net时,创建的容器都是使用的是bridge网络模式。

在该模式下,每创建一个容器都会给容器分配自己的network namespace,如 ip地址。

每个容器都有自己的ip,那么同一台宿主机上这些容器之间需要通信,则需要借助网桥的设备。我们在安装docker时,默认情况下会创建一个docker0 linux bridge的虚拟网桥设备,我们创建的容器

都会挂到docker0网桥上。关于linux虚拟网桥的知识我们可以参考这篇博文(https://segmentfault.com/a/1190000009491002

现在分别创建两个bridge网络的容器,如下:

[root@VM_0_12_centos ~]# docker run -dit  --name=bbox2 busybox
7b4221300b296026126d3cf600db39bed68e4048729982d6e09100f59ec900b7 [root@VM_0_12_centos ~]# docker run -dit --name=bbox1 busybox
91dd8c37571d69eacafe562f97a7c476f67a6189a0e58b4a95cc9a8f2ac013df
我们可以查看bridge网络的配置,子网分配,网关地址(docker0网桥)以及分配给每个容器的ip地址及mac地址,如下红色标注:
[root@VM_0_12_centos ~]# docker network inspect bridge
[
{
"Name": "bridge",
"Id": "5b6d64e4b4433bb639b26a3f4a0e828ecb1b2a54984cb01225dd682322fa61d4",
"Created": "2019-10-15T15:52:52.560070504+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"7b4221300b296026126d3cf600db39bed68e4048729982d6e09100f59ec900b7": {
"Name": "bbox2",
"EndpointID": "b3745248db52c2ea8e6eb7d05a5e581113105c4979717759d2d49bfebda2be49",
"MacAddress": "02:42:ac:11:00:03",
"IPv4Address": "172.17.0.3/16",
"IPv6Address": ""
},
"91dd8c37571d69eacafe562f97a7c476f67a6189a0e58b4a95cc9a8f2ac013df": {
"Name": "bbox1",
"EndpointID": "60b01cb330806b9fbbc9b212530b6561f7f56e697ac6ea1040f2e31419ed74d5",
"MacAddress": "02:42:ac:11:00:04",
"IPv4Address": "172.17.0.4/16",
"IPv6Address": ""
},
"f2f176f13894b434b4e7f6f6bcc68af1782559295d7ca430561eaf679d288deb": {
"Name": "nginx1",
"EndpointID": "d0f39a169126cd8222514eddfbba008a8e7f6727df8d49c25e19e35f6e53e191",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16",
"IPv6Address": ""
}
},
通过ifconfig 可以看出,分别创建了两个以Veth开头的虚拟网卡

[root@VM_0_12_centos ~]# ifconfig
docker0: flags=<UP,BROADCAST,RUNNING,MULTICAST> mtu
inet 172.17.0.1 netmask 255.255.0.0 broadcast 0.0.0.0
ether ::::: txqueuelen (Ethernet)
RX packets bytes (278.0 B)
RX errors dropped overruns frame
TX packets bytes (452.0 B)
TX errors dropped overruns carrier collisions eth0: flags=<UP,BROADCAST,RUNNING,MULTICAST> mtu
inet 172.26.0.12 netmask 255.255.240.0 broadcast 172.26.15.255
ether :::5d:: txqueuelen (Ethernet)
RX packets bytes (43.7 GiB)
RX errors dropped overruns frame
TX packets bytes (47.2 GiB)
TX errors dropped overruns carrier collisions lo: flags=<UP,LOOPBACK,RUNNING> mtu
inet 127.0.0.1 netmask 255.0.0.0
loop txqueuelen (Local Loopback)
RX packets bytes (4.7 KiB)
RX errors dropped overruns frame
TX packets bytes (4.7 KiB)
TX errors dropped overruns carrier collisions veth7614922: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
ether be:a8:fb:ed:e5:e8 txqueuelen (Ethernet)
RX packets bytes (378.0 B)
RX errors dropped overruns frame
TX packets bytes (420.0 B)
TX errors dropped overruns carrier collisions vethe3d2ca0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
ether f2:ec:f2:ab::a1 txqueuelen (Ethernet)
RX packets bytes (712.0 B)
RX errors dropped overruns frame
TX packets bytes (830.0 B)
TX errors dropped overruns carrier collisions

虚拟设备的一端的两个虚拟网卡都被挂载在docker0网桥上

[root@VM_0_12_centos ~]# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.024229183927 no veth7614922
vethe3d2ca0 而虚拟设备的另外一端分别挂在了两个容器上,在容器内部为eth0虚拟网卡,与宿主机 veth虚拟网卡一一对应。 分别进入两个容器内部查看网络设备

[root@VM_0_12_centos ~]# docker exec -it bbox1 ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:04  ------------ (对应虚拟设备的另外一端)
inet addr:172.17.0.4 Bcast:172.17.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:11 errors:0 dropped:0 overruns:0 frame:0
TX packets:11 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:830 (830.0 B) TX bytes:712 (712.0 B)


lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)


[root@VM_0_12_centos ~]# docker exec -it bbox2 ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:03   -------------(对应虚拟设备的另外一端
inet addr:172.17.0.3 Bcast:172.17.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:6 errors:0 dropped:0 overruns:0 frame:0
TX packets:5 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:420 (420.0 B) TX bytes:378 (378.0 B)


lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)

 

可以看到两个容器内部都有自己的虚拟网卡eth0,mac地址,ip地址等。现在进入bbox1 来 ping bbox2的ip看是否能够ping通。

[root@VM_0_12_centos ~]# docker exec -it bbox1 ping 172.17.0.3
PING 172.17.0.3 (172.17.0.3): data bytes
bytes from 172.17.0.3: seq= ttl= time=0.087 ms
bytes from 172.17.0.3: seq= ttl= time=0.081 ms
bytes from 172.17.0.3: seq= ttl= time=0.063 ms
bytes from 172.17.0.3: seq= ttl= time=0.086 ms
bytes from 172.17.0.3: seq= ttl= time=0.082 ms
bytes from 172.17.0.3: seq= ttl= time=0.095 ms

以bbox1 ping容器bbox2对应的ip地址172.17.0.3来看两个容器之间是如何通信的。

首先bbox1 ping的过程中会发送 icmp包,ip层包头会填上:原地址为172.17.0.2,目的地址为172.17.0.3。容器的内核协议栈会经过路由选择:我们可以通过route来查看数据包从哪个端口发送。

/ # route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
default 172.17.0.1 0.0.0.0 UG eth0
172.17.0.0 * 255.255.0.0 U 0 0 0 eth0

根据路由表项可知,目的ip为172.17.0.3匹配的是第二项,因为Gateway为*, 可以通过容器bbox1的的虚拟网卡eth0在二层直接发送出去,不需要经过三层网络转发。数据包在经过二层封包的过程中

需要知道目的ip地址172.17.0.2对应的mac地址,进而将数据包

通过二层网络发送出去。初始通信的过程中bbox1是不知道ip(172.17.0.2)对应的mac地址的,所以需要向172.17.0.2发送ARP请求(广播包,目的mac地址填上以太网帧首部的硬件地址填

FF:FF:FF:FF:FF:FF),请求获取其mac地址。ARP包经过bbox1的eth0流向了另外一端

的虚拟网卡 veth7614922,该虚拟网卡作为网桥docker0的从设备,以端口号的形式挂载在docker0上。最终ARP包通过veth7614922设备端口号流入docker0网桥,docker0网桥处理ARP的过程如

下:

1. 首先会根据源mac地址与进入的端口号建立mac地址与端口号的映射关系存入CAM表(mac地址与端口映射表),学习用。

2. 判断该包是否为广播包(通过目的mac地址判断)如果为广播包,则进入4的流程。如果为非广播包,进入3流程。

3.从CAM表中查找目的mac地址对应的端口号是否存在,存在,则直接将这个数据包从对应端口转发出去。

4. 通过向所有的端口(除数据包进入的端口)发送arp包,在本例中,当bbox2中收到该arp包后,其会向bbox1回复响应包。响应包中会填上bbox2的mac地址。响应包经过bbox2的eth0网卡流入到

docker0的vethe3d2ca0端口进入docker0,docker0会根据1的规则建立bbox2的mac地址与端口号的映射关系,并通过先前建立 bbox1的mac地址与端口号的映射关系,将响应包通过veth7614922

端口回复给bbox1,bbox1拿到ARP的响应包后,通过二层封包,填上目的ip地址对应的mac地址将数据包以单播的形式经过docker0网桥转发出去。由于docker0网桥已经学习到bbox2的mac地址与

端口号的映射关系,这次可以直接通过目的mac地址对应的端口号,将数据包通过该端口号发送出去,从而完成从bbox1到bbox2的通信过程。

注:bbox1在获取到bbox2的ARP响应包后,会在本地存储对应的ip地址与mac地址的映射关系,如下图所示:

/ # arp -a
? (172.17.0.1) at ::::: [ether] on eth0
? (172.17.0.3) at 02:42:ac:11:00:03 [ether] on eth0
/ #

docker容器网络—单主机容器网络的更多相关文章

  1. Docker的单主机容器网络

    作者:杨冬 欢迎转载,也请保留这段声明.谢谢! 出处: https://andyyoung01.github.io/ 或 http://andyyoung01.16mb.com/ 本篇文章主要探索Do ...

  2. docker的网络-单主机(三种原生网络)none、host、bridge

    docker的网络分为:单主机.跨主机 这篇先说:单主机 我们先说一下docker的原生网络模式 网络模式 简介 优点 使用场景 none 空网络,没有网络 此网络与外界隔离,安全度非常高 适合公司内 ...

  3. Docker学习(15) Docker容器的跨主机连接

    Docker容器的跨主机连接 Docker使用网桥跨主机容器连接 Docker使用Open cSwitch实现跨主机容器连接 Docker使用weave实现跨主机容器连接

  4. docker应用-5(使用overlay 网络进行容器间跨物理主机通信)

    同一个主机上的Docker容器之间通信 docker 引擎会在主机上增加一个docker0网卡,该网卡具有双重身份: 1.从容器视角,网桥(交换机)身份docker0 对于运行在同一个主机上的各个容器 ...

  5. Docker 单主机网络

    PS:欢迎大家关注我的公众号:aCloudDeveloper,专注技术分享,努力打造干货分享平台,二维码在文末可以扫,谢谢大家. 当容器逐步向容器集群,容器云技术演进的时候,一个不得不面对的问题就是各 ...

  6. Swarm基于多主机容器网络 - overlay networks 梳理

    前面介绍了Docker管理工具-Swarm部署记录,下面重点说下Swarm基于多主机容器通信的覆盖网络 在Docker版本1.12之后swarm模式原生支持覆盖网络(overlay networks) ...

  7. Docker学习笔记之为容器配置网络

    0x00 概述 在互联网时代,网络已经成为绝大多数应用进行数据交换的主要通道,Docker 作为集群部署的利器,在网络支持上也下了许多功夫.功能丰富和强大,并不代表使用复杂,在 Docker 的封装下 ...

  8. Docker入门篇(二)之docker的单主机网络

    Docker 安装时会自动在host上创建三个网络,我们可用 docker network ls命令查看: [root@localhost ~]# docker network ls NETWORK ...

  9. docker单主机网络

    当你安装Docker时,它会自动创建三个网络.你可以使用以下docker network ls命令列出这些网络: [root@localhost ~]# docker network ls NETWO ...

随机推荐

  1. kettle教程---增量更新

    以下操作都在5.0.1版本下进行开发,其余版本可以进行自动比对 在平时工作当中,会遇到这种情况,而且很常见.比如:增量抽取(每隔2个小时抽取截至到上次抽取时间的记录) 一.操作前提: 存在3张表,源表 ...

  2. nginx目录详解

  3. 浅谈JS函数防抖及应用场景

    [前言] 在工作中,我们可能碰到这样的问题: 用户在搜索的时候,在不停敲字,如果每敲一个字我们就要调一次接口,接口调用太频繁,给卡住了. 用户在阅读文章的时候,我们需要监听用户滚动到了哪个标题,但是每 ...

  4. 【转】gdb的调试与使用

    转载自:https://www.jianshu.com/p/7a06b0bda2d8 gdb的调试与使用 这篇应该是我见过的总结最详细的gdb调试指南了,这位博主是个很强的人,他的博客对萌新比较友好, ...

  5. ACM-冒泡排序

    将多组输入数据进行冒泡排序,并去除相同的数据 #include <iostream> #include <vector> using namespace std; void R ...

  6. 项目那几步走:先配置setting路径文件、创建数据库、执行数据库迁移命令、配置mysql数据库信息、注册app、注释中间件、pymysql替换mysqldb-配置urls路由-继续视图函数-然后HTML页面展示-HTML里面导入css文件、models配置数据库表、

    django使用mysql数据库: 首先cmd创建库 1.settings: """Django settings for day42 project. Generate ...

  7. SpringMVC环境搭建(二)

    一.基于XML 1. 创建Maven Project,选择war,修改pom.xml SpringMVC是依赖于Spring的,需要导入核心包. <properties> <!-- ...

  8. Log日志级别从高到低排序 ERROR、WARN、INFO、DEBUG

    Log4j建议只使用四个级别,优先级从高到低分别是 ERROR.WARN.INFO.DEBUG.通过在这里定义的级别,您可以控制到应用程序中相应级别的日志信息的开关.比如在这里定义了INFO级别,则应 ...

  9. keras 学习笔记(一) ——— model.fit & model.fit_generator

    from keras.preprocessing.image import load_img, img_to_array a = load_img('1.jpg') b = img_to_array( ...

  10. KPConv针对Modelnet40的分类

    1. 训练样本airplane_0001.txt的可视化: 飞机尺度: 物体类别与对应标签: 2. 对训练样本进行降采样: 体素法降采样,降采样的网络大小设置为0.02m.在pycharm下面的Con ...