Dragonfly V2 分發(fā)集群的鏡像
1. Dragonfly 簡(jiǎn)介
Dragonfly 的相關(guān)文檔在社區(qū) https://d7y.io/zh/docs/ 已經(jīng)有詳細(xì)說(shuō)明。這里只是簡(jiǎn)單介紹一下,V2 版本的主要組件:
- Manager,提供 UI 界面、用戶(hù)管理、集群監(jiān)控、任務(wù)管理等功能
- Scheduler,調(diào)度 Peer 之間的流量、提供預(yù)熱等功能
- Seed Peer,回源節(jié)點(diǎn),用于從源站(Harbor、Docker.io 等)下載數(shù)據(jù),也可以作為 Peer 節(jié)點(diǎn)
- Peer,提供下載數(shù)據(jù)的終端節(jié)點(diǎn)
其中 Manager、Scheduler 是單獨(dú)的容器鏡像,Seed Peer 和 Peer 是同一個(gè)容器鏡像。
Dragonfly 支持的鏡像預(yù)熱功能,可以和 Harbor 進(jìn)行集成,但本文不會(huì)涉及。本文主要是介紹我們?cè)谥?AI 業(yè)務(wù)時(shí),生產(chǎn)環(huán)境下的一些實(shí)踐。值得注意的是 Dragonfly V2 實(shí)際上構(gòu)建了一個(gè) P2P 分發(fā)的網(wǎng)絡(luò),不僅可以分發(fā)鏡像,還可以分發(fā)文件,這就打開(kāi)了想象空間。
2. IDC 機(jī)房中的 Dragonfly 集群
我們 AI 模型的推理和訓(xùn)練都是基于 Kubernetes 集群,后端存儲(chǔ)采用的是企業(yè)版 JuiceFS,在每個(gè) Node 節(jié)點(diǎn)都掛載了幾個(gè) T 的 SSD 磁盤(pán),用來(lái)掛載 JuiceFS 的緩存目錄。
因此,Kubernetes 集群中的每個(gè) Node 節(jié)點(diǎn)都具備作為 Dragonfly Peer 節(jié)點(diǎn)的條件。但 Peer 組網(wǎng)時(shí),我們不希望有額外的負(fù)擔(dān),包括:
- 跨 VPC 的 NAT 流量
- 公網(wǎng)傳輸數(shù)據(jù)
下面是 Dragonflyv2 機(jī)房多 VPC 部署拓?fù)鋱D:

- LB 需要公網(wǎng) IP,作為 Peer 的接入點(diǎn)
- 一個(gè) VPC 對(duì)應(yīng)一個(gè) Dragonfly 的 Cluster 抽象
- 雖然 IDC 打通了 VPC 之間的網(wǎng)絡(luò),但一個(gè) VPC 內(nèi)的 Peer 才允許組網(wǎng)
- 集群內(nèi)每個(gè) Node 節(jié)點(diǎn)部署一個(gè) Peer
VPC 內(nèi),下面這張圖給出了詳細(xì)的高可用方案。

- LB 只需要內(nèi)網(wǎng) IP 即可
- 使用云廠(chǎng)的 MySQL 8.0、Redis 6 服務(wù)
- 兩臺(tái) VM 部署 Manager、Scheduler、Seed Peer
- 每個(gè) VM 部署的是一套完整的 Dragonfly 集群,包括 Manager、Scheduler、Seed Peer,不用經(jīng)過(guò) LB 也能用
- 每個(gè) Node 節(jié)點(diǎn)部署 Peer
Dragonfly 構(gòu)建的 P2P 分發(fā)網(wǎng)絡(luò),不應(yīng)該和 PaaS 層耦合太緊密,避免循環(huán)依賴(lài)。因此,這里采用雙 VM 的方案,共享數(shù)據(jù)存儲(chǔ),保障可用性。在 Kubernetes 集群的 Master 節(jié)點(diǎn)上,我們也不會(huì)進(jìn)行加速優(yōu)化,保障 PaaS 層控制面的簡(jiǎn)潔和獨(dú)立。
3. VM 上部署 Dragonfly 控制平面
需要提前安裝好 Docker,分別在兩臺(tái) VM 上進(jìn)行獨(dú)立部署。
3.1 安裝 docker-compose
- 下載 docker-compose
curl -L https://mirror.ghproxy.com/https://github.com/docker/compose/releases/download/v2.23.3/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose
- 添加執(zhí)行權(quán)限
chmod +x /usr/local/bin/docker-compose
- 查看版本
docker-compose -v
3.2 安裝 dragonfly
參考 https://d7y.io/zh/docs/getting-started/quick-start/docker-compose/
- 下載 docker-compose 部署文件
cd /data
wget https://mirror.ghproxy.com/https://github.com/dragonflyoss/Dragonfly2/archive/refs/tags/v2.1.28.tar.gz
tar -zxvf v2.1.28.tar.gz
cp -r Dragonfly2-2.1.28/deploy/docker-compose ./
- 清理不需要的文件
rm -rf *2.1.28*
- 生成默認(rèn)的配置文件
cd docker-compose
由于默認(rèn)的發(fā)布包中,沒(méi)有配置文件,這里先生成一份配置文件,然后再修改。
export IP=VM_IP
./run.sh
立即終止執(zhí)行,然后繼續(xù)修改配置文件。
- 固定鏡像版本
sed -i 's/latest/v2.1.28/g' docker-compose.yaml
- 修改存儲(chǔ)賬號(hào)及其他配置
修改 Redis、MySQL 地址和密碼
vim template/manager.template.yaml
修改 Redis 密碼
vim template/scheduler.template.yaml
在這兩個(gè)配置文件中,還有一些其他的配置項(xiàng),可以根據(jù)實(shí)際情況進(jìn)行修改。比如,manager 的 addr 指向當(dāng)前主機(jī)的服務(wù)、將日志輸出到控制臺(tái)、開(kāi)啟 Metrics 等。
- 修改 seed-peer 的緩存目錄
vim docker-compose.yaml
volumes:
- ./cache:/var/cache/dragonfly
- ./data:/var/lib/dragonfly
如果關(guān)閉了 seed-peer 作為 peer 節(jié)點(diǎn)的功能,可以跳過(guò)這一步,同時(shí),VM 的磁盤(pán)空間也可以不用太大。
- 啟動(dòng)服務(wù)
docker-compose up -d
- 查看服務(wù)
docker-compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
manager dragonflyoss/manager:v2.1.28 "/opt/dragonfly/bin/…" manager 14 hours ago Up 14 hours (healthy) 0.0.0.0:8080->8080/tcp, 0.0.0.0:65003->65003/tcp
scheduler dragonflyoss/scheduler:v2.1.28 "/opt/dragonfly/bin/…" scheduler 14 hours ago Up 14 hours (healthy) 0.0.0.0:8002->8002/tcp
seed-peer dragonflyoss/dfdaemon:v2.1.28 "/opt/dragonfly/bin/…" seed-peer 14 hours ago Up 14 hours (healthy) 65001/tcp, 0.0.0.0:65006-65008->65006-65008/tcp
- 打開(kāi)管理頁(yè)面看看
訪(fǎng)問(wèn) http://${VM_IP}:8080 端口可以看到 Dragonfly 的管理界面,如果機(jī)器沒(méi)有公網(wǎng) IP,可以使用 socat 進(jìn)行端口轉(zhuǎn)發(fā)。找一臺(tái)有公網(wǎng) IP 的機(jī)器,執(zhí)行以下命令,將 30000 端口轉(zhuǎn)發(fā)到 8080 端口:
export IP=VM_IP
socat TCP-LISTEN:30000,fork TCP:$IP:8080
兩臺(tái) VM 部署完成,在 Dashboard 中可以看到這樣一個(gè)集群,兩個(gè) Scheduler、兩個(gè) Seed Peer。如下圖:

4. 在集群部署 Peer 節(jié)點(diǎn)
- 創(chuàng)建命名空間
kubectl create ns dragonfly-system
- 創(chuàng)建配置文件
這里需要將 LB 的 IP 地址填入配置文件中,Peer 才能接入到 Dragonfly 集群中。
export MANAGER_IP=LB_IP
有很多參數(shù),可以根據(jù)實(shí)際情況進(jìn)行修改,這里提供了一份默認(rèn)的配置文件。
kubectl apply -f - <<EOF
apiVersion: v1
data:
dfget.yaml: |
aliveTime: 0s
gcInterval: 1m0s
keepStorage: false
workHome: /usr/local/dragonfly
logDir: /var/log/dragonfly
cacheDir: /var/cache/dragonfly
pluginDir: /usr/local/dragonfly/plugins
dataDir: /var/lib/dragonfly
console: true
health:
path: /server/ping
tcpListen:
port: 40901
verbose: true
pprof-port: 18066
metrics: ":8000"
jaeger: ""
scheduler:
manager:
enable: true
netAddrs:
- type: tcp
addr: $MANAGER_IP:65003
refreshInterval: 10m
netAddrs:
scheduleTimeout: 30s
disableAutoBackSource: false
seedPeer:
clusterID: 1
enable: false
type: super
host:
idc: ""
location: ""
download:
calculateDigest: true
downloadGRPC:
security:
insecure: true
tlsVerify: true
unixListen:
socket: ""
peerGRPC:
security:
insecure: true
tcpListen:
port: 65000
perPeerRateLimit: 512Mi
prefetch: false
totalRateLimit: 1024Mi
upload:
rateLimit: 1024Mi
security:
insecure: true
tlsVerify: false
tcpListen:
port: 65002
objectStorage:
enable: false
filter: Expires&Signature&ns
maxReplicas: 3
security:
insecure: true
tlsVerify: true
tcpListen:
port: 65004
storage:
diskGCThreshold: 1000Gi
multiplex: true
strategy: io.d7y.storage.v2.simple
taskExpireTime: 72h
proxy:
defaultFilter: Expires&Signature&ns
defaultTag:
tcpListen:
port: 65001
security:
insecure: true
tlsVerify: false
registryMirror:
dynamic: true
insecure: false
url: https://index.docker.io
proxies:
- regx: blobs/sha256.*
security:
autoIssueCert: false
caCert: ""
certSpec:
dnsNames: null
ipAddresses: null
validityPeriod: 4320h
tlsPolicy: prefer
tlsVerify: false
network:
enableIPv6: false
announcer:
schedulerInterval: 30s
kind: ConfigMap
metadata:
labels:
app: dragonfly
name: dragonfly-dfdaemon
namespace: dragonfly-system
EOF
- 創(chuàng)建 DaemonSet
我們從官方的 Helm Chart 中提取出來(lái)的 DaemonSet 文件。需要注意的是,Peer 使用的緩存目錄是主機(jī)上的 /data/dfget 目錄。最好提前清理主機(jī)上的 /data/dfget 目錄,避免出現(xiàn)權(quán)限問(wèn)題,也不用提前創(chuàng)建,DaemonSet 會(huì)自動(dòng)創(chuàng)建。
kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: DaemonSet
metadata:
labels:
app: dragonfly
name: dragonfly-dfdaemon
namespace: dragonfly-system
spec:
selector:
matchLabels:
app: dragonfly
template:
metadata:
labels:
app: dragonfly
spec:
containers:
- image: dragonflyoss/dfdaemon:v2.1.28
livenessProbe:
exec:
command:
- /bin/grpc_health_probe
- -addr=:65000
name: dfdaemon
ports:
- containerPort: 65001
protocol: TCP
- containerPort: 40901
hostIP: 127.0.0.1
hostPort: 40901
protocol: TCP
- containerPort: 8000
protocol: TCP
readinessProbe:
exec:
command:
- /bin/grpc_health_probe
- -addr=:65000
failureThreshold: 3
initialDelaySeconds: 5
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
resources:
limits:
cpu: "2"
memory: 2Gi
securityContext:
capabilities:
add:
- SYS_ADMIN
volumeMounts:
- mountPath: /etc/dragonfly
name: config
- mountPath: /var/cache/dragonfly
name: dfgetcache
- mountPath: /var/lib/dragonfly
name: dfgetdata
hostNetwork: true
hostPID: true
volumes:
- configMap:
defaultMode: 420
name: dragonfly-dfdaemon
name: config
- hostPath:
path: /data/dfget/cache
type: DirectoryOrCreate
name: dfgetcache
- hostPath:
path: /data/dfget/data
type: DirectoryOrCreate
name: dfgetdata
EOF
- 查看負(fù)載
kubectl -n dragonfly-system get pod
NAME READY STATUS RESTARTS AGE
dragonfly-dfdaemon-79qkw 1/1 Running 0 14h
dragonfly-dfdaemon-8hhzb 1/1 Running 3 14h
dragonfly-dfdaemon-nnfc5 1/1 Running 0 14h
dragonfly-dfdaemon-w7lff 1/1 Running 0 14h
dragonfly-dfdaemon-wrmzw 1/1 Running 0 14h
5. 在 VM 上部署 Peer 節(jié)點(diǎn)
- 創(chuàng)建目錄
mkdir -p /data/dfget && cd /data/dfget
- 設(shè)置 IP
wget https://mirror.ghproxy.com/https://raw.githubusercontent.com/shaowenchen/hubimage/main/nydus/dfget.template.yaml -O dfget.yaml
export MANAGER_IP=LB_IP
sed -i "s/__MANAGER_IP__/$MANAGER_IP/g" dfget.yaml
- 啟動(dòng) Peer
nerdctl run -d --name=peer --restart=always \
-p 65000:65000 -p 65001:65001 -p 65002:65002 \
-v $(pwd)/data:/var/lib/dragonfly \
-v $(pwd)/cache:/var/cache/dragonfly \
-v $(pwd)/dfget.yaml:/etc/dragonfly/dfget.yaml:ro \
dragonflyoss/dfdaemon:v2.1.28
6. 使用節(jié)點(diǎn)配置
6.1 Docker
Docker 的 Mirror 方式只能加速 Docker.io 的鏡像,這里采用 Proxy 的方式,代理全部 Dockerd 的流量。Proxy 與 Mirror 的區(qū)別在于,Mirror 掛了,Dockerd 會(huì)拉取源站,而 Proxy 掛了,Dockerd 直接拉取失敗。
- 添加代理
mkdir -p /etc/systemd/system/docker.service.d
cat > /etc/systemd/system/docker.service.d/http-proxy.conf <<EOF
[Service]
Environment="HTTP_PROXY=http://127.0.0.1:65001"
Environment="HTTPS_PROXY=http://127.0.0.1:65001"
EOF
- 重啟 Docker
systemctl daemon-reload
systemctl restart docker
注意,這里如果 /etc/docker/daemon.json 中沒(méi)有配置 "live-restore": true ,會(huì)導(dǎo)致容器全部重啟。
- 查看環(huán)境變量
systemctl show --property=Environment docker
Environment=HTTP_PROXY=http://127.0.0.1:65001 HTTPS_PROXY=http://127.0.0.1:65001
- 鏡像拉取測(cè)試
docker pull nginx
此時(shí),Dockerd 的流量會(huì)經(jīng)過(guò) Dragonfly Peer 節(jié)點(diǎn)。
6.2 Containerd
參考 https://github.com/containerd/containerd/blob/main/docs/cri/config.md#registry-configuration
在 /etc/containerd/config.toml 中 [plugins."io.containerd.grpc.v1.cri".registry] 項(xiàng)的 config_path = "/etc/containerd/certs.d" 提供了類(lèi)似于 mirror 的配置方式。
- 配置 Docker.io
mkdir -p /etc/containerd/certs.d/docker.io
cat > /etc/containerd/certs.d/docker.io/hosts.toml <<EOF
server = "https://docker.io"
[host."http://127.0.0.1:65001"]
capabilities = ["pull", "resolve"]
[host."http://127.0.0.1:65001".header]
X-Dragonfly-Registry = ["https://registry-1.docker.io"]
[host."https://registry-1.docker.io"]
capabilities = ["pull", "resolve"]
EOF
- 配置其他、私有鏡像倉(cāng)庫(kù)
其他鏡像倉(cāng)庫(kù)的配置可以通過(guò)腳本生成,比如:
wget https://mirror.ghproxy.com/https://raw.githubusercontent.com/dragonflyoss/Dragonfly2/main/hack/gen-containerd-hosts.sh
bash gen-containerd-hosts.sh ghcr.io
這里沒(méi)有用腳本生成 docker.io 的配置是因?yàn)椋傻呐渲梦募校?code style="color:rgb(235,97,97);font-size:14px;font-family:'Operator Mono', Consolas, Monaco, Menlo, monospace;">X-Dragonfly-Registry 是 https://docker.io,而不是 https://registry-1.docker.io。
使用 X-Dragonfly-Registry = ["https://docker.io"] 會(huì)出現(xiàn)如下錯(cuò)誤:
unknow type: text/html
以上添加的 mirror,不用重啟 Containerd,直接能生效。
- 鏡像拉取測(cè)試
nerdctl pull nginx
此時(shí),在本地 /data/dfget/data 目錄下可以看到 Peer 節(jié)點(diǎn)緩存的鏡像數(shù)據(jù)。
7. 集成 Nydus
如果 Nydus 已經(jīng)配置好,這里其實(shí)已經(jīng)能輕松配置好。
- 給 Nydusd 添加 mirror
vim /etc/nydus/nydusd-config.fusedev.json
{
"device": {
"backend": {
"type": "registry",
"config": {
"mirrors": [
{
"host": "http://127.0.0.1:65001",
"auth_through": false,
"headers": {
"X-Dragonfly-Registry": "https://index.docker.io"
},
"ping_url": "http://127.0.0.1:40901/server/ping"
}
]
}
}
}
}
- 重啟 Nydusd
systemctl restart nydus-snapshotter
- 鏡像拉取測(cè)試
nerdctl pull shaowenchen/demo-ubuntu:latest-nydus
8. 總結(jié)
本篇記錄了這周在生產(chǎn)環(huán)境中,測(cè)試并部署 Dragonfly V2 的部分過(guò)程,主要內(nèi)容包括:
- 機(jī)房中 Dragonfly 集群的部署拓?fù)?/li>
- 集群和 VM 上 Peer 節(jié)點(diǎn)的部署
- Docker、Containerd、Nydus 的集成
說(shuō)下不足,沒(méi)有指標(biāo)監(jiān)控,在做 Benchmark 時(shí),我們發(fā)現(xiàn) AZ 內(nèi)和跨 AZ 的 Peer 之間的數(shù)據(jù)傳輸都受限,如果想構(gòu)建高性能的 P2P 分發(fā)網(wǎng)絡(luò),Peer 與 Peer、Peer 與 Seed Peer 之間的網(wǎng)絡(luò)是一個(gè)重要的考量因素。

