Docker | 跨主机通信
source link: https://ijayer.github.io/post/tech/devops/docker/20170919-%E8%B7%A8%E4%B8%BB%E6%9C%BA%E9%80%9A%E4%BF%A1/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Docker | 跨主机通信
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跨主机通信
Overview
使用Docker Overlay网络,需要注意一下几点:
一个可访问的键值存储系统:Docker支持
Consul
、Etcd
、ZooKeeper(分布式)
键值存储。一个Docker Host集群,他们要链接到键值存储,并且集群内每个Docker Host的主机名必须要唯一。因为Docker守护进程与consul通信时,会以主机名相互区分。
配置正确的Docker Daemon启动参数。让所有的Docker Host都可以访问集群key-value的服务端口
通过官网给出的需求,可以知道:
Docker Daemon要开启远程管理的端口(tcp xxx),这个端口可以用来远程给Docker(极度危险)
Docker Daemon还要开启一个tcp/udp的7946端口,Docker通过这个端口,用gossip协议学习各个宿主机上运行了那些容器。
VxLan本身也需要一个UDP的4789端口
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:一个用于服务发现和配置共享的服务软件,由HashiCorp公司用Go开发;Consul支持健康检查、并允许HTTP和DNS协议调用API存储键值对
在这里,我们使用Consul来保存Overlay的网络状态信息,包括Endpoint、Network & IP等;当然,我们不需要写代码,只需要安装Consul, 之后Docker会自动进行状态存储等。
- 安装Consul
最简单的安装方式即运行Docker.Consul容器哦, 这里 consul 服务搭建在主机:192.168.1.180
|
启动后,可在浏览器输入
host:port
可以看到Nodes节点已经添加了Consul;这里host:port=192.168.1.180:8500
配置Docker服务
Note: 所有加入Overlay网络的Docker Host都需要完成如下配置,且所有Docker Host主机名必须唯一
修改Docker启动参数 ```bash
修改 docekr.service
$ vim /usr/lib/systemd/system/docker.service
修改 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
> 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网络
|
Note: 在之后运行容器时指定 –network=ovnet1即可使Overlay网络内的Docker主机实现通信
- 在HostA(192.168.180)上查看网络
|
Note: 刚才创建的ovnet1网络作用域(SCOPE)是global, 而其他为local
- 在HostB(192.168.1.181)上查看网络
|
Note:
- 我们没有在HostB上创建网络,而这里可以发现HostA上创建的网络 ovnet1;这是因为创建ovnet1时HostA将overlay的网络信息写入了consul,而HostB从consul中读取到了网络数据完成了配置; 之后ovnet1的任何变化都会同步到HostA和HostB
- 查看网络详细配置
|
Note: IPAM, 表示IP Address Management
创建容器并接入Overlay网络
|
- 查看容器内部网络
|
Note: 可以看到容器内部有两块网卡, eth0连接overlay网络,eth1连接172.18.0.5; 且默认路由是从eth1网卡出去的
- 查看宿主机网桥信息
|
可以看到多了 docker_gwbridge 网卡; 且Docker容器的eth1网卡连接的是docker_gwbridge网桥
测试连通性
在HostB创建容器
$ docker run --name cotan2 --network ovnet1 -itd busybox
查看容器IP地址并测试连接
|
可见overlay网络中的容器可以直接通信,同时Docker也实现了DNS服务
该方案存在的问题
宿主机如何简单高效的访问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
- Issue1
|
- Issue2
|
注意: ens3换成IP地址可能导致容器跨主机通信失败
See Also
Thanks to the authors 🙂
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK