1. 基本介绍
Kraken (https://github.com/uber/kraken) 是一个由P2P(peer-to-peer)驱动的专注于提升扩展性和可靠性的docker镜像仓库。它被设计用来在混合云环境中进行docker镜像管理、复制和分发。通过可插拔式的后端支持,可以方便和已有的镜像仓库(如Harbor)协作(甚至可替代Harbor的核心功能:支持镜像拉取也支持镜像下载,将在下文介绍),作为镜像分发层来运行。
其可做到每天分发100w个镜像层,其中包含10w个超过1GB大小的块。峰值性能下,30s内可分发2w个100MB - 1G的镜像层。
2. 功能特点
- 高扩展性。Kraken镜像分开速度 > 主机下载速度的50%。而且,集群规模和镜像大小对下载速度没有明显影响。
- 每个集群至少可支持15k台主机
- 支持任意大镜像层。默认限制为20G,以获得最佳性能
- 高可用性。所有组件都不是单点部署
- 安全性。支持TLS上传验证和数据完整性保护
- 兼容多种后端存储。将数据放在可靠存储服务,如S3, GCS, ECR, HDFS等,同时接入其他存储非常容易
- 可实现跨集群镜像同步复制
- 依赖极少。依赖后端存储之外,只依赖DNS
3. 设计理念
Kraken的高级思想是让少量专用主机(调用镜像存储服务拉取镜像)将内容播种到运行在集群中每个主机上的Agent上(即一个deamonset服务)
一个中心组件,跟踪器(tracker,类似Zookeeper的组件),将协调网络中的所有参与者,形成一个伪随机规则图(各个Agent之前随机同步)
这样的图连通度高,直径小。结果是,就算只有一个播种者,一秒内加入了成千上万的端点(peer),所有参与者理论上可以达到至少80%的最大上传/下载速度(当前实现下可达到60%),性能在镜像size变大和集群规模变大时不受影响
4. 架构说明
4.1 核心流程图
- Agent
- 部署在每台Node上
- 实现docker镜像仓库接口(即可以接受docker pull请求)
- 向tracker申明自己拥有的内容
- 连接请求tracker后返回peer列表,用于下载内容
- Origin
- 专用播种机
- 将镜像层存储在可靠存储上 (e.g. S3, GCS, ECR)
- 形成一个自修复散列环来分配负载
- Tracker
- 记录哪些peer上有哪些内容 (包含下载中和下载完成的)
- 提供拉取某些镜像层对应的peer列表
- Proxy
- 实现docker镜像仓库接口(即可以接受docker push请求)
- 上传镜像层到origin,进而到后端存储
- 上传Tag到Build Index,进而到后端存储
- Build-Index
- 将 tag 映射到 digest,如 v1.0.0 → sha256:6a8b53655bcda24a2a44131e249f70eec0251d2b8e6d75c901ebe7d3f34c641d (存储镜像层的后端存储只认识Digest)
- 无一致性保证。镜像覆盖场景,如某个组件多次打镜像,一直用latest作为tag,因为ngnix缓存关系,Build-Index可能返回的不是最新的digest
- 支持多集群间镜像复制
- 将Tag存储在可靠存储上 (e.g. S3, GCS, ECR)
4.2 镜像拉取流程图
4.3 镜像复制流程图
5. 基准测试
3GB 镜像 每个镜像有两个镜像层 2600个节点同时下载(要进行5200次下载) 节点下载限速300MB/s (使用 5个trackers实例和 5个origins实例):
- p50 = 10s
- p99 = 18s
- p99.9 = 22s
结论:2600个镜像层,在10s内下载完成,几乎所有的镜像层,在22s内全部下载完成
6. 与其他项目对比
6.1 Gragonfly from Alibaba
Dragonfly集群有一个或几个“超级节点”(类似Kraken中tracker的角色),它们协调集群中每4MB数据块的传输。
虽然超级节点可能会做出最优选择,但整个集群的吞吐量由几个节点的性能决定,随着镜像层大小和集群规模的增长,镜像分发性能将线性降低
Kraken的tracker只负责协调各个端点形成一个随机连接图,让数据传输的细节由各个端点自行决定,所以面对大镜像层分发有更好的扩展性。此外,Kraken支持HA并支持跨集群的镜像复制,对混合云环境而言非常重要
6.2 BitTorrent
Kraken最初基于BitTorrent创建,最终因考虑与存储方案集成和方便做性能优化,实现了自己的P2P驱动
7. 使用限制
- Kraken对单次docker pull的速度并没有提升,只有在镜像分发吞吐量成了你的瓶颈时才能实现威力。如果想加速docker pull,可以用Makisu,实现在构建时镜像层更好的复用,或者调整镜像压缩比,因为拉取镜像时大部分时间都花在了解压缩上面
- Build-Index无一致性保证。镜像覆盖场景,如某个组件多次打镜像,一直用latest作为tag,因为ngnix缓存关系,Build-Index可能返回的不是最新的digest,作者正在优化这块的功能逻辑。当前可以通过减少缓存失效时间来部分解决
- 理论上,Kraken可分发任意大小的镜像层,而性能几乎不受影响。不过当前强制执行20G的限制,不能支持超大镜像层的使用。如果你有超大镜像层的需求,建议可以先把他们分割成小于10GB的层
8. 与Harbor集成
8.1 架构图
好处:
- 保留harbor这一层,有利于利用harbor的项目管理、镜像扫描等kraken不具备的能力,且如果kraken出现问题,也可切换到harbor正常拉取镜像
- 结合harbor-registry的通知机制,可同时实现镜像预热+P2P镜像分发,极大加快发布的速度
8.2 镜像预热
8.2.1 修改harbor-registry的配置文件,增加另一个通知项
notifications:
endpoints:
- name: harbor
disabled: false
url: http://harbor-harbor-core/service/notifications
timeout: 3000ms
threshold: 5
backoff: 1s
ignoredmediatypes:
- application/vnd.docker.image.rootfs.diff.tar.gzip
- application/vnd.docker.image.rootfs.foreign.diff.tar.gzip
- application/vnd.oci.image.layer.v1.tar
- application/vnd.oci.image.layer.v1.tar+gzip
- application/vnd.oci.image.layer.v1.tar+zstd
- application/vnd.oci.image.layer.nondistributable.v1.tar
- application/vnd.oci.image.layer.nondistributable.v1.tar+gzip
- application/vnd.oci.image.layer.nondistributable.v1.tar+zstd
- application/octet-stream
- name: kraken
disabled: false
url: http://kraken-proxy.kraken.svc.cluster.local:10050/registry/notifications
timeout: 3000ms
threshold: 5
backoff: 1s
8.2.2 修改kraken-origin、kraken-buildindex的配置文件,将harbor配置为存储服务
build_index:
replicas: 3
extraBackends: |-
- namespace: .*
backend:
registry_tag:
address: xxx
security:
basic:
username: admin
password: ***
origin:
replicas: 3
extraBackends: |-
- namespace: .*
backend:
registry_blob:
address: xxx
security:
basic:
username: admin
password: ***
9. 核心配置 (代码块里均为默认配置)
9.1 Peer之间上传下载带宽 (node节点之间)
scheduler:
conn:
bandwidth:
enable: true
egress_bits_per_sec: 1677721600 # 200*8 Mbit
ingress_bits_per_sec: 2516582400 # 300*8 Mbit
9.2 后端服务上传下载带宽 (与nos交互)
backends:
- namespace: .*
backend:
s3: <omitted>
bandwidth:
enabled: true
egress_bits_per_sec: 8589934592 # 8 Gbit
ingress_bits_per_sec: 85899345920 # 10*8 Gbit
9.3 磁盘缓存过期时间和缓存文件数量
store:
cache_cleanup:
tti: 6h
download_cleanup:
tti: 6h
origin 另外可限制缓存Blob数
store:
capacity: 1000000
9.4 内存缓存过期时间
agent / origin 配置
scheduler:
seeder_tti: 5m
9.5 origin / build-index 配置多后端
backends:
- namespace: library/.*
backend:
registry_blob:
address: index.docker.io
timeout: 60s
security:
basic:
username: ""
password: ""
- namespace: test-domain/.*
backend:
http:
download_url: http://test-domain:9000/download?sha256=%s
download_backoff:
enabled: true
- namespace: ecr-images/.*
backend:
registry_tag:
address: 123456789012.dkr.ecr.<region>.amazonaws.com
security:
credsStore: 'ecr-login'
- namespace: s3-images/.*
backend:
s3:
region: us-west-1
bucket: test-bucket
root_directory: /test-bucket/kraken/default/
name_path: sharded_docker_blob
username: kraken-user
- namespace: minio-images/.*
backend:
s3:
region: us-east-1
bucket: self-hosted-bucket
root_directory: /kraken/default/
name_path: sharded_docker_blob
username: minio-user
endpoint: http://172.17.0.1:9000
disable_ssl: true
force_path_style: true
bandwidth:
enable: true
- namespace: gcs-images/.*
backend:
gcs:
username: kraken-user
bucket: test-bucket
root_directory: /test-bucket/kraken/default/
name_path: sharded_docker_blob
bandwidth:
enable: true
auth:
s3:
kraken-user:
s3:
aws: kraken-user
aws_access_key_id: <keyid>
aws_secret_access_key: <key>
minio-user:
s3:
aws: minio-user
aws_access_key_id: <keyid>
aws_secret_access_key: <key>
gcs:
kraken-user:
gcs:
access_blob: <service_account_key>
9.6 torrent并发下载数
scheduler:
connstate:
max_open_conn: 10
10. 部署
10.1 通过Helm
# 添加 Helm repo
helm repo add iamyeka https://iamyeka.github.io/helm-charts
# 一键安装
helm install kraken -n kraken --create-namespace iamyeka/kraken
内置了 Grafana dashboard大盘,可导入使用,路径:https://github.com/iamyeka/helm-charts/tree/main/charts/kraken/dashboard
大盘的指标来源于二次开发添加的一些指标,具体修改见:https://github.com/iamyeka/kraken/tree/enhance-observability
生产实测,总体镜像平均拉取耗时下降 66.6%,最大拉取耗时下降 33.6%,加速效果较明显