基于dragonfly p2p技术加速容器镜像分发实践

概述

首先p2p网络是一种分布式的去中心化的网络,在网络中每个节点的地位都是对等的,每个节点既能充当服务器,也同时能为其他节点提供服务,同时也享有其他节点提供的服务。

为什么需要引入p2p技术来加速镜像分发?
在大规模的容器集群内,镜像分发,往往需要消耗大量时间,并且会给镜像仓库带来很大的压力负担,通过p2p技术将流量分担到集群的每个节点上,这样可以大大缩短下载镜像的时间,并且能非常有效的减轻镜像仓库的压力。

 

Dragonfly介绍

这里我们使用的是阿里巴巴开源的基于P2P技术的PB级文件分发系统蜻蜓(dragonfly)。

 

 

引用阿里巴巴双11技术解密内容:
蜻蜓整体架构分三层:第一层是 Config Service,他管理所有的 Cluster Manager,Cluster Manager 又管理所有的 Host,Host 就是终端,dfget 就是类似 wget 的一个客户端程序。
Config Service 主要负责 Cluster Manager 的管理、客户端节点路由、系统配 置管理以及预热服务等等。简单的说,就是负责告诉 Host,离他最近的一组 Cluster Manager 的地址列表,并定期维护和更新这份列表,使 Host 总能找到离他最近的 Cluster Manager。
Cluster Manager 主要的职责有两个:

  • 以被动 CDN 方式从文件源下载文件并生成一组种子分块数据;
  • 构造 P2P 网络并调度每个 peer 之间互传指定的分块数据。Host 上就存放着 dfget,dfget 的语法跟 wget 非常类似。

主要功能包括文件下 载和 P2P 共享等。

原理

两个 Host 和 CM 会组成一个 P2P 网络,首先 CM 会查看本地是否有缓存,如果没有,就会回源下载,文件当然会被分片,CM 会多线程下载这些分片,同时会将 下载的分片提供给 Host 们下载,Host 下载完一个分片后,同时会提供出来给 peer 下载,如此类推,直到所有的 Host 全部下载完。
本地下载的时候会将下载分片的情况记录在 metadata 里,如果突然中断了下 载,再次执行 dfget 命令,会断点续传。
下载结束后,还会比对 MD5,以确保下载的文件和源文件是完全一致的。蜻蜓通过 HTTP cache 协议来控制 CM 端对文件的缓存时长,CM 端当然也有自己定期 清理磁盘的能力,确保有足够的空间支撑长久的服务。
需要注意的是开源版的dragonfly目前没有开源config-Service。

 

 

使用Dragonfly做docker镜像分发

技术原理类似我们用的BT下载技术的bitorrent协议
cluster-manager就类似于Tracker服务器。
.meta类似于torrent文件
通过torrent文件,获取其他正在下载该文件的网址名单,根据torrent文件的网址然后连接tracker服务器,从tracker服务器获取正在下载该文件的网址名单,然后与它们取得联系,从他们那里获取文件的片端,直到整个下载完成。
原理(来源官方github)

 

首先,docker pull 命令,会被 dfget proxy 截获。然后,由 dfget proxy 向 CM 发送调度请求,CM 在收到请求后会检查对应的下载文件是否已经被缓存到本地,如果没有被缓存,则会从Registry 中下载对应的文件,并生成种子分块数据(种子分块数据一旦生成就可以立即被使用);如果已经被缓存,则直接生成分块任务,请求者解析相应的分块任务,并从其他 peer 或者 supernode 中下载分块数据,当某个Layer的所有分块下载完成后,一个Layer也就下载完毕了,同样,当所有的Layer下载完成后,整个镜像也就下载完成了。

文件分块的下载

 

注: 其中cluster manager即超级节点(supernode)

每个文件会被分成多个块在对等者(peer)间进行传输。一个peer就是一个P2P客户端。
超级节点会判断文件是否存在本地,如果不存在,则会将其从文件服务器下载到本地。

配置方法
主要参考官方的服务端和客户端的安装和使用
https://github.com/alibaba/Dragonfly/tree/master/docs/zh
软件版本:
docker:17.03-2
os:ubuntu16.04
Dragonfly:0.2.0
Harbor:1.4.0

环境信息

rke-node1:172.31.164.57
rke-node2:172.31.164.58
rke-node3:172.31.164.59
Harbor:172.31.164.66
cluster-manger:172.31.164.113

 

