从零掌握containerd镜像构建:nerdctl与buildkit实战指南

张开发
2026/4/11 11:42:58 15 分钟阅读

分享文章

从零掌握containerd镜像构建:nerdctl与buildkit实战指南
1. 为什么需要nerdctl和buildkit如果你最近在折腾Kubernetes可能会发现一个变化从1.24版本开始Kubernetes彻底移除了对Docker的直接支持。这意味着我们熟悉的docker build命令在Kubernetes环境下不再适用。这时候containerd作为默认容器运行时登上了舞台但它自带的ctr命令用起来实在不够友好最关键的是——它居然不支持构建镜像这就是nerdctl和buildkit这对黄金搭档出场的时候了。nerdctl就像是containerd世界的docker-cli让你可以用类似docker的语法管理容器和镜像而buildkit则是专门负责镜像构建的引擎。我在迁移Kubernetes集群时发现这对组合虽然初期学习曲线有点陡但用顺手后效率反而比docker更高。2. nerdctl的两种版本选择2.1 精简版轻量但有限制nerdctl的精简版只有10MB左右下载安装特别方便wget https://github.com/containerd/nerdctl/releases/download/v1.0.0/nerdctl-1.0.0-linux-amd64.tar.gz tar xf nerdctl-1.0.0-linux-amd64.tar.gz -C /usr/bin但要注意几个坑点如果遇到SSL证书错误记得加上--no-check-certificate参数精简版不支持nerdctl build命令会报错提示需要buildkit默认使用/run/containerd/containerd.sock如果你的路径不同需要用-a参数指定2.2 完整版功能全面但体积大完整版约220MB包含了buildkitd、buildctl等全套工具。我建议如果你需要构建镜像直接上完整版更省心。安装后有几个关键点需要注意buildkit.service文件默认路径是/usr/local/bin/buildkitd你可能需要调整完整版自带CNI插件这对网络配置很重要包含了runc和ctr等工具调试时更方便3. 配置buildkit服务3.1 两种worker模式选择buildkit支持两种workeroci-worker默认使用runccontainerd-worker直接集成containerd如果你想要更好的性能建议使用containerd-workerbuildkitd \ --oci-workerfalse \ --containerd-workertrue \ --containerd-worker-addr/run/containerd/containerd.sock这里有个小技巧使用containerd-worker时buildkit会自动创建buildkit这个namespace可以通过nerdctl namespace ls查看。3.2 服务管理完整版自带了systemd服务文件cp lib/systemd/system/buildkit.service /lib/systemd/system/ systemctl enable --now buildkit.service我遇到过服务启动失败的情况大多是路径配置问题。建议先用journalctl -u buildkit -f查看日志排错。4. 镜像构建实战4.1 使用nerdctl构建这是最接近docker体验的方式。先准备一个简单的DockerfileFROM alpine:3.16.3 ENV LANGen_US.UTF-8 TZAsia/Shanghai RUN echo /bin/sleep 315360000 start.sh CMD [sh,start.sh]构建命令nerdctl build -t alpine:3.16.3-test .注意namespace问题如果想将镜像放到buildkit namespace下需要显式指定nerdctl -n buildkit build -t alpine:3.16.3-test .4.2 使用buildctl构建虽然更底层但灵活性更高buildctl build \ --frontend dockerfile.v0 \ --local context. \ --local dockerfile. \ --output typeimage,namealpine:3.16.3-buildctl参数说明--frontend支持dockerfile.v0和gateway.v0--local context构建上下文路径--local dockerfileDockerfile路径--output指定输出为镜像5. 常见问题解决5.1 CNI路径问题我在实际使用中发现nerdctl默认会去/opt/cni/bin找CNI插件。如果你的CNI安装在其他位置有两种解决方案创建aliasalias nerdctlnerdctl --cni-path /your/cni/path/修改配置文件mkdir -p /etc/nerdctl echo cni_path /your/cni/path /etc/nerdctl/nerdctl.toml5.2 namespace管理containerd的namespace概念容易让人困惑。记住几个要点Kubernetes使用的默认namespace是k8s.iobuildkit自动创建的namespace是buildkit查看镜像时要指定namespacectr -n k8s.io image ls nerdctl -n buildkit image ls5.3 镜像拉取问题从Docker Hub拉取镜像时记得指定k8s.io namespacenerdctl -n k8s.io pull nginx:alpine否则Kubernetes会找不到这个镜像。这是我踩过的一个大坑当时花了半天才找到原因。6. 性能优化技巧经过多次测试我发现这些配置可以显著提升构建速度为buildkit配置缓存buildctl prune --all buildctl build --frontend dockerfile.v0 --local context. --local dockerfile. --output typeimage,nametest-image --export-cache typeinline --import-cache typeregistry,refyour-registry/cache-image使用更快的storage driver 在/etc/containerd/config.toml中配置[plugins.io.containerd.grpc.v1.cri.containerd] snapshotter stargz并行构建buildctl build --opt build-arg:BUILDKIT_INLINE_CACHE1 --export-cache typeinline --import-cache typeregistry,refyour-registry/cache-image迁移到containerd生态确实需要适应期但一旦掌握nerdctl和buildkit的组合你会发现它们在Kubernetes环境下的表现比Docker更加稳定高效。特别是在CI/CD流水线中buildkit的缓存机制能大幅缩短构建时间。刚开始可能会被namespace和CNI路径这些小问题困扰但只要理解了containerd的设计哲学这些都会变得顺理成章。

更多文章