Docker跨主机通信实现与分析

开发 开发工具
docker的overlay的网络驱动支持跨主机通信,这个实现在libnetwork中基于内置的VXLAN实现以及docker的libkv库。使用overlay网络需要依赖K-V Store,目前支持的K-V Store包括etcd、Consul、Zookeeper。

[[186794]]

前言

docker目前支持以下5种网络模式:

  • bridge:此时docker引擎会创建一个veth对,一端连接到容器实例并命名为eth0,另一端连接到指定的网桥中(比如docker0),因此同在一个主机的容器实例由于连接在同一个网桥中,它们能够互相通信。容器创建时还会自动创建一条SNAT规则,用于容器与外部通信时。如果用户使用了-p或者-Pe端口端口,还会创建对应的端口映射规则。
  • host:与宿主机共享网络,此时容器没有使用网络的namespace,宿主机的所有设备,如Dbus会暴露到容器中,因此存在安全隐患。
  • none:不设置网络,相当于容器内没有配置网卡,用户可以手动配置。
  • container:指定与某个容器实例共享网络
  • network:使用自定义网络,可以使用docker network create创建,并且默认支持多种网络驱动,用户可以自由创建桥接网络或者overlay网络。

默认是桥接模式,网络地址为172.16.0.0/16,同一主机的容器实例能够通信,但不能跨主机通信。本文下面将介绍如何使用gre隧道技术实现跨主机通信。

环境配置

本文使用两台主机A,B模拟实验,这两台主机其实是virtalbox虚拟机,操作系统为ubuntu14.04,均配置有两张网卡,网卡配置如下:

  • eth0:与宿主机桥接,连接公网
  • eth1:host only网卡,分配的ip地址为192.168.56.0/24,连接在同一个host only的网卡能够互相通信

其中A主机网络:

  1. eth0: 172.16.1.24(公司内网IP,能够通外网) 
  2. eth1: 192.168.56.4 

B主机网络:

  1. eth0: 172.16.1.178(公司内网IP,能够通外网)  
  2. eth1: 192.168.56.5 

两台主机需要安装以下软件包:

  • Docker,实验时使用的***版本1.11,快速安装:
  1. curl -sSL https://get.docker.com/ | sh 
  • Openvswitch, 安装方法:
  1. sudo apt-get install openvswitch-switch 
  • bridge-utils,也可以不安装,使用ovs-vsctl。

Docker配置

两台主机的容器能够通信,不能出现网络重叠,因此设置不同的网络:

  1. A: 10.103.100.0/24  
  2. B: 10.103.200.0/24 

并且为了加速镜像拉取,使用灵雀云镜像。***A主机配置文件/etc/default/docker如下:

  1. DOCKER_OPTS="$DOCKER_OPTS --registry-mirror=http://houchaohann.m.alauda.cn --bip=10.103.100.1/24 --fixed-cidr=10.103.100.0/24" 

B主机配置文件/etc/default/docker如下:

  1. DOCKER_OPTS="$DOCKER_OPTS --registry-mirror=http://houchaohann.m.alauda.cn --bip=10.103.200.1/24 --fixed-cidr=10.103.200.0/24" 

分别重启A、B主机Docker服务:

  1. sudo service docker restart 

此时A主机docker0网桥地址为10.103.100.1,B主机docker0网桥地址为10.103.200.1。

在A主机上ping 10.103.200.1显然不通,同理B主机ping不通A主机网桥。

隧道配置

在A主机上创建一个网桥(使用ovs-vsctl,不要使用brctl):

  1. sudo ovs-vsctl add-br docker_tunnel 

将gre0接口加入到网桥docker_tunnel, 创建一个GRE隧道添加到网桥中并配置远端IP,注意:我们在eth1之上建立隧道,因此需要使用eth1 IP地址:

  1. sudo ovs-vsctl add-port docker_tunnel gre0 -- set Interface gre0 type=gre options:remote_ip=192.168.56.5 

