相关知识
Overlay Network?
An overlay network is a computer network that is built on top of another network. 覆盖网络,是一个建立在另一个网络上的计算机网络。覆盖网络中的节点被认为是通过虚拟或逻辑链接相连的,其中每一条链接对应一条路径(PATH)。Wikipedia 、基于多租户的云计算Overlay网络
Overlay的主要技术标准:VXLAN
- VXLAN(Virtual Extensible LAN: 虚拟可扩展局域网):是一种Overlay网络(在网络之上构建的一层网络),基于隧道技术实现。
- Linux Bridge默认支持VXLAN, OpenVSwitch也支持VXLAN
- VxLan 类似于 VLan技术,最大的不同点是,VxLan可以拥有更多的网段,远远大于VLan的网段。 VLan只支持4094个网段。
- VXLAN 的数据包是封装到UDP通过三层网络转发,可使用所有的网络路径; VXLAN的传输协议是 IP+UDP
Docker网络架构和libnetwork
libnetwork 是Docker容器网络库,最核心的内容是其定义的 Container Network Model(CNM), 这个模型对容器网络进行了抽象
CNM 主要由以下三类组件构成:
Sandbox(沙箱):容器的网络栈,包含容器的Interface、路由表和DNS设置。Linux Network Namespace 是sandbox的标准实现。sandbox可以包含来自不同Network的Endpoint
Endpoint(端点):用于将sandbox接入Network。Endpoint的典型实现是 veth pair。一个 Endpoint只能属于一个网络,也只能属于一个sandbox
Network(网络):Network包含一组Endpoint,同一Network的Endpoint可以直接通信。
架构示意图:
libnetwork中的5种内置驱动:
bridge 驱动:Docker默认的设置,使用这个驱动的时候,libnetwork将创建出来的Docker容器链接到Docker网桥上。
host 驱动:使用这种驱动的时候,libnetwork将不会为Docker容器创建网络协议栈,也就是不会创建独立的network namespace。Docker容器中的进程处于宿主机的网络环境中。
overlay 驱动:该驱动采用标准的VxLANFANGSHI, 并且VxLan被普遍认为是最适合大规模的云计算虚拟化环境的SDN controller模式。在使用过程中,需要一个额外的配置存储服务
。
remote 驱动:这个驱动并没有做真正的网络实现,而是调用了用户自行实现的网络驱动插件,使libnetwork实现了驱动的可插件化。
null 驱动:使用这种驱动的时候,Docker容器拥有自己的network namespace,但是不会进行任何网络配置。
相关方案简介
基于桥接的跨主机通信
基于桥接的跨主机通信
目前, Docker默认网络模式(bridge)下,单台主机上的Docker容器间可通过docker0网桥通信, 而不同主机上的Docker容器间只能通过在主机上做端口映射的方法通信。这种方案在Docker集群应用时很不方便, 如果可以直接使用容器IP跨主机通信则会简便很多。
基于Overlay的跨主机通信
Docker支持使用Overlay网络驱动实现跨主机网络通信
不同于 bridge
网络,使用overlay网络需要满足一下条件中的任意一个:
- Docker运行在 swarm 模式
- 一个键值存储集群(ZooKeeper | etcd | consul)
Note: 官方文档中Docker overlay网络是和Swarm共存的
基于Overlay网络和一个外部Key-Value存储数据库搭建Docker跨主机通信
参考方案·Docker Overlay跨主机通信
Overview
使用Docker Overlay网络,需要注意一下几点:
一个可访问的键值存储系统:Docker支持 Consul
、Etcd
、ZooKeeper(分布式)
键值存储。
一个Docker Host集群,他们要链接到键值存储,并且集群内每个Docker Host的主机名必须要唯一。因为Docker守护进程与consul通信时,会以主机名相互区分。
配置正确的Docker Daemon启动参数。让所有的Docker Host都可以访问集群key-value的服务端口
通过官网给出的需求,可以知道:
Note:要在防火墙开启这些端口
实验环境说明
实验主机:
Host |
OS |
Description |
192.168.1.180 |
Centos7 Kernel 3.10.0 |
Docker主机_A(搭建consul数据库) |
192.168.1.181 |
Centos7 Kernel 3.10.0 |
Docker主机_B |
启动Consul数据库
Consul 的相关介绍
Consul:一个用于服务发现和配置共享的服务软件,由HashiCorp公司用Go开发;Consul支持健康检查、并允许HTTP和DNS协议调用API存储键值对
在这里,我们使用Consul来保存Overlay的网络状态信息,包括Endpoint、Network & IP等;当然,我们不需要写代码,只需要安装Consul, 之后Docker会自动进行状态存储等。
https://blog.coding.net/blog/intro-consul
最简单的安装方式即运行Docker.Consul容器哦, 这里 consul 服务搭建在主机:192.168.1.180
1
2
3
4
5
6
7
8
|
# 拉取镜像
$ docker pull progrium/consul
# 启动consul服务
$ docker run --resatrt=always -d -p 8500:8500 -h consul --name consul progrium/consul -server -bootstrap
# 查看consul容器是否运行成功
docker ps
|
启动后,可在浏览器输入 host:port
可以看到Nodes节点已经添加了Consul;这里host:port=192.168.1.180:8500
配置Docker服务
Note: 所有加入Overlay网络的Docker Host都需要完成如下配置,且所有Docker Host主机名必须唯一
修改 ExecStart 选项如下
ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2376 -H unix:///var/run/docker.sock –cluster-store=consul://192.168.1.180:8500 –cluster-advertise=ens33:2376
1
2
3
4
5
6
7
8
9
10
|
> Note:
>
> - --cluster-store: 指定键值存储的地址(Consul节点IP)
> - --cluster-advertise: 告诉存储服务自己的连接地址(ens33为docker节点IP地址所在的网卡名)
- 重启Docker服务
```bash
$ systemctl daemon-reload
$ systemctl restart docker.service |
Note: 可以看到 docker/nodes下已经有两个节点
创建Overlay网络
- 在HostA(192.168.1.180)上创建Overlay网络
1
2
3
4
5
|
# 创建 Overlay 网络 ovnet1, -d 指定网络模式
$ docker network create -d overlay ovnet1
# 创建 Overlay 网络时, 指定其子网和网关
$ docker network create -d overlay ovnet2 --subnet 172.19.0.0/24 --gateway 172.19.0.1
|
Note: 在之后运行容器时指定 –network=ovnet1即可使Overlay网络内的Docker主机实现通信
1
2
3
4
5
6
7
8
|
# Lookup HostA Docker Network
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
2315b20ebe40 bridge bridge local
45fcb93505c0 docker_gwbridge bridge local
9ccf08201f10 host host local
e15bf8515ecd none null local
0c7ad0717a77 ovnet1 overlay global
|
Note: 刚才创建的ovnet1网络作用域(SCOPE)是global, 而其他为local
- 在HostB(192.168.1.181)上查看网络
1
2
3
4
5
6
7
8
|
# Lookup HostB Docker Network
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
2315b20ebe40 bridge bridge local
45fcb93505c0 docker_gwbridge bridge local
9ccf08201f10 host host local
e15bf8515ecd none null local
0c7ad0717a77 ovnet1 overlay global
|
Note:
- 我们没有在HostB上创建网络,而这里可以发现HostA上创建的网络 ovnet1;这是因为创建ovnet1时HostA将overlay的网络信息写入了consul,而HostB从consul中读取到了网络数据完成了配置; 之后ovnet1的任何变化都会同步到HostA和HostB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
$ docker inspect ovnet1
[
{
"Name": "ovnet1",
"Id": "0c7ad0717a77b329357a251f79f43f8889be819313334249be45a4f04677a0de",
"Created": "2017-09-21T08:51:50.324849876+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": {},
"Options": {},
"Labels": {}
}
]
|
Note: IPAM, 表示IP Address Management
创建容器并接入Overlay网络
1
|
$ docker run --name cotan1 --network ovnet1 -itd busybox
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
$ docker exec -it cotan1 sh
$ ip address
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
16: eth0@if17: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1450 qdisc noqueue state UP
link/ether 02:42:0a:00:00:05 brd ff:ff:ff:ff:ff:ff
inet 10.0.0.5/24 scope global eth0
valid_lft forever preferred_lft forever
26: eth1@if27: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:12:00:05 brd ff:ff:ff:ff:ff:ff
inet 172.18.0.5/16 scope global eth1
valid_lft forever preferred_lft forever
$ ip route
default via 172.18.0.1 dev eth1
10.0.0.0/24 dev eth0 src 10.0.0.5
172.18.0.0/16 dev eth1 src 172.18.0.5
|
Note: 可以看到容器内部有两块网卡, eth0连接overlay网络,eth1连接172.18.0.5; 且默认路由是从eth1网卡出去的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
# 在HostA执行
$ ip address
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 00:0c:29:c5:85:c4 brd ff:ff:ff:ff:ff:ff
inet 192.168.1.180/24 brd 192.168.1.255 scope global ens33
valid_lft forever preferred_lft forever
inet6 fe80::c517:b883:c99a:290c/64 scope link
valid_lft forever preferred_lft forever
3: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN qlen 1000
link/ether 52:54:00:9e:02:43 brd ff:ff:ff:ff:ff:ff
inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
valid_lft forever preferred_lft forever
4: virbr0-nic: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast master virbr0 state DOWN qlen 1000
link/ether 52:54:00:9e:02:43 brd ff:ff:ff:ff:ff:ff
5: docker_gwbridge: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP
link/ether 02:42:31:81:ce:4e brd ff:ff:ff:ff:ff:ff
inet 172.18.0.1/16 scope global docker_gwbridge
valid_lft forever preferred_lft forever
inet6 fe80::42:31ff:fe81:ce4e/64 scope link
valid_lft forever preferred_lft forever
6: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP
link/ether 02:42:a8:41:f3:9e brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:a8ff:fe41:f39e/64 scope link
valid_lft forever preferred_lft forever
8: veth7f764b0@if7: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP
link/ether 66:03:b1:8f:c2:af brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet6 fe80::6403:b1ff:fe8f:c2af/64 scope link
valid_lft forever preferred_lft forever
|
可以看到多了 docker_gwbridge 网卡; 且Docker容器的eth1网卡连接的是docker_gwbridge网桥
测试连通性
在HostB创建容器
1
|
$ docker run --name cotan2 --network ovnet1 -itd busybox |
查看容器IP地址并测试连接
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
$ docker exec -it cotan2 sh
$ ip address
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
9: eth0@if10: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1450 qdisc noqueue
link/ether 02:42:0a:00:00:02 brd ff:ff:ff:ff:ff:ff
inet 10.0.0.2/24 scope global eth0
valid_lft forever preferred_lft forever
13: eth1@if14: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.18.0.2/16 scope global eth1
valid_lft forever preferred_lft forever
$ ping 10.0.0.5
64 bytes from 10.0.0.2: seq=0 ttl=64 time=0.588 ms
64 bytes from 10.0.0.2: seq=1 ttl=64 time=0.417 ms
--- container1 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.417/0.502/0.588 ms
|
可见overlay网络中的容器可以直接通信,同时Docker也实现了DNS服务
该方案存在的问题
http://www.chongchonggou.com/g_6115686.html
宿主机如何简单高效的访问Docker自带的Overlay网络中的所有容器(包括其他宿主机上的)
在Docker自带的Overlay网络中,容器内部访问外网使用的是自动创建的docker_gwbridge桥,那么 docker 宿主机如何访问overlay网络内部呢(比如其他宿主机上同时加入该overlay网络的容器)?
解决方法有如下几种:
- 尝试把到overlay路由指到docker_gwbridge,但是无法访问其他宿主机上加入到这个overlay的容器,因为没有回程路由,给每台启动的容器加回程路由也是很不现实的。
- 宿主机上,容器内都开反向代理。
- 容器内开启iptables,做nat。
- 传统模式给容器做nat映射宿主机端口。
- 如果能指定overlay中的某个容器为整个overlay的默认路由的话,一切都好办了,奈何目前到1.10.2,gateway都会被自动指到某个网桥上,只能每台容器去修改,但是给每台容器赋予这么高的权限,个人是不愿意的。
Overlay网络实现原理
总结Overlay网络
- Overlay网络会自动创建一个docker_gwbridge网卡,作用是为Docker容器提供上外网需求
- Docker容器不能通过docker_gwbridge网卡互相通信,即使在同一台Docker主机, 同一个Overlay网络也不行
- Docker容器间通信只能通过overlay网络
- Overlay网络间是相互隔离的,通过VXLan隔离
- Docker容器的网络命名空间与Overlay网络的命名空间通过一对veth pair连接起来
- Docker容器的veth pair对端veth0与vxlan0设备通过br0这个Linux bridge桥接在一起, br0在同一宿主机上起到虚拟交换机的作用,如果目标地址在同一宿主机上,则直接通信,如果不在则通过设置vxlan0这个VXLan设备进行跨主机通信
- Overlay网络独立的命名空间里面会有一个网桥br0
- VXLan0设备会在创建时,由Docker daemon 为其分配vxlan隧道ID,起到网络隔离的作用
- Docker Host集群会通过key/value存储共享数据,在7496端口上,互相之间通过gossip协议学习各个宿主机上运行了那些容器。守护进程根据这些数据在vxlan0设备上生成静态MAC转发表
- 根据静态MAC转发表的设置,通过UDP端口4789,将流量转发到对端宿主机网卡上
- 根据流量包中的VxLan隧道ID,将流量转发到对端宿主机的overlay网络的网络命名空间中。
- 对端宿主机的overlay网络的网络命名空间中br0网桥,起到虚拟交换机的作用,将流量根据MAC地址转发到对应容器内部。
Issue
1
2
3
|
[root@zhe0 ~]# docker run --name cotan1 --network ovnet1 --ip 10.0.0.10 -d busybox
402fb4295afa1fcf9ba7cc5493c9dedecf50edee1983fbbad376e8b93e560d20
docker: Error response from daemon: user specified IP address is supported only when connecting to networks with user configured subnets.
|
1
2
|
在 ExecStart 最后添加: --cluster-store=consul://<consul_ip>:8500 --cluster-advertise=ens3:2376
其中 表示运行 consul 容器的节点IP。ens3为当前节点的ip地址对应的网卡
|
注意: ens3换成IP地址可能导致容器跨主机通信失败
See Also
Thanks to the authors 🙂