Skip to main content
Version: Next

Lightweight Deployment

Documentation for deploying Dragonfly on multi-cluster kubernetes using helm. A Dragonfly cluster manages cluster within a network. If you have two clusters with disconnected networks, you can use two Dragonfly clusters to manage their own clusters.

Without the Manager, deploy a Dragonfly cluster per kubernetes cluster. Each deployment has its own scheduler headless service and dynconfig.yaml ConfigMap, and clients only discover the schedulers of their own deployment, so each deployment forms an isolated P2P network. Because peer can only transmit data in its own Dragonfly cluster, if a kubernetes cluster deploys a Dragonfly cluster, then a kubernetes cluster forms a p2p network, and internal peers can only schedule and transmit data in a kubernetes cluster.

Runtime

You can have a quick start following Helm Charts. It is recommended to use containerd.

RuntimeVersion
containerdv1.1.0+
Dockerv20.0.1+
CRI-OAll

Setup kubernetes cluster

Kind is recommended if no Kubernetes cluster is available for testing.

Create kind cluster configuration file kind-config.yaml, configuration content is as follows:

kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
labels:
cluster: a
- role: worker
labels:
cluster: a
- role: worker
labels:
cluster: b
- role: worker
labels:
cluster: b

Create cluster using the configuration file:

kind create cluster --config kind-config.yaml

Switch the context of kubectl to kind cluster:

kubectl config use-context kind-kind

Kind loads Dragonfly image

Pull Dragonfly latest images:

docker pull dragonflyoss/scheduler:latest
docker pull dragonflyoss/client:latest
docker pull dragonflyoss/dfinit:latest

Kind cluster loads Dragonfly latest images:

kind load docker-image dragonflyoss/scheduler:latest
kind load docker-image dragonflyoss/client:latest
kind load docker-image dragonflyoss/dfinit:latest

Create Dragonfly cluster

Each Dragonfly cluster is deployed as an independent helm release in its own namespace. The clients of each release use the scheduler headless service of their own release for scheduler discovery, so the two Dragonfly clusters are isolated from each other.

Create Dragonfly cluster A

Create Dragonfly cluster A based on helm charts

Create Dragonfly cluster A charts configuration file charts-config-cluster-a.yaml, configuration content is as follows:

scheduler:
nodeSelector:
cluster: a
image:
repository: dragonflyoss/scheduler
tag: latest
metrics:
enable: true

seedClient:
nodeSelector:
cluster: a
image:
repository: dragonflyoss/client
tag: latest
metrics:
enable: true

client:
nodeSelector:
cluster: a
image:
repository: dragonflyoss/client
tag: latest
metrics:
enable: true
dfinit:
enable: true
image:
repository: dragonflyoss/dfinit
tag: latest
config:
containerRuntime:
containerd:
configPath: /etc/containerd/config.toml
proxyAllRegistries: true

Create Dragonfly cluster A using the configuration file:

$ helm repo add dragonfly https://dragonflyoss.github.io/helm-charts/
$ helm install --wait --create-namespace --namespace cluster-a dragonfly dragonfly/dragonfly -f charts-config-cluster-a.yaml
NAME: dragonfly
LAST DEPLOYED: Mon Jul 27 21:23:00 2026
NAMESPACE: cluster-a
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
1. Dragonfly is running without the manager. The scheduler and client load the dynamic
configuration from the local dynconfig.yaml file mounted as a ConfigMap, and clients
discover schedulers via the scheduler headless service:
dragonfly-scheduler.cluster-a.svc.cluster.local:8002

