dragonfly集成harbor

介绍

Dragonfly 是一款基于 P2P 的智能镜像和文件分发工具。它旨在提高大规模文件传输的效率和速率,最大限度地利用网络带宽。在应用分发、缓存分发、日志分发和镜像分发等领域被大规模使用。

官方文档地址:https://d7y.io/zh/docs/
github地址:https://github.com/dragonflyoss/Dragonfly2

架构

file

Manager

1、存储动态配置供 Seed Peer 集群、Scheduler 集群以及 Dfdaemon 消费。
2、维护 Seed Peer 集群和 Scheduler 集群之间关联关系。
3、提供统一异步任务管理,用作预热等功能。
4、监听各模块是否健康运行。
5、为 Dfdaemon 筛选最优 Scheduler 集群调度使用。
6、提供可视化控制台,方便用户操作管理 P2P 集群。

Scheduler

1、基于机器学习的多场景自适应智能 P2P 节点调度, 为当前下载节点选择最优父节点。
2、构建 P2P 下载网络的有向无环图。
3、根据不同特征值评估节点下载能力, 剔除异常节点。
4、当下载失败情况,主动通知 Dfdaemon 进行回源下载。

Dfdaemon

1、基于 gRPC 提供下载功能, 并提供多源适配能力。
2、开启 Seed Peer 模式可以作为 P2P 集群中回源下载节点, 也就是整个集群中下载的根节点。
3、为镜像仓库或者其他 HTTP 下载任务提供代理服务。
4、下载任务基于 HTTP 或 HTTPS 或其他自定义协议。

环境

  • k8s版本:1.24.16
  • containerd版本:1.6.9
  • harbor版本:v2.8.2,开启了https,参考这里
  • dragonfly版本:v2.1.0

file

部署

添加helm repo

我是部署在k8s集群内的,所以这里使用helm chart来部署。

helm repo add dragonfly https://dragonflyoss.github.io/helm-charts/
helm repo list
helm install --wait --create-namespace --namespace dragonfly-system dragonfly dragonfly/dragonfly -f charts-config.yaml

file

我的机器拉github超时。所以去github上下载压缩包。

helm pull dragonfly/dragonfly
wget https://github.com/dragonflyoss/helm-charts/releases/download/dragonfly-1.1.3/dragonfly-1.1.3.tgz
tar xvf dragonfly-1.1.3.tgz

修改values.yaml

containerRuntime:
  containerd:
    enable: true

scheduler:
  replicas: 1
  metrics:
    enable: true
  config:
    verbose: true
    pprofPort: 18066

seedPeer:
  replicas: 1
  metrics:
    enable: true
  config:
    verbose: true
    pprofPort: 18066

dfdaemon:
  metrics:
    enable: true
  config:
    verbose: true
    pprofPort: 18066

manager:
  replicas: 1
  metrics:
    enable: true
  config:
    verbose: true
    pprofPort: 18066

jaeger:
  enable: true

部署

helm install --create-namespace --namespace dragonfly-system dragonfly .

file

这里mysql和redis会卡在pending状态,因为pvc没有配置storageCLass。导出pvc-yaml后删除pvc,添加storageCLassName,再apply即可。下面是mysql的pvc-yaml。

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  labels:
    app.kubernetes.io/component: primary
    app.kubernetes.io/instance: dragonfly
    app.kubernetes.io/name: mysql
  name: data-dragonfly-mysql-0
  namespace: dragonfly-system
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 8Gi
  volumeMode: Filesystem
  storageClassName: fast

file

k delete pvc data-dragonfly-mysql-0 redis-data-dragonfly-redis-master-0 redis-data-dragonfly-redis-replicas-0 -n dragonfly-system

redis-replicas会有3副本,所以redis-data-dragonfly-redis-replicas-1,redis-data-dragonfly-redis-replicas-2也得删除重建。

values.yaml中的global选项中没有配置storageCLassName的地方,mysql和redis的配置中也没有,所以只能这样删除重建了。

查看服务情况

k get po,pvc -n dragonfly-system

file

dragonfly-jaeger-query是headless服务,这里再创建一个nodePort服务。

cat svc.yaml
apiVersion: v1
kind: Service
metadata:
  annotations:
    meta.helm.sh/release-name: dragonfly
    meta.helm.sh/release-namespace: dragonfly-system
  labels:
    app.kubernetes.io/component: service-query
    app.kubernetes.io/instance: dragonfly
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: jaeger
    app.kubernetes.io/version: 1.39.0
    helm.sh/chart: jaeger-0.66.1
  name: dragonfly-jaeger-query-nodeport
  namespace: dragonfly-system
