Dragonfly 是一款基于 P2P 的智能镜像和文件分发工具。它旨在提高文件传输的效率和速率,最大限度地利用网络带宽,尤其是在分发大量数据时,例如应用分发、缓存分发、日志分发和镜像分发。

在阿里巴巴,Dragonfly 每个月会被调用 20 亿次,分发的数据量高达 3.4PB。Dragonfly 已成为阿里巴巴基础设施中的重要一环。

尽管容器技术大部分时候简化了运维工作,但是它也带来了一些挑战:例如镜像分发的效率问题,尤其是必须在多个主机上复制镜像分发时。

Dragonfly 在这种场景下能够完美支持 Docker 和 PouchContainer。它也兼容其他格式的容器。相比原生方式,它能将容器分发速度提高 57 倍,并让 Registry 网络出口流量降低 99.5%。
Dragonfly 能让所有类型的文件、镜像或数据分发变得简单而经济。

更多请通过官方文档了解。

纯Docker部署

这里采用多机部署,方案如下:
13.6、使用DragonFly进行智能镜像分发 - 图1

应用 IP
服务端 172.17.100.120
客户端 172.17.100.121
客户端 172.17.100.122

部署服务端

以docker方式部署,命令如下:

  1. docker run -d --name supernode --restart=always -p 8001:8001 -p 8002:8002 \
  2. dragonflyoss/supernode:0.3.0 -Dsupernode.advertiseIp=172.17.100.120

部署客户端

准备配置文件
Dragonfly 的配置文件默认位于 /etc/dragonfly 目录下,使用容器部署客户端时,需要将配置文件挂载到容器内。
为客户端配置 Dragonfly Supernode 地址:

  1. cat <<EOD > /etc/dragonfly/dfget.yml
  2. nodes:
  3. - 172.17.100.120
  4. EOD

启动客户端
  1. docker run -d --name dfclient --restart=always -p 65001:65001 \
  2. -v /etc/dragonfly:/etc/dragonfly \
  3. dragonflyoss/dfclient:v0.3.0 --registry https://index.docker.io

registry是仓库地址,这里使用的官方仓库

修改Docker Daemon配置

我们需要修改 Dragonfly 客户端机器(dfclient0, dfclient1)上 Docker Daemon 配置,通过 mirror 方式来使用 Dragonfly 进行镜像的拉取。
在配置文件 /etc/docker/daemon.json 中添加或更新如下配置项:

  1. {
  2. "registry-mirrors": ["http://127.0.0.1:65001"]
  3. }

然后重启Docker

  1. systemctl restart docker

拉取镜像测试

在任意一台客户端上进行测试,比如:

  1. docker pull tomcat

验证

查看client端的日志,如果输出如下,则表示是通过DragonFly来传输的。

  1. docker exec dfclient grep 'downloading piece' /root/.small-dragonfly/logs/dfclient.log
  1. 2020-06-20 15:56:49.813 INFO sign:146-1592668602.159 : downloading piece:{"taskID":"4d977359836129ce2eec4b8418a7042c47db547a239e2a577ddc787ee177289c","superNode":"172.17.100.120","dstCid":"cdnnode:172.17.100.120~4d977359836129ce2eec4b8418a7042c47db547a239e2a577ddc787ee177289c","range":"0-4194303","result":503,"status":701,"pieceSize":4194304,"pieceNum":0}

如果需要查看镜像是否通过其他 peer 节点来完成传输,可以执行以下命令:

  1. docker exec dfclient grep 'downloading piece' /root/.small-dragonfly/logs/dfclient.log | grep -v cdnnode

如果以上命令没有输出结果,则说明镜像没有通过其他peer节点完成传输,否则说明通过其他peer节点完成传输。

在Kubernetes中部署

