Docker跨主机通信之overlay

0、背景知识

什么是VXLAN?

VXLAN-Virtual eXtensible Local Area Network(虚拟化可扩展局域网),从名字上就知道,这是一个 VLAN 的扩展协议。 VXLAN 本质上是一种隧道封装技术。它使用 TCP/IP 协议栈的惯用手法——封装/解封装技术,将 L2 的以太网帧(Ethernet frames)封装成 L4 的 UDP 数据报(datagrams),然后在 L3 的网络中传输,效果就像 L2 的以太网帧在一个广播域中传输一样,实际上是跨越了 L3 网络,但却感知不到 L3 网络的存在。

为什么需要 VXLAN

VLAN ID 数量限制

虚拟化技术的发展,使得以前以单个物理设备组网的方式,逐步向以虚拟设备的方式过渡。

以前一台物理设备(一台服务器也好,一台网络设备也好),能支持几十个端口就已经很了不起了,所以使用 VLAN 是绰绰有余,但是虚拟化环境下就大不同了,一台物理主机可能虚拟出上百上千台虚拟设备,整个云数据中心可能要划分超过成千上万个的广播域,而 VLAN 被限制为最多 4094 个,这就显得捉襟见肘了。

灵活的虚拟机部署和迁移

采用 VLAN 的虚拟网络环境,不存在 overlay 网络,只有 underlay 网络。也就是说 虚拟机的 VLAN 数据包直接在物理网络上传输,和物理网络上的 VLAN 数据包融合在一起,这样的好处是虚拟机能直接访问到物理网络的设备,但坏处也很明显,虚拟网络无法打破物理网络的界限,具体表现在虚拟机的部署和迁移不太灵活。

  • 部署 :如果要在 VLAN 100 上部署虚拟机,那么只能在支持 VLAN 100 的物理机上部署,如下图所示,假设左右两个区域分属 VLAN 100 和 VLAN 200,现在 VLAN 100 已经部署了很多虚拟机,而 VLAN 200 却才部署了少量的虚拟机,如果这时需要继续往 VLAN 100 部署新的虚拟机,那么也只能选择在左边区域部署,这就会造成左边区域负担过重。
  • 迁移 :同样,如果从左边区域往右边区域迁移虚拟机,因为两边分属于不同的 VLAN,虚机所分配的 IP 地址不同,无法直接进行迁移,这会造成整个集群机器的负载分配不均。

使用 VxLAN 则完全不存在这些问题,通过 VxLAN 的封装,在一个 L3 网络上构建了 L2 网络,或者说基于 underlay 网络的 overlay 网络,虚拟机的数据可以打破 L2 网络的限制,在 L3 网络上传输,虚拟机的部署和迁移也不受物理网络的限制,可以灵活部署和迁移,使得整个数据中心保持一个平均的利用率。

1、什么是overlay网络

为支持容器跨主机通信,Docker 提供了 overlay driver,使用户可以创建基于 VXLAN 的 overlay 网络。

接下来,让我们实践一下。

2、安装consul

Docerk overlay 网络需要一个 key-value 数据库用于保存网络状态信息,包括 Network、Endpoint、IP 等。Consul、Etcd 和 ZooKeeper 都是 Docker 支持的 key-vlaue 软件。在这里我们使用consul。

node1上:

docker run -d -p 8500:8500 -h consul --name consul progrium/consul -server -bootstrap
  • -p 8500:8500 指定映射端口8500
  • -h consul 指定主机名
  • --name consul 是容器的名字
  • progrium/consul 镜像名
  • -server 设置Agent是server模式
  • -bootstrap 设置服务为“bootstrap”模式

容器启动后,可以通过 http://192.168.1.12:8500 访问 Consul。

node2、node3上: vim /etc/docker/daemon.json

{
  "hosts":["tcp://0.0.0.0:2375","unix:///var/run/docker.sock"],
  "cluster-store": "consul://192.168.1.12:8500",
  "cluster-advertise": "192.168.1.13:2375"                       
}
  • host 开启和监听2375端口,同时使用docker.sock文件
  • --cluster-store指定 consul 的地址。
  • --cluster-advertise 告知 consul 自己的连接地址。

注意:记得修改docker.service.因为配置和daemon.json冲突

#修改 /usr/lib/systemd/system/docker.service
#将-H fd://去掉
ExecStart=/usr/bin/dockerd  --containerd=/run/containerd/containerd.sock

修改后重启docker

systemctl daemon-reaload
systemctl restart docker

创建好以上步骤后,我们就可以在网页上访问: http://192.168.1.12:8500