此时:

  1. fgp@ubuntu-4:~$ sudo ovs-vsctl show 
  2. 2189345f-d4fb-4915-ab97-4c65a8d9ffe0 
  3.     Bridge docker_tunnel 
  4.         Port "gre0" 
  5.             Interface "gre0" 
  6.                 type: gre 
  7.                 options: {remote_ip="192.168.56.5"
  8.         Port docker_tunnel 
  9.             Interface docker_tunnel 
  10.                 type: internal 
  11.     ovs_version: "2.0.2" 

把docker_tunnel加入到docker0网桥中:

  1. sudo brctl addif docker0 docker_tunnel 

增加路由:

  1. sudo ip route add 10.103.200.0/24 via 192.168.56.5 dev eth1 

此时路由表:

  1. fgp@ubuntu-4:~$ sudo route -n 
  2. Kernel IP routing table 
  3. Destination     Gateway         Genmask         Flags Metric Ref    Use Iface 
  4. 0.0.0.0         172.16.1.1      0.0.0.0         UG    0      0        0 eth0 
  5. 10.103.100.0    0.0.0.0         255.255.255.0   U     0      0        0 docker0 
  6. 10.103.200.0    192.168.56.5    255.255.255.0   UG    0      0        0 eth1 
  7. 172.16.1.0      0.0.0.0         255.255.255.0   U     0      0        0 eth0 
  8. 192.168.56.0    0.0.0.0         255.255.255.0   U     0      0        0 eth1 

验证A主机是否能和B通信:

  1. fgp@ubuntu-4:~$ ping -c 2 -w 1 10.103.200.1 
  2. PING 10.103.200.1 (10.103.200.1) 56(84) bytes of data. 
  3. 64 bytes from 10.103.200.1: icmp_seq=1 ttl=64 time=0.339 ms 
  4.  
  5. --- 10.103.200.1 ping statistics --- 
  6. 1 packets transmitted, 1 received, 0% packet loss, time 0ms 
  7. rtt min/avg/max/mdev = 0.339/0.339/0.339/0.000 ms 

同样在B主机执行相同步骤:

  1. sudo ovs-vsctl add-br docker_tunnel 
  2. sudo ovs-vsctl add-port docker_tunnel gre0 -- set Interface gre0 type=gre options:remote_ip=192.168.56.4 
  3. sudo brctl addif docker0 docker_tunnel 
  4. sudo ip route add 10.103.100.0/24 via 192.168.56.4 dev eth1 

验证B主机是否能够和A通信:

  1. fgp@ubuntu-5:~$ ping -c 2 -w 1 10.103.100.1 
  2. PING 10.103.100.1 (10.103.100.1) 56(84) bytes of data. 
  3. 64 bytes from 10.103.100.1: icmp_seq=1 ttl=64 time=0.336 ms 
  4. 64 bytes from 10.103.100.1: icmp_seq=2 ttl=64 time=0.409 ms 
  5.  
  6. --- 10.103.100.1 ping statistics --- 
  7. 2 packets transmitted, 2 received, 0% packet loss, time 999ms 
  8. rtt min/avg/max/mdev = 0.336/0.372/0.409/0.041 ms 

验证docker容器跨主机通信

A主机创建ubuntu14.04容器:

  1. docker run -t -i --rm --name from-A --hostname from-A ubuntu:14.04 bash 

在容器内部查看ip地址:

  1. from-A 
  2. ifconfig eth0 | grep 'inet addr' | cut -d ':' -f 2 | cut -d ' ' -f 1 
  3. # 10.103.100.2 

B主机创建ubuntu14.04容器:

  1. docker run -t -i --rm --name from-A --hostname from-B ubuntu:14.04 bash 

在容器内部查看地址:

  1. from-B 
  2. ifconfig eth0 | grep 'inet addr' | cut -d ':' -f 2 | cut -d ' ' -f 1 
  3. # 10.103.200.2 

在A容器实例上ping B容器实例:

  1. from-A 
  2. ping 10.103.200.2 

输出:

  1. root@from-A:/# ping -c 2 -w 1 10.103.200.2 
  2. PING 10.103.200.2 (10.103.200.2) 56(84) bytes of data. 
  3. 64 bytes from 10.103.200.2: icmp_seq=1 ttl=62 time=0.510 ms 
  4.  
  5. --- 10.103.200.2 ping statistics --- 
  6. 1 packets transmitted, 1 received, 0% packet loss, time 0ms 
  7. rtt min/avg/max/mdev = 0.510/0.510/0.510/0.000 ms 

我们发现,在主机A的容器成功ping通主机B的容器,实现了跨主机通信!

使用docker-swarm实现跨主机容器通信

docker的overlay的网络驱动支持跨主机通信,这个实现在libnetwork中基于内置的VXLAN实现以及docker的libkv库。使用overlay网络需要依赖K-V Store,目前支持的K-V Store包括etcd、Consul、Zookeeper。

本来想直接使用docker启动consul的,后来发现docker daemon启动依赖consul,因此只能先按照consul。首先到官方下载安装包:下载地址,解压缩后,只有一个二进制文件,直接运行即可:

  1. nohup ./consul agent -dev -advertise 172.16.1.24 -client 0.0.0.0 & 

注意: 该服务在A机器上运行,172.16.1.24务必配成能够连接外网的IP地址,否则后面启动Swarm容器时内部无法通信!

然后修改A、B服务的daemon配置文件/etc/default/docker:

  1. DOCKER_OPTS="--cluster-store=consul://172.16.1.24:8500 --cluster-advertise=eth0:2375" 
  2. DOCKER_OPTS="$DOCKER_OPTS --registry-mirror=http://houchaohann.m.alauda.cn -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock" 

重启docker服务:

  1. sudo service docker restart 

执行docker info必须包含以下信息:

  1. Cluster store: consul://172.16.1.24:8500 
  2. Cluster advertise: 172.16.1.24:2375 

接着我们需要部署Docker Swarm集群,详细过程参考手动部署docker-swarm集群。

***创建overlay网络:

  1. docker network create --driver overlay --subnet 10.103.240.0/24 test 

其中--dirver指定为overlay,并指定我们需要的子网地址,名称为test,通过docker network ls可以检查我们创建的网络是否成功:

  1. fgp@ubuntu-5:~$ docker network ls | grep test 
  2. 7eef808f272b        test                       overlay 

此时overlay网络创建完毕。我们测试其是否支持跨主机通信,首先我们创建一个ubuntu容器,命名为ubuntu-1,并使用我们刚刚创建的网络:

  1. docker run -t -i -d --net test --name ubuntu-1 ubuntu:14.04 

接着我们创建***个ubuntu容器,此时为了保证它不和ubuntu-1调度在同一台主机上,我们需要使用docker swarm的filter,指定affinity,如下:

  1. docker run -t -i -d --net test --name ubuntu-2 -e affinity:container!=~ubuntu-1 ubuntu:14.04 

运行docker ps:

  1. docker ps 
  2. fgp@ubuntu-5:~$ docker ps 
  3. CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                  PORTS               NAMES 
  4. ba5018dfe26e        ubuntu:14.04        "/bin/bash"         2 minutes ago       Up Less than a second                       ubuntu-5/ubuntu-1 
  5. bedd266cddaa        ubuntu:14.04        "/bin/bash"         14 hours ago        Up 41 seconds                               ubuntu-4/ubuntu-2 

由此可知,两个ubuntu容器运行在不同的主机上,符合我们的测试要求。分别获取ubuntu-1和ubuntu-2的ip地址:

  1. fgp@ubuntu-5:~$ docker inspect -f '' ubuntu-1 
  2. 10.103.240.2 
  3. fgp@ubuntu-5:~$ docker inspect -f '' ubuntu-2 
  4. 10.103.240.3 

可见ubuntu-1的ip地址为10.103.240.2,ubuntu-2的ip地址为10.103.240.3,我们在ubuntu-1上ping ubuntu-2地址:

  1. fgp@ubuntu-5:~$ docker exec -t -i ubuntu-1 ping -c 2 10.103.240.3 
  2. PING 10.103.240.3 (10.103.240.3) 56(84) bytes of data. 
  3. 64 bytes from 10.103.240.3: icmp_seq=1 ttl=64 time=0.559 ms 
  4. 64 bytes from 10.103.240.3: icmp_seq=2 ttl=64 time=0.661 ms 
  5.  
  6. --- 10.103.240.3 ping statistics --- 
  7. 2 packets transmitted, 2 received, 0% packet loss, time 999ms 
  8. rtt min/avg/max/mdev = 0.559/0.610/0.661/0.051 ms 

结果发现,不在同一主机的ubuntu-1和ubuntu-2能够正常通信!

【本文是51CTO专栏作者“付广平”的原创文章,如需转载请通过51CTO获得联系】

戳这里,看该作者更多好文

责任编辑:武晓燕 来源: 51CTO专栏
相关推荐

2011-08-31 13:22:37

PhoneGapAndroidjavascript

2011-04-22 10:30:11

VMwareWindowsFTP

2022-07-20 15:19:17

容器Docker

2014-11-11 15:25:00

Dockerambassador云计算

2021-08-11 14:31:52

鸿蒙HarmonyOS应用

2009-12-22 09:11:31

WCF双向通信

2023-08-01 08:43:29

Python多线程

2009-12-03 18:15:04

Linux

2020-10-26 15:11:50

Docker容器IT

2009-07-15 16:05:04

IP通信捷思锐科技Zed-3

2021-06-28 10:20:31

网络技术Kubernetes通信

2015-11-09 09:52:23

Docker1.9跨主机网络新特性

2011-09-05 10:07:03

多媒体融合通信智能化

2011-06-22 17:49:35

Linux Qt 串口

2015-01-08 10:29:59

Shipyardweb管理集中化

2020-02-05 14:31:04

两种互通方法

2010-01-04 16:50:04

Silverlight

2011-08-05 11:29:07

路由器

2023-11-13 09:28:20

跨组件组件化

2009-12-08 17:00:19

路由器功能
点赞
收藏

51CTO技术栈公众号