安装cluster-manger(https://github.com/alibaba/Dragonfly/blob/master/docs/zh/install_server.md)
分为两种方式
1、通过docker镜像方式安装,适于用快速部署测试的环境。
2、源码编译安装,适用于生产环境部署
我们这里主要介绍docker镜像方式安装,源码方式安装参考上述链接。
clone 代码

git clone https://github.com/alibaba/Dragonfly.git

 

进入项目目录

cd Dragonfly

 

编译代码,打包镜像需要本地安装java环境和maven

./build/build.sh supernode

 

获取镜像ID

${superNodeDockerImageId}=`docker image ls|grep 'supernode' |awk '{print $3}' | head -n1`

 

启动cluster-manger

docker run -d -p 8001:8001 -p 8002:8002 ${superNodeDockerImageId}

 

测试验证
telnet 127.0.0.1 8001
telent 127.0.0.1 8002

安装client端(https://github.com/alibaba/Dragonfly/blob/master/docs/zh/install_client.md)
安装客户端

wget https://github.com/alibaba/Dragonfly/raw/master/package/df-client.linux-amd64.tar.gz

#创建文件夹存放
mkdir /root/install
tar xzvf df-client.linux-amd64.tar.gz -C /root/install

#设置环境变量
vim ~/.bashrc
PATH=$PATH:/root/install/df-client

source ~/.bashrc

 

验证执行命令

df-daemon -h

Usage of df-daemon:
 -callsystem string
     caller name (default "com_ops_dragonfly")
 -certpem string
     cert.pem file path
 -dfpath string
     dfget path (default "/root/install/df-client/dfget")
 -h	help
 -keypem string
     key.pem file path
 -localrepo string
     temp output dir of daemon (default "/root/.small-dragonfly/dfdaemon/data/")
 -notbs
     not try back source to download if throw exception (default true)
 -port uint
     daemon will listen the port (default 65001)
 -ratelimit string
     net speed limit,format:xxxM/K
 -registry string
     registry addr(https://abc.xx.x or http://abc.xx.x) and must exist if df-daemon is used to mirror mode
 -rule string
     download the url by P2P if url matches the specified pattern,format:reg1,reg2,reg3
 -urlfilter string
     filter specified url fields (default "Signature&Expires&OSSAccessKeyId")
 -v	version
 -verbose
     verbose
使用方法
配置客户端连接超级节点
vi /etc/dragonfly.conf


[node]
address=172.31.164.113 #多台cluster-manger用逗号分隔
启动dfdaemon,指定镜像仓库地址,默认端口为65001
df-daemon --registry 172.31.164.66 &

 

配置docker-mirror和docker http-proxy

vim /etc/docker/daemon.json
{
  "registry-mirrors": [
    "http://127.0.0.1:65001"
],
  "insecure-registries" : [
     "http://127.0.0.1:65001",
     "172.31.164.66"
]
}




vim /lib/systemd/system/docker.service
Environment="HTTP_PROXY=http://127.0.0.1:65001"


重启docker
systemctl daemon-reload
systemctl restart docker

 

验证
直接将Harbor的地址改成 127.0.0.1:65001就可以拉取镜像,看看是否能拉取成功

docker pull 127.0.0.1:65001/library/front-end:30

 

Harbor内公开的项目镜像拉取,不用输入镜像仓库地址拉取

docker pull library/front-end:30

 

注意点:
1、private registry不能提供mirror的方式将流量转发到df-daemon,只能通过给docker配置http proxy的方式,原因在于docker pull project_name/image_name:tag方式下载镜像时不会在请求头里面携带docker login时输入的账号和密码而通过docker pull registry_address/project_name/image_name:tag方式会在请求头内通过authorization传递login时输入的账号和密码 。

2、蜻蜓默认是限速20M的,取消限速的方法https://github.com/alibaba/Dragonfly/issues/38

抓包分析

tcpdump -i lo port 65001  #确实有大量数据包经过

 

数据查看
查看到大量数据分片

ls ~/.small-dragonfly/data/

 

查看下载日志

less ~/.small-dragonfly/logs/dfclient.log

因为性能测试需要大并发,大流量环境下才能对比出差异性,所以这里性能测试结果使用阿里巴巴官方测试数据

上图可以看出,随着下载规模的扩大,蜻蜓与 Native 模式耗时差异显著扩 大,最高可提速可以达 20 倍。在测试环境中源的带宽也至关重要,如果源的带宽是 2Gbps,提速可达 57 倍。

 

向 200 个节点分发 500M 的镜像,比 docker 原生模式使用更低的网络流量, 实验数据表明采用蜻蜓后,Registry 的出流量降低了 99.5% 以上;而在 1000 并发 规模下,Registry 的出流量更可以降低到 99.9% 左右。

项目地址:
https://github.com/alibaba/Dragonfly

发表评论