使用DragonFly進行智慧鏡像分發
- 2020 年 6 月 21 日
- 筆記
- docker, dragonfly, Kubernetes
Dragonfly 是一款基於 P2P 的智慧鏡像和文件分發工具。它旨在提高文件傳輸的效率和速率,最大限度地利用網路頻寬,尤其是在分發大量數據時,例如應用分發、快取分發、日誌分發和鏡像分發。
在阿里巴巴,Dragonfly 每個月會被調用 20 億次,分發的數據量高達 3.4PB。Dragonfly 已成為阿里巴巴基礎設施中的重要一環。
儘管容器技術大部分時候簡化了運維工作,但是它也帶來了一些挑戰:例如鏡像分發的效率問題,尤其是必須在多個主機上複製鏡像分發時。
Dragonfly 在這種場景下能夠完美支援 Docker 和 PouchContainer。它也兼容其他格式的容器。相比原生方式,它能將容器分發速度提高 57 倍,並讓 Registry 網路出口流量降低 99.5%。
Dragonfly 能讓所有類型的文件、鏡像或數據分發變得簡單而經濟。
更多請通過官方文檔了解。
純Docker部署
這裡採用多機部署,方案如下:
應用 | IP |
---|---|
服務端 | 172.17.100.120 |
客戶端 | 172.17.100.121 |
客戶端 | 172.17.100.122 |
部署服務端
以docker方式部署,命令如下:
docker run -d --name supernode --restart=always -p 8001:8001 -p 8002:8002 \
dragonflyoss/supernode:0.3.0 -Dsupernode.advertiseIp=172.17.100.120
部署客戶端
準備配置文件
Dragonfly 的配置文件默認位於 /etc/dragonfly
目錄下,使用容器部署客戶端時,需要將配置文件掛載到容器內。
為客戶端配置 Dragonfly Supernode 地址:
cat <<EOD > /etc/dragonfly/dfget.yml
nodes:
- 172.17.100.120
EOD
啟動客戶端
docker run -d --name dfclient --restart=always -p 65001:65001 \
-v /etc/dragonfly:/etc/dragonfly \
dragonflyoss/dfclient:v0.3.0 --registry //index.docker.io
registry是倉庫地址,這裡使用的官方倉庫
修改Docker Daemon配置
我們需要修改 Dragonfly 客戶端機器(dfclient0
, dfclient1
)上 Docker Daemon 配置,通過 mirror 方式來使用 Dragonfly 進行鏡像的拉取。
在配置文件 /etc/docker/daemon.json
中添加或更新如下配置項:
{
"registry-mirrors": ["//127.0.0.1:65001"]
}
然後重啟Docker
systemctl restart docker
拉取鏡像測試
在任意一台客戶端上進行測試,比如:
docker pull tomcat
驗證
查看client端的日誌,如果輸出如下,則表示是通過DragonFly來傳輸的。
docker exec dfclient grep 'downloading piece' /root/.small-dragonfly/logs/dfclient.log
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 節點來完成傳輸,可以執行以下命令:
docker exec dfclient grep 'downloading piece' /root/.small-dragonfly/logs/dfclient.log | grep -v cdnnode
如果以上命令沒有輸出結果,則說明鏡像沒有通過其他peer節點完成傳輸,否則說明通過其他peer節點完成傳輸。
在Kubernetes中部署
服務端以Deployment的形式部署
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: supernode
name: supernode
namespace: kube-system
spec:
replicas: 1
selector:
matchLabels:
app: supernode
template:
metadata:
labels:
app: supernode
annotations:
scheduler.alpha.kubernetes.io/critical-pod: ""
spec:
containers:
- image: dragonflyoss/supernode:0.3.0
name: supernode
ports:
- containerPort: 8080
hostPort: 8080
name: tomcat
protocol: TCP
- containerPort: 8001
hostPort: 8001
name: register
protocol: TCP
- containerPort: 8002
hostPort: 8002
name: download
protocol: TCP
volumeMounts:
- mountPath: /etc/localtime
name: ltime
- mountPath: /home/admin/supernode/logs/
name: log
- mountPath: /home/admin/supernode/repo/
name: data
hostNetwork: true
dnsPolicy: ClusterFirstWithHostNet
restartPolicy: Always
tolerations:
- effect: NoExecute
operator: Exists
- effect: NoSchedule
operator: Exists
nodeSelector:
node-role.kubernetes.io/master: ""
volumes:
- hostPath:
path: /etc/localtime
type: ""
name: ltime
- hostPath:
path: /data/log/supernode
type: DirectoryOrCreate
name: log
- hostPath:
path: /data/supernode/repo/
type: DirectoryOrCreate
name: data
---
kind: Service
apiVersion: v1
metadata:
name: supernode
namespace: kube-system
spec:
selector:
app: supernode
ports:
- name: register
protocol: TCP
port: 8001
targetPort: 8001
- name: download
protocol: TCP
port: 8002
targetPort: 8002
以hostNetwork的形式部署在master上。
部署過後可以看到supernode已經正常啟動了。
# kubectl get pod -n kube-system | grep supernode
supernode-86dc99f6d5-mblck 1/1 Running 0 4m1s
客戶端以daemonSet的形式部署,yaml文件如下:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: dfdaemon
namespace: kube-system
spec:
selector:
matchLabels:
app: dfdaemon
template:
metadata:
annotations:
scheduler.alpha.kubernetes.io/critical-pod: ""
labels:
app: dfdaemon
spec:
containers:
- image: dragonflyoss/dfclient:v0.3.0
name: dfdaemon
imagePullPolicy: IfNotPresent
args:
- --registry //index.docker.io
resources:
requests:
cpu: 250m
volumeMounts:
- mountPath: /etc/dragonfly/dfget.yml
subPath: dfget.yml
name: dragonconf
hostNetwork: true
dnsPolicy: ClusterFirstWithHostNet
restartPolicy: Always
tolerations:
- effect: NoExecute
operator: Exists
- effect: NoSchedule
operator: Exists
volumes:
- name: dragonconf
configMap:
name: dragonfly-conf
配置文件我們以configMap的形式掛載,所以我們還需要編寫一個configMap的yaml文件,如下:
apiVersion: v1
kind: ConfigMap
metadata:
name: dragonfly-conf
namespace: kube-system
data:
dfget.yml: |
nodes:
- 172.17.100.120
部署過後觀察結果
# kubectl get pod -n kube-system | grep dfdaemon
dfdaemon-mj4p6 1/1 Running 0 3m51s
dfdaemon-wgq5d 1/1 Running 0 3m51s
dfdaemon-wljt6 1/1 Running 0 3m51s
然後修改docker daemon的配置,如下:
{
"registry-mirrors": ["//127.0.0.1:65001"]
}
重啟docker
systemctl restart docker
現在我們來拉取鏡像測試,並觀察日誌輸出。
下載鏡像(在master上測試的):
docker pull nginx
然後觀察日誌
kubectl exec -n kube-system dfdaemon-wgq5d grep 'downloading piece' /root/.small-dragonfly/logs/dfclient.log
看到日誌輸出如下,表示成功
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}
今天的測試就到這裡,我這是自己的小集群實驗室,效果其實並不明顯,在大集群效果可能更好。