2. Get the scheduler address by running these commands:
export SCHEDULER_POD_NAME=$(kubectl get pods --namespace cluster-a -l "app=dragonfly,release=dragonfly,component=scheduler" -o jsonpath={.items[0].metadata.name})
export SCHEDULER_CONTAINER_PORT=$(kubectl get pod --namespace cluster-a $SCHEDULER_POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
kubectl --namespace cluster-a port-forward $SCHEDULER_POD_NAME 8002:$SCHEDULER_CONTAINER_PORT
echo "Visit http://127.0.0.1:8002 to use your scheduler"

3. Configure runtime to use dragonfly:
https://d7y.io/docs/getting-started/quick-start/kubernetes/

Check that Dragonfly cluster A is deployed successfully:

$ kubectl get po -n cluster-a
NAME READY STATUS RESTARTS AGE
dragonfly-client-5gvz7 1/1 Running 0 3m
dragonfly-client-xvqmq 1/1 Running 0 3m
dragonfly-scheduler-0 1/1 Running 0 3m
dragonfly-seed-client-0 1/1 Running 0 3m

Create Dragonfly cluster B

Create Dragonfly cluster B based on helm charts

Create Dragonfly cluster B charts configuration file charts-config-cluster-b.yaml, configuration content is as follows:

scheduler:
nodeSelector:
cluster: b
image:
repository: dragonflyoss/scheduler
tag: latest
metrics:
enable: true

seedClient:
nodeSelector:
cluster: b
image:
repository: dragonflyoss/client
tag: latest
metrics:
enable: true

client:
nodeSelector:
cluster: b
image:
repository: dragonflyoss/client
tag: latest
metrics:
enable: true
dfinit:
enable: true
image:
repository: dragonflyoss/dfinit
tag: latest
config:
containerRuntime:
containerd:
configPath: /etc/containerd/config.toml
proxyAllRegistries: true

Create Dragonfly cluster B using the configuration file:

$ helm install --wait --create-namespace --namespace cluster-b dragonfly dragonfly/dragonfly -f charts-config-cluster-b.yaml
NAME: dragonfly
LAST DEPLOYED: Mon Jul 27 21:26:00 2026
NAMESPACE: cluster-b
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
1. Dragonfly is running without the manager. The scheduler and client load the dynamic
configuration from the local dynconfig.yaml file mounted as a ConfigMap, and clients
discover schedulers via the scheduler headless service:
dragonfly-scheduler.cluster-b.svc.cluster.local:8002

2. Get the scheduler address by running these commands:
export SCHEDULER_POD_NAME=$(kubectl get pods --namespace cluster-b -l "app=dragonfly,release=dragonfly,component=scheduler" -o jsonpath={.items[0].metadata.name})
export SCHEDULER_CONTAINER_PORT=$(kubectl get pod --namespace cluster-b $SCHEDULER_POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
kubectl --namespace cluster-b port-forward $SCHEDULER_POD_NAME 8002:$SCHEDULER_CONTAINER_PORT
echo "Visit http://127.0.0.1:8002 to use your scheduler"

3. Configure runtime to use dragonfly:
https://d7y.io/docs/getting-started/quick-start/kubernetes/

Check that Dragonfly cluster B is deployed successfully:

$ kubectl get po -n cluster-b
NAME READY STATUS RESTARTS AGE
dragonfly-client-f4897 1/1 Running 0 3m
dragonfly-client-m9k9f 1/1 Running 0 3m
dragonfly-scheduler-0 1/1 Running 0 3m
dragonfly-seed-client-0 1/1 Running 0 3m

Using Dragonfly to distribute images for multi-cluster kubernetes

Containerd pull image back-to-source for the first time through Dragonfly in cluster A

Pull alpine:3.19 image in kind-worker node:

time docker exec -i kind-worker /usr/local/bin/crictl pull alpine:3.19

When pull image back-to-source for the first time through Dragonfly, peer uses cluster-a's scheduler and seed peer. It takes 31.714s to download the alpine:3.19 image.

Containerd pull image hits the cache of remote peer in cluster A

Delete the client whose Node is kind-worker to clear the cache of Dragonfly local Peer.

# Find pod name.
export POD_NAME=$(kubectl get pods --namespace cluster-a -l "app=dragonfly,release=dragonfly,component=client" -o=jsonpath='{.items[?(@.spec.nodeName=="kind-worker")].metadata.name}' | head -n 1 )

# Delete pod.
kubectl delete pod ${POD_NAME} -n cluster-a

Delete alpine:3.19 image in kind-worker node:

docker exec -i kind-worker /usr/local/bin/crictl rmi alpine:3.19

Pull alpine:3.19 image in kind-worker node:

time docker exec -i kind-worker /usr/local/bin/crictl pull alpine:3.19

When pull image hits cache of remote peer, peer uses cluster-a's scheduler and seed peer. It takes 7.304s to download the alpine:3.19 image.

Containerd pull image back-to-source for the first time through dragonfly in cluster B

Pull alpine:3.19 image in kind-worker3 node:

time docker exec -i kind-worker3 /usr/local/bin/crictl pull alpine:3.19

When pull image back-to-source for the first time through Dragonfly, peer uses cluster-b's scheduler and seed peer. It takes 36.208s to download the alpine:3.19 image.

Containerd pull image hits the cache of remote peer in cluster B

Delete the client whose Node is kind-worker3 to clear the cache of Dragonfly local Peer.

# Find pod name.
export POD_NAME=$(kubectl get pods --namespace cluster-b -l "app=dragonfly,release=dragonfly,component=client" -o=jsonpath='{.items[?(@.spec.nodeName=="kind-worker3")].metadata.name}' | head -n 1 )

# Delete pod.
kubectl delete pod ${POD_NAME} -n cluster-b

Delete alpine:3.19 image in kind-worker3 node:

docker exec -i kind-worker3 /usr/local/bin/crictl rmi alpine:3.19

Pull alpine:3.19 image in kind-worker3 node:

time docker exec -i kind-worker3 /usr/local/bin/crictl pull alpine:3.19

When pull image hits cache of remote peer, peer uses cluster-b's scheduler and seed peer. It takes 6.963s to download the alpine:3.19 image.