ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

BuildKit 构建 Nydus 按需拉取加速镜像:从 buildkitd 编译到镜像导出全指南

BuildKit 构建 Nydus 按需拉取加速镜像:从 buildkitd 编译到镜像导出全指南 BuildKit 构建 Nydus 按需拉取加速镜像从 buildkitd 编译到镜像导出全指南【免费下载链接】buildkitconcurrent, cache-efficient, and Dockerfile-agnostic builder toolkit项目地址: https://gitcode.com/GitHub_Trending/bu/buildkitNydus 是一种由 Dragonfly 社区 image-service 项目提出的、兼容 OCI/Docker 规范的容器镜像加速格式其核心价值是让容器运行时按需拉取镜像数据不必等整个镜像下载完成即可启动容器。本文以 BuildKit 当前仓库为蓝本完整讲解如何编译带 Nydus 支持的buildkitd、通过buildctl导出 Nydus 镜像并从源码层面剖析导出链路中额外 metadata 层的产生机制与各项已知限制最终交付一套可直接落地的 Nydus 镜像构建实战方案。一、Nydus 镜像格式为什么需要按需拉取1.1 传统镜像拉取方式的痛点在使用普通 OCI 镜像时容器运行时的启动流程通常是先拉取全部镜像层并解压到本地然后才挂载文件系统、启动容器。当镜像体积大、网络带宽有限时镜像拉取和解压会显著拉长容器冷启动时间同时占用大量磁盘 IO 与临时磁盘空间。1.2 Nydus 的解决思路blob bootstrap 分层Nydus 将镜像内容拆分为两类数据参见 cache/compression_nydus.go 中MergeNydus的注释与实现数据层nydus blob镜像的真实文件内容按 chunk 切分后存放拉取时可做到用到哪块拉哪块即按需拉取on-demand pull。元数据层nydus bootstrap描述整个文件系统视图的元数据目录结构、文件属性、chunk 索引等体积很小。容器启动时只需要先拿到体积小巧的 bootstrap 元数据即可建立文件系统视图实际文件数据在访问时才按需从远端拉取因此无需等待完整镜像下载完成就能启动容器。按 docs/nydus.md 的描述Nydus 已投入生产使用并在拉取镜像、启动容器的时间、网络与磁盘 IO 开销上带来了显著改善。1.3 运行时形态FUSE 用户态文件系统与内核 EROFSNydus 镜像可以灵活地以两种形态被消费FUSE 用户态文件系统通过用户态的 nydus daemon 提供文件系统能力部署灵活、不依赖内核版本。内核 EROFSEnhanced Read-Only File System从 Linux 内核 v5.16 起Nydus 可以直接以内核 EROFS 文件系统形态挂载用户态只需运行 nydus daemon 配合。由于 EROFS 是只读压缩文件系统且具备内核对文件系统的直接支持性能开销更低。由于 nydus daemon 运行在用户态与 KataContainers 这类基于 VM 的容器运行时集成也变得更加容易可以把 nydus daemon 一同放进 guest 虚拟机中实现在 VM 场景下的按需拉取。二、环境准备编译带 Nydus 支持的 buildkitd2.1 build tag 机制Nydus 是编译期特性BuildKit 通过 Go 的构建标签build tag将 Nydus 支持作为编译期可选特性注入。这一点在源码中非常清晰util/compression/nydus.go 以//go:build nydus开头定义了完整的nydusType压缩类型实现Compress、Decompress、NeedsConversion、OnlySupportOCITypes、MediaType等。util/compression/parse.go 则以//go:build !nydus开头是未开启该特性时的空实现。也就是说不携带nydustag 编译出的buildkitd根本不包含 Nydus 压缩类型导出时会直接走默认压缩逻辑。2.2 编译命令在 BuildKit 仓库根目录执行参考 docs/nydus.mdgo build -tagsnydus -o ./bin/buildkitd ./cmd/buildkitd编译完成后./bin/buildkitd即为带 Nydus 导出能力的守护进程。除buildkitd外其它导出路径如 exporter/containerimage/patch_nydus.go、cache/compression_nydus.go、util/winlayers/apply_nydus.go也均由nydustag 控制与默认的非 Nydus 版本如 exporter/containerimage/patch.go形成一一对应。2.3 准备 nydus-image 工具导出 Nydus 镜像时buildkitd 需要调用外部二进制nydus-image来完成数据打包因此必须预先准备从 Nydus 官方 release 页面下载nydus-image二进制要求版本 v2.1.6 及以上将nydus-image放入$PATH或通过NYDUS_BUILDER环境变量显式指定其路径env NYDUS_BUILDER/path/to/nydus-image buildkitd ...在 vendor 依赖 nydus-snapshotter 的 converter 实现中可以看到对应环境变量常量envNydusBuilder与envNydusWorkDir位于 vendor 下 nydus-snapshotter 的pkg/converter/convert_unix.goBuildKit 直接复用该套环境变量约定。另外还存在NYDUS_DISABLE_TAR2RAFS环境变量可用于控制是否禁用 tar 到 rafs 的转换路径。2.4 临时工作目录NYDUS_WORKDIR构建过程中Nydus 转换会产生一些中间文件。默认情况下这些中间文件创建在当前工作目录构建结束后会自动清理。如需改变中间文件存放位置通过NYDUS_WORKDIR环境变量指定即可env NYDUS_WORKDIR/var/tmp/nydus-build buildkitd ...在 CI 或容器化部署 buildkitd 时将NYDUS_WORKDIR指向有足够磁盘空间、且可写的独立目录是更稳妥的做法。三、使用 buildctl 导出 Nydus 镜像3.1 完整导出命令在 buildctl 一侧Nydus 被作为镜像导出时的一种压缩类型compression type来指定。将compressionnydus与force-compressiontrue组合即可把构建产物导出为 Nydus 镜像buildctl build ... \ --output typeimage,namedocker.io/username/image,pushtrue,compressionnydus,force-compressiontrue,oci-mediatypestrue3.2 关键导出参数逐个拆解参数取值作用typeimage固定使用镜像导出器image exporter产物为符合 OCI 规范的镜像并推送到 registrynamedocker.io/username/image目标镜像名含 tag将推送到该地址pushtrue布尔导出完成后直接推送到 registrycompressionnydus压缩类型指定导出层的压缩/格式为 NydusBuildKit 将调用nydus-image生成 nydus blob 层并追加 bootstrap 层force-compressiontrue布尔强制所有层统一使用指定压缩类型禁止混合其它压缩类型详见下文限制章节oci-mediatypestrue布尔使用 OCI media types而非 Docker media types是 Nydus 这种非 Docker 原生格式正常工作的前提3.3 参数在源码中的落地compressionnydus的解析入口在 util/compression/nydus.go 的Parse/FromMediaType函数当内置的常规压缩类型解析失败、而目标字符串恰好是nydus或 media type 是MediaTypeNydusBlob时返回compression.Nydus类型。该类型的关键行为包括Compress调用nydusify.Pack将层内容打包为 nydus blob并为层写入containerd.io/uncompressed标签与LayerAnnotationNydusBlob注解用于标识该层是 nydus blob 层util/compression/nydus.goDecompress调用nydusify.Unpack将 nydus blob 还原为普通层内容OnlySupportOCITypes返回true说明 Nydus 层只支持 OCI media types这正对应导出时要求开启oci-mediatypestrueNeedsComputeDiffBySelf返回true表示该压缩类型需要由自身完成 diff 计算。四、Nydus 导出流程的源码级原理4.1 导出主流程patchImageLayers镜像导出器在组装 manifest 时会调用patchImageLayers调用点在 exporter/containerimage/writer.go。该函数存在两个版本默认版本 exporter/containerimage/patch.go仅做层与 history 的规范化normalizeLayersAndHistory不额外追加任何层Nydus 版本 exporter/containerimage/patch_nydus.go当压缩类型是compression.Nydus时先调用cache.MergeNydus生成最终的 bootstrap 描述符并将其追加到 manifest 的层描述符末尾然后再做层与 history 的规范化。4.2 多一层的来源MergeNydus 的两步合并为什么 Nydus 镜像总是比其它压缩类型的镜像多一层答案就在 cache/compression_nydus.go 的MergeNydus中提取 bootstrap对每一层从其 nydus 格式内容nydus blob nydus bootstrap中取出对应的 bootstrap 元数据合并 bootstrap将各层 bootstrap 合并成一个最终的 bootstrap代表整个镜像文件系统视图的完整元数据并以 tar.gz 形式写回 content store作为镜像的额外一层追加到 manifest。由于 bootstrap 体积非常小合并操作很快源码注释明确指出 The nydus bootstrap size is very small, so the merge operation is fast。合并产物层的描述符带LabelUncompressed与LayerAnnotationNydusBootstrap注解用于标识它是 nydus bootstrap 层。这正是 docs/nydus.md 中导出的 Nydus 镜像总是比其它压缩类型多一个 metadata 层这一说法的实现来源。4.3 集成测试验证三层 manifest 结构仓库内置的 Nydus 集成测试 client/client_nydus_test.go//go:build nydus以 alpine 为基础镜像执行touch操作后导出断言 manifest 恰好包含 3 层第 1、2 层携带LayerAnnotationNydusBlob注解的 nydus blob 层第 3 层携带LayerAnnotationNydusBootstrap注解的 nydus bootstrap 层。测试还以compression.Gzip、compression.Zstd分别导出同样内容做对照验证普通镜像为 2 层且同一镜像内不会出现 Nydus 层与 gzip/zstd 层混合的情况。这条测试同时覆盖了强制统一压缩类型的约束与文档中的限制说明一一对应。五、已知限制与注意事项根据 docs/nydus.md 的 Known limitations 章节使用 BuildKit 导出 Nydus 镜像时需注意以下四点仅支持 Linux 平台Nydus 镜像的导出以及运行时如 docker-nydus-graphdriver、containerd nydus-snapshotter 等目前只在 Linux 上受支持。Windows 平台虽有针对 nydus blob 的应用逻辑util/winlayers/apply_nydus.go但其定位是处理已有 nydus 层而非导出。不得混用压缩类型同一镜像内的层不能被混合为不同压缩类型因此同时导出 Nydus 与其它压缩类型时必须开启force-compressiontrue强制全镜像统一压缩格式。基础镜像支持但不支持懒加载Dockerfile 中可以将 Nydus 镜像作为基础镜像base image使用但目前不支持对基础镜像的懒拉取lazy pulling。不能作为缓存导出/导入由于导出的 Nydus 镜像总是比其它类型镜像多一个 metadatabootstrap层与缓存cache的导出/导入结构不兼容因此 Nydus 镜像不能作为 BuildKit 缓存导出或导入。六、其它创建 Nydus 镜像的方式除 BuildKit 直接导出外还有两类常用途径参见 docs/nydus.md预转换镜像Dragonfly 社区在ghcr.io/dragonflyoss/image-service仓库提供了一批预先转换好的 Nydus 镜像主要用于测试验证 Nydus 运行时与按需拉取能力。Nydusify CLINydus 官方提供的命令行工具负责拉取一个 OCIv1 镜像、转换为 Nydus 镜像并推送回 registry适合对存量镜像做离线批量转换。Harbor AcceldHarbor 提供的通用加速服务能够把 OCIv1 镜像统一转换为 Nydus、eStargz 等多种加速镜像格式适合在 Harbor 镜像仓库侧做集中式转换。这些方式与 BuildKit 直接导出形成互补需要从 Dockerfile 构建新镜像时用 BuildKit需要转换已有镜像时用 Nydusify 或 Harbor Acceld。七、总结与最佳实践围绕 BuildKit 使用 Nydus 加速镜像的完整链路可以归纳为编译go build -tagsnydus -o ./bin/buildkitd ./cmd/buildkitd确保nydus构建标签生效准备工具下载 v2.1.6 及以上版本的nydus-image放入$PATH或通过NYDUS_BUILDER指定必要时用NYDUS_WORKDIR隔离中间文件导出buildctl 输出参数固定搭配compressionnydus,force-compressiontrue,oci-mediatypestrue容器运行时侧配合 nydus daemonFUSE 或内核 EROFSLinux v5.16即可享受按需拉取带来的启动提速与网络/磁盘 IO 节省。实践中最容易踩坑的三点忘记携带nydus编译标签导致导出类型不识别、force-compression未开启导致层类型混用、以及在非 Linux 平台尝试导出。理解了 util/compression/nydus.go、cache/compression_nydus.go 背后的 blob/bootststrap 拆分与合并机制后这些问题都能一眼定位。【免费下载链接】buildkitconcurrent, cache-efficient, and Dockerfile-agnostic builder toolkit项目地址: https://gitcode.com/GitHub_Trending/bu/buildkit创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表