在KEY/VALUE -> docker -> nodes 下如果有你创建的两个节点node2(192.168.1.13),node3(192.168.1.14),说明成功。

3、创建overlay网络

在 node2 中创建 overlay 网络 ol1:

[root@tuling2 ~]$ docker network create -d overlay ol1

-d overlay 指定 driver 为 overaly。

查看当前网络:

注意到 ol1 的 SCOPE 为 global,而其他网络为 local

[root@tuling2 ~]$ docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
f91878b4b82d        bridge              bridge              local
1651b429a674        host                host                local
9fb8eccd5dd8        mac10               macvlan             local
26621389d2e1        mac20               macvlan             local
4f2664e6f883        none                null                local
f1615acab206        ol1                 overlay             global

同时查看node3,也会出现ol1网络,这是因为创建 ol1 时 node2 将 overlay 网络信息存入了 consul,node3 从 consul 读取到了新网络的数据。之后 ol1 的任何变化都会同步到 node2 和 node3。

[root@tuling3 ~]$ docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
ab6ad262b11f        bridge              bridge              local
1651b429a674        host                host                local
9fb8eccd5dd8        mac10               macvlan             local
26621389d2e1        mac20               macvlan             local
4f2664e6f883        none                null                local
f1615acab206        ol1                 overlay             global

4、启动容器测试

分别在node2,node3启动容器busybox

[root@tuling2 ~]$ docker run -it --network ol1 --name obox1  busybox:latest /bin/sh

指定网络ol1,容器名ol2

[root@tuling3 ~]$ docker run -it --network ol1 --name obox2  busybox:latest /bin/sh

容器obox1与obox2之间可相互完成通信。

[root@tuling3 ~]$ docker run -it --network ol1 --name obox2  busybox:latest /bin/sh
/ $ ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:0A:00:00:03  
          inet addr:10.0.0.3  Bcast:10.0.0.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1450  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:0 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