服务端以Deployment的形式部署

  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. labels:
  5. app: supernode
  6. name: supernode
  7. namespace: kube-system
  8. spec:
  9. replicas: 1
  10. selector:
  11. matchLabels:
  12. app: supernode
  13. template:
  14. metadata:
  15. labels:
  16. app: supernode
  17. annotations:
  18. scheduler.alpha.kubernetes.io/critical-pod: ""
  19. spec:
  20. containers:
  21. - image: dragonflyoss/supernode:0.3.0
  22. name: supernode
  23. ports:
  24. - containerPort: 8080
  25. hostPort: 8080
  26. name: tomcat
  27. protocol: TCP
  28. - containerPort: 8001
  29. hostPort: 8001
  30. name: register
  31. protocol: TCP
  32. - containerPort: 8002
  33. hostPort: 8002
  34. name: download
  35. protocol: TCP
  36. volumeMounts:
  37. - mountPath: /etc/localtime
  38. name: ltime
  39. - mountPath: /home/admin/supernode/logs/
  40. name: log
  41. - mountPath: /home/admin/supernode/repo/
  42. name: data
  43. hostNetwork: true
  44. dnsPolicy: ClusterFirstWithHostNet
  45. restartPolicy: Always
  46. tolerations:
  47. - effect: NoExecute
  48. operator: Exists
  49. - effect: NoSchedule
  50. operator: Exists
  51. nodeSelector:
  52. node-role.kubernetes.io/master: ""
  53. volumes:
  54. - hostPath:
  55. path: /etc/localtime
  56. type: ""
  57. name: ltime
  58. - hostPath:
  59. path: /data/log/supernode
  60. type: DirectoryOrCreate
  61. name: log
  62. - hostPath:
  63. path: /data/supernode/repo/
  64. type: DirectoryOrCreate
  65. name: data
  66. ---
  67. kind: Service
  68. apiVersion: v1
  69. metadata:
  70. name: supernode
  71. namespace: kube-system
  72. spec:
  73. selector:
  74. app: supernode
  75. ports:
  76. - name: register
  77. protocol: TCP
  78. port: 8001
  79. targetPort: 8001
  80. - name: download
  81. protocol: TCP
  82. port: 8002
  83. targetPort: 8002

以hostNetwork的形式部署在master上。

部署过后可以看到supernode已经正常启动了。

  1. # kubectl get pod -n kube-system | grep supernode
  2. supernode-86dc99f6d5-mblck 1/1 Running 0 4m1s

客户端以daemonSet的形式部署,yaml文件如下:

  1. apiVersion: apps/v1
  2. kind: DaemonSet
  3. metadata:
  4. name: dfdaemon
  5. namespace: kube-system
  6. spec:
  7. selector:
  8. matchLabels:
  9. app: dfdaemon
  10. template:
  11. metadata:
  12. annotations:
  13. scheduler.alpha.kubernetes.io/critical-pod: ""
  14. labels:
  15. app: dfdaemon
  16. spec:
  17. containers:
  18. - image: dragonflyoss/dfclient:v0.3.0
  19. name: dfdaemon
  20. imagePullPolicy: IfNotPresent
  21. args:
  22. - --registry https://index.docker.io
  23. resources:
  24. requests:
  25. cpu: 250m
  26. volumeMounts:
  27. - mountPath: /etc/dragonfly/dfget.yml
  28. subPath: dfget.yml
  29. name: dragonconf
  30. hostNetwork: true
  31. dnsPolicy: ClusterFirstWithHostNet
  32. restartPolicy: Always
  33. tolerations:
  34. - effect: NoExecute
  35. operator: Exists
  36. - effect: NoSchedule
  37. operator: Exists
  38. volumes:
  39. - name: dragonconf
  40. configMap:
  41. name: dragonfly-conf

配置文件我们以configMap的形式挂载,所以我们还需要编写一个configMap的yaml文件,如下:

  1. apiVersion: v1
  2. kind: ConfigMap
  3. metadata:
  4. name: dragonfly-conf
  5. namespace: kube-system
  6. data:
  7. dfget.yml: |
  8. nodes:
  9. - 172.17.100.120

部署过后观察结果

  1. # kubectl get pod -n kube-system | grep dfdaemon
  2. dfdaemon-mj4p6 1/1 Running 0 3m51s
  3. dfdaemon-wgq5d 1/1 Running 0 3m51s
  4. dfdaemon-wljt6 1/1 Running 0 3m51s

然后修改docker daemon的配置,如下:

  1. {
  2. "registry-mirrors": ["http://127.0.0.1:65001"]
  3. }

重启docker

  1. systemctl restart docker

现在我们来拉取镜像测试,并观察日志输出。
下载镜像(在master上测试的):

  1. docker pull nginx

然后观察日志

  1. kubectl exec -n kube-system dfdaemon-wgq5d grep 'downloading piece' /root/.small-dragonfly/logs/dfclient.log

看到日志输出如下,表示成功

  1. 2020-06-20 17:14:54.578 INFO sign:128-1592673287.190 : downloading piece:{"taskID":"089dc52627a346df2a2ff67f6c07497167b35c4bad2bca1e9aad087441116982","superNode":"172.17.100.120","dstCid":"cdnnode:192.168.235.192~089dc52627a346df2a2ff67f6c07497167b35c4bad2bca1e9aad087441116982","range":"0-4194303","result":503,"status":701,"pieceSize":4194304,"pieceNum":0}

今天的测试就到这里,我这是自己的小集群实验室,效果其实并不明显,在大集群效果可能更好。