docker overlay网络拓扑及服务注册问题
跨主机docker网络有多种方案,如overlay、flannel、calico、weave等,其中overlay是docker原生的跨主机网络方案。最近使用overlay方案部署容器集群,在进行服务注册时遇到问题,需要手动创建veth设备解决。
1. overlay网络拓扑
overlay网络中,docker会为每一个overlay网络创建一个独立的network namespace,即上图中的net1和net2。每个namespace中都有一个linux bridge br0,docker容器与br0之间通过veth pair连接,一端为容器中的eth0,另一端通过namespace中的veth接口连接到br0。br0还连接了vxlan1,通过vxlan隧道实现跨主机容器通信。
br0没有与宿主机namespace中的接口相连,因此容器无法通过eth0与主机通信。在overlay网络中,为了实现容器与主机之间的通信,在宿主机namespace中创建了linux bridge docker_gwbridge。所有容器都通过veth pair连接到该网桥中。上图中,容器可以通过eth1与宿主机通信。eth1接口仅用于容器与宿主机通信,即使位于同一个overlay网络中的容器间,也无法通过eth1接口通信。
2. 服务注册问题
最近,使用overlay网络部署容器集群后,需要将容器的IP地址和端口注册到注册中心中,注册中心将容器提供的服务进行映射,对外暴露统一的IP地址。有两种使用场景:
a) 集群外部通过注册中心查询服务,通过映射后的地址和端口号访问
b) 集群内部通过注册中心查询服务,可通过映射后的地址和端口号访问,也可直接选择容器的地址和端口号访问
在以上的应用场景中,通过映射后的地址和端口号服务,访问服务时需要经过注册中心,再到达容器。在我的集群中,注册中心使用host方式部署,与提供服务的容器之间通过eth1接口进行通信,容器向注册中心注册时,服务的IP地址必须为eth1的IP地址,才能保证通过注册中心顺利转发。但这时,集群内访问时,查询到的容器IP是eth1的IP地址,无法直接访问。如果注册时服务的IP采用eth0的IP,则无法通过注册中心转发。
为了解决以上问题,我通过vethpair设备将overlay网络直接与宿主机相连通。这样,将eth0的IP注册到注册中心,同样能通过注册中心进行转发。具体步骤如下:
创建vethpair设备:
ip link add vethhost type veth peer name gw_api
查找overlay网络的namespace,可在/var/run/docker/netns中找到,格式为 数字-网络ID,本例中为1-cae3e00181
创建符号链接(可能要使用root权限手动创建/var/run/netns目录):
ln -s /var/run/docker/netns/1-cae3e00181 /var/run/netns/
将vethpair的vethhost一端连接到overlay网络的namespace中,
ip link set vethhost netns 1-cae3e00181
将vethhost端接入br0网桥:
ip netns exec 1-cae3e00181 brctl addif br0 vethhost
设置vethhost端mtu并up:
ip netns exec 1-cae3e00181 ifconfig vethhost mtu 1450 up
设置gw_api端mtu和IP地址(overlay网络同网段IP)
ifconfig gw_api mtu 1450 193.168.120.1/16
经过上述设置,容器与注册中心的网络拓扑如下(省略了net2):
由于注册中心使用宿主机网络,可以通过gw_api接口与overlay网络net1通信。
在这一解决方法中,我修改了overlay网络的拓扑。暂时没有考虑其他几种跨主机容器网络方案能不能避免该问题,等有时间研究一下k8s的网络方案,或许会有更多收获。