eth1      Link encap:Ethernet  HWaddr 02:42:AC:12:00:02  
          inet addr:172.18.0.2  Bcast:172.18.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:10 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:872 (872.0 B)  TX bytes:0 (0.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:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

/ # ping 10.0.0.2
PING 10.0.0.2 (10.0.0.2): 56 data bytes
64 bytes from 10.0.0.2: seq=0 ttl=64 time=0.563 ms

5、原理分析

整体架构如图:

查看 网络 ol1 的详细信息,可以看到IPAM

[root@tuling2 ~]$ docker network inspect ol1
[
    {
        "Name": "ol1",
        "Id": "f1615acab206bfa2bff0c93460b66438cdd084c91416e43a3a25c71fe7d1bc00",
        "Created": "2020-06-09T22:51:04.158526977+08:00",
        "Scope": "global",
        "Driver": "overlay",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "10.0.0.0/24",
                    "Gateway": "10.0.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "a85fe4883f52638d70b7070ea15ea29cf32ff1033e07d170ace3573c5f134b62": {
                "Name": "obox2",
                "EndpointID": "da8a6789bd7fe899a2174828487d98460b9166bdd397ccb06641e876f0d31c93",
                "MacAddress": "02:42:0a:00:00:03",
                "IPv4Address": "10.0.0.3/24",
                "IPv6Address": ""
            },
            "ep-b05199cddd067aaa1ebd173685b13465e233b1ff3170c40508fec934176364ce": {
                "Name": "obox1",
                "EndpointID": "b05199cddd067aaa1ebd173685b13465e233b1ff3170c40508fec934176364ce",
                "MacAddress": "02:42:0a:00:00:02",
                "IPv4Address": "10.0.0.2/24",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]

IPAM 是指 IP Address Management,docker 自动为 ol1 分配的 IP 空间为 10.0.0.0/24。

docker 默认为overlay网络分配24位掩码的子网(10.0.x.0/24),所有主机共享这个subnet,容器启动顺序分配IP,也可以通过--subnet指定子网

docker network create -d overlay --subnet 10.22.1.0/24 ov3

[root@tuling2 ~]$ docker network inspect ov3 |jq ".[0].IPAM.Config"
[
  {
    "Subnet": "10.22.1.0/24"
  }
]

查看容器obox1 有两个网络接口 eth0 和 eth1。eth0 IP 为 10.0.0.2,连接的是 overlay 网络 ol1。eth1 IP 172.18.0.2,容器的默认路由是走 eth1,eth1 是哪儿来的呢?

[root@tuling2 docker]$ docker run -it --network ol1 --name obox1  busybox:latest /bin/sh
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:0A:00:00:02  
          inet addr:10.0.0.2  Bcast:10.0.0.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1450  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:0 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

eth1      Link encap:Ethernet  HWaddr 02:42:AC:12:00:02  
          inet addr:172.18.0.2  Bcast:172.18.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:13 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:1102 (1.0 KiB)  TX bytes:0 (0.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:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

/ # route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         172.18.0.1      0.0.0.0         UG    0      0        0 eth1
10.0.0.0        0.0.0.0         255.255.255.0   U     0      0        0 eth0
172.18.0.0      0.0.0.0         255.255.0.0     U     0      0        0 eth1

其实,docker 会创建一个 bridge 网络 “docker_gwbridge”,为所有连接到 overlay 网络的容器提供访问外网的能力。

docker network inspect docker_gwbridge 输出可确认 docker_gwbridge 的 IP 地址范围是 172.18.0.0/16,当前连接的容器就是 obox1(172.18.0.2)。

[root@tuling2 ~]$ docker network inspect docker_gwbridge
[
    {
        "Name": "docker_gwbridge",
        "Id": "f22c7085c33dc6b291ceb63c29bd8044466b54b56c4f0886d2688ff1f170a0f7",
        "Created": "2020-06-09T22:53:19.501579727+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "a85fe4883f52638d70b7070ea15ea29cf32ff1033e07d170ace3573c5f134b62": {
                "Name": "gateway_2c49e6fc6b26",
                "EndpointID": "36239e661f068ae8ffc7b204415c3d0e637755d145eb9a5d219a8f425f25a4ee",
                "MacAddress": "02:42:ac:12:00:02",
                "IPv4Address": "172.18.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {
            "com.docker.network.bridge.enable_icc": "false",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.name": "docker_gwbridge"
        },
        "Labels": {}
    }
]

而且此网络的网关就是网桥 docker_gwbridge 的 IP 172.18.0.1,实现外网访问

[root@tuling2 docker]$ docker run -dit --network ol1 --name obox1  busybox:latest 
1535ef4c12d36609502efe8ae86dceab7c5c00ea415b733e7821d91b5a559932
[root@tuling2 docker]$ docker exec -it obox1 ping www.baidu.com -c 2
PING www.baidu.com (61.135.169.121): 56 data bytes
64 bytes from 61.135.169.121: seq=0 ttl=57 time=3.074 ms
64 bytes from 61.135.169.121: seq=1 ttl=57 time=3.937 ms

--- www.baidu.com ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 3.074/3.505/3.937 ms

另一台node3,用容器 直接ping obox1

[root@tuling3 docker$ docker exec -it obox2 ping obox1 -c 2
PING obox1 (10.0.0.2): 56 data bytes
64 bytes from 10.0.0.2: seq=0 ttl=64 time=0.499 ms
64 bytes from 10.0.0.2: seq=1 ttl=64 time=0.437 ms

--- obox1 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.437/0.468/0.499 ms

说明:overlay网络中容器可以通信,不需要指定ip地址,同时docker也实现了dns服务

6 、overlay的隔离特性

不同的overlay网络是相互隔离的

创建第二个overlay网络ov2并运行容器obox3

docker network create -d overlay ov2

docker run -itd --name obox3 --network ov2 busybox

obox3分配的地址是10.0.1.2,ping obox1(10.0.0.2),是不通的

[root@tuling2 docker]$ docker exec -it box3 ip r
default via 172.18.0.1 dev eth1 
10.0.1.0/24 dev eth0 scope link  src 10.0.1.2 
172.18.0.0/16 dev eth1 scope link  src 172.18.0.3 

[root@tuling2 docker]$ docker exec -it box3 ping -c 2 10.0.0.2
PING 10.0.0.2 (10.0.0.2): 56 data bytes

--- 10.0.0.2 ping statistics ---
2 packets transmitted, 0 packets received, 100% packet loss

即使通过docker_gwbridge也不能通信

[root@tuling2 docker]$ docker exec -it obox3 ping -c 2 172.18.0.2
PING 172.18.0.2 (172.18.0.2): 56 data bytes

--- 172.18.0.2 ping statistics ---
2 packets transmitted, 0 packets received, 100% packet loss

至此,overlay 网络已经讨论完了。

参考文章

如果 想对docker网络还要更深入的了解,可以参考以下文章,它详细描述了Docker的overlay网络,Docker的overlay网络依赖的相关技术

https://blog.revolve.team/2017/04/25/deep-dive-into-docker-overlay-networks-part-1/

results matching ""

    No results matching ""