spec:
  ports:
  - name: http-query
    port: 16686
    protocol: TCP
    targetPort: 16686
    nodePort: 30686
  - name: grpc-query
    port: 16685
    protocol: TCP
    targetPort: 16685
    nodePort: 30685
  selector:
    app.kubernetes.io/component: all-in-one
    app.kubernetes.io/instance: dragonfly
    app.kubernetes.io/name: jaeger
  sessionAffinity: None
  type: NodePort

k get svc -n dragonfly-system

file

启用containerd的Mirror模式

配置dfdaemon

修改values.yaml

file

helm upgrade dragonfly -n dragonfly-system .

file

配置containerd

前面helm安装dragonfly时配置了containerd,只启用了enable: true。如果添加了injectConfigPath: true的配置,就意味着允许Charts注入config_path并重新启动 containerd。此选项启用多个镜像仓库支持。我这里只加速一个镜像仓库,故不启用此选项。下图是启用该选项的chart配置:

file

修改config.toml

添加配置文件路径:config_path = "/etc/containerd/certs.d",下面不能有其他配置,否则containerd会无法正常启动。状态是正常的,但是会无法执行crictl ps

file

containerd配置参考:https://github.com/containerd/containerd/blob/main/docs/cri/config.md#registry-configuration

file

# 创建certs.d目录
mkdir /etc/containerd/certs.d
# 拷贝config.toml文件
ansible all -m copy -a "src=/etc/containerd/config.toml dest=/etc/containerd/"

生成hosts.toml

可以手动生成也可以自动生成。路径: /etc/containerd/certs.d/example.com/hosts.toml。自动生成 hosts.toml 脚本为 https://github.com/dragonflyoss/Dragonfly2/blob/main/hack/gen-containerd-hosts.sh

bash gen-containerd-hosts.sh harbor.harbor.com

下面是手动生成的配置文件示例。

server = "https://harbor.harbor.com"

[host."http://127.0.0.1:65001"]
  capabilities = ["pull", "resolve"]
  [host."http://127.0.0.1:65001".header]
    X-Dragonfly-Registry = ["https://harbor.harbor.com"]
  [host."https://harbor.harbor.com"]
    capabilities = ["pull", "resolve"]

file

重启containerd

systemctl daemon-reload
systemctl restart containerd

containerd对接harbor

添加harbor域名解析

首先添加主机hosts解析。

ansible all -m shell -a "echo '192.168.1.1 `harbor.harbor.com`' >> /etc/hosts"

尝试拉取镜像:

crictl pull harbor.harbor.com/xxx/nginx:1.24.0

会报错500:

file

这是因为dragonfly的pod内无法解析harbor.harbor.com,需要手动添加hosts解析。

修改dragonfly-dfdaemon(ds),dragonfly-manager(deployment),dragonfly-scheduler(sts),dragonfly-seed-peer(sts)的yaml文件,添加harbor域名解析。

k edit ds dragonfly-dfdaemon -n dragonfly-system -o yaml

hostAliases:
- hostnames:
  - harbor.harbor.com
  ip: 192.168.1.1

添加证书

等待pod重启完成后,再次尝试拉取镜像,报错x509:certificate signed by unknown authority

这个是因为harbor启用了https,containerd认证失败了。如果是http就没这个问题了。拷贝harbor的证书目录到/etc/containerd/certs.d/harbor.harbor.com目录。
修改hosts.toml,手动添加证书文件如下:

server = "https://harbor.harbor.com"

[host."http://127.0.0.1:65001"]
  capabilities = ["pull", "resolve"]
  [host."http://127.0.0.1:65001".header]
    X-Dragonfly-Registry = ["https://harbor.harbor.com"]
  [host."https://harbor.harbor.com"]
    capabilities = ["pull", "push", "resolve"]
    ca = "/etc/containerd/certs.d/harbor.harbor.com/ca.crt"
    client = ["/etc/containerd/certs.d/harbor.harbor.com/harbor.harbor.com.cert", "/etc/containerd/certs.d/harbor.harbor.com/harbor.harbor.com.key"]

重启containerd,再次拉取报错:found a certificate rather than a key in the PEM for the private key,我没找到正确添加证书认证的方法。所以采用了跳过证书认证的方法…

server = "https://harbor.harbor.com"

[host."http://127.0.0.1:65001"]
  capabilities = ["pull", "resolve"]
  [host."http://127.0.0.1:65001".header]
    X-Dragonfly-Registry = ["https://harbor.harbor.com"]
  [host."https://harbor.harbor.com"]
    capabilities = ["pull", "resolve"]
    skip_verify = true

重启containerd后,可以登录harbor了。忽略这个登录时的报错,截图时还没重启dragonfly的pod。重启后就不会报错了。

file

但是仍然无法拉取。还是报错x509。

添加ca证书信任

cat /etc/containerd/certs.d/harbor.harbor.com/ca.crt
# 把ca证书添加到本地信任
cat ca.crt >> /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem

再次尝试拉取,拉取成功。

file

验证dragonfly

containerd通过dragonfly首次回源拉镜像

前面已经加了jaeger的的nodePort,访问jaeger的ui。
比如镜像为harbor.harbor.com/xxx/redis:5.0.6,tag的格式为:http.url="/v2/xxx/redis/blobs/sha256:e1285fcc6a46ea12a10f75a49278f3c82937cc174e5cdf052ef5e31bdaf93509?ns=harbor.harbor.com",sha256那串为镜像的某一层。

file

Tracing详细内容:

file

集群内首次回源时,下载 e1285fcc6a46ea12a10f75a49278f3c82937cc174e5cdf052ef5e31bdaf93509 层需要消耗时间为 215.86ms。

containerd下载镜像命中dragonfly本地peer的缓存

删除下载的redis镜像,在该节点上再次下载redis镜像。

nerdctl rmi harbor.harbor.com/xxx/redis:5.0.6
nerdctl images

jaeger上搜索上面的tag。

file

命中本地peer缓存时,下载 e1285fcc6a46ea12a10f75a49278f3c82937cc174e5cdf052ef5e31bdaf93509 层需要消耗时间为 409us。

containerd下载镜像命中dragonfly远程peer的缓存

在其他节点上下载redis镜像。jaeger上搜索上面的tag。

file

Tracing详细内容:

file

命中远程peer缓存时,下载 e1285fcc6a46ea12a10f75a49278f3c82937cc174e5cdf052ef5e31bdaf93509 层需要消耗时间为 74.31ms。

综上,可以看出dragonfly可以一定程度上提升镜像拉取的速度。由于我这里只启用了一个manager,scheduler,peer节点,所以看着不是太明显,增加pod数量可以提升下载速度。

登录控制台

修改manager的svc为nodePort。

k edit svc dragonfly-manager -n dragonfly-system

file

访问 http://ip:30088

file

默认账号为 root, 密码为 dragonfly。可以注册账号。

查看集群信息。

file

file

查看调度信息。

file

查看peer信息。

file

预热

预热功能在对接有公网域名的harbor时非常有用,因为一般公网域名的harbor都配置了CDN,而预热功能会把镜像缓存在CDN。这样再次拉取的时候CDN直接返回,就不用再去源镜像仓库拉取了。我这里harbor是离线的,所以预热功能开不开都没区别。这里介绍一下如何配置:

首先containerd得是Mirror模式。上文中已经配置。下面就是配置harbor。
harbor官方文档地址:https://goharbor.io/docs/2.8.0/administration/p2p-preheat/manage-preheat-providers/

登录harbor,点击分布式分发,创建实例。

注意:这里的endpoint为dragonfly-manager的地址。我按照官方文档的8002地址,以为是dragonfly-scheduler,一直调不通…

预热镜像

执行命令:

curl --location --request POST 'http://192.168.1.1:30088/api/v1/jobs' \
--header 'Content-Type: application/json' \
--data '{
    "type": "preheat",
    "args": {
        "type": "image",
        "url": "https://harbor.harbor.com/xxx/jenkins/manifests/2.332.3"
    }
}'

这里不能按照官方文档的命令格式,会报错--data-raw is unknown,得改成--data

file

查看任务执行情况:

curl --request GET 'http://192.168.1.1:30088/api/v1/jobs/1'

如果返回预热任务状态为 SUCCESS,表示预热成功:

file

在两台node上都下载镜像。jaeger上搜索tag:http.url="/v2/xxx/jenkins/blobs/sha256:xxxxxxxx?ns=harbor.harbor.com

file

可以看到第一次下载层耗时2.08s,第二次耗时527.33ms。

查看tracing信息。

file

预热功能已实现。

和kraken的对比

kraken GitHub地址:https://github.com/uber/kraken

两者的主要差异是:

  • Dragonfly 集群有一个或几个“超级节点”,用于协调集群中每个 4MB 大小的数据块的传输。虽然超级节点能够做出最佳决策,但整个集群的吞吐量会受到一台或数台主机的处理能力限制,并且随着 blob 大小或集群大小的增加,整体性能会线性下降。
  • Kraken的架构中,中心部件Tracker只负责搭建起一个随机正则图的网络拓扑结构,但是具体的数据传输的协商是由每台机器上的peer进程负责,所以Kraken的性能不会太受集群和镜像大小的影响。此外,Kraken是一个高可用性的系统,并且支持跨集群异地无损复制,适合使用于混合云环境。

我的环境都是本地或者云上环境,没有混合云场景。所以具体内容没有测试。

0 0 投票数
文章评分
订阅评论
提醒
guest

0 评论
内联反馈
查看所有评论

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部
0
希望看到您的想法,请您发表评论x