我的 Homelab2 repo 之前是遵循上游 repo,使用 nix。但是有2点很别扭:
这次改动的目标只有一个:把 Nix 从本地开发和 CI 两条链路里彻底拿掉,并且不留回潮的口子。
原来的 devShell 里装了 31 项工具,CI 侧依赖 nixos/nix 和 nixery.dev 的镜像。迁移完成后,这两个名字在仓库里出现一次都会被 scripts/check-no-nix 拦下来。
接下来介绍规划的工具分工。
Python 这一摊全部交给 uv:
.python-version 固定到 3.13uv.lock 一起入库# .python-version
3.13依赖分组用根 pyproject.toml 里的 PEP 735 dependency groups,一共四组:scripts、dev、ci、docs。很清楚,看名字就能知道用途。
非 Python 工具交给 mise,版本精确固定到补丁位(我的习惯,出于安全考量):
工具 | 固定版本 |
|---|---|
helm | 3.20.2 |
kubectl | 1.36.6 |
kustomize | 5.8.3 |
opentofu | 1.11.14 |
go | 1.26.10 |
shellcheck | 0.11.0 |
入口统一成一条命令:mise run setup
[tasks.setup]
description = "安装 mise 工具并同步 uv 依赖"
run = """
mise install --yes
uv sync --all-groups
"""为什么不全用 mise,或者全用 uv?
uv 对 Python 的解释器、venv、lock 是一体的,换成 mise 管 Python 反而要自己拼装。mise 反过来能管 helm、go、opentofu 这类二进制,uv 管不了。
📝 Notes:这条分工的边界是语言生态与通用二进制两条线,不是新工具与旧工具的分界。个人习惯,仅供参考。
CI 侧的做法是单镜像加宿主机构建(宿主机构建也是为了节省 CI 时间)。
镜像定义在 .woodpecker/ci/Dockerfile,基础镜像 debian:13-slim 按 digest 固定,不跟 tag 漂:
# .woodpecker/ci/Dockerfile
FROM debian:13-slim@sha256:<digest> # 按 digest 固定,不跟随 tag镜像里只装 pre-commit(用于静态检查) 与 helm-diff 需要的东西:helm、dyff(用于 helm chart 选然后 diff)、shellcheck、git、diffutils、Python 与 pre-commit。
go、opentofu、ansible、kubectl、kustomize、gotestsum、docker CLI 一个都不装。原因是:
构建由我在宿主机执行 scripts/build-ci-image,内部是:
docker buildx build --push --provenance=false同时推 latest 和 sha-<short> 两个 tag,并输出 digest。CI 侧只做 pull: true,不使用 Woodpecker secret,不使用 privileged 步骤。收益是:pipeline 里没有构建镜像的耗时,也没有把 registry 凭据塞进 CI 的必要。代价是镜像重建变成一个人工环节,后面会讲到。(我认为可接受)
第一版是全量镜像,3.57GB。(解压后的尺寸)
k8s agent 拉取直接超时,CI pipeline 失败:
backoff: maximum elapsed time exceeded (last error: container "wp-01m68s38mskt3yad4bz2yjvh0d" in pod "wp-01m68s38mskt3yad4bz2yjvh0d" is waiting to start: trying and failing to pull image)然后是一轮一轮砍:3.57GB → 2.36GB → 1.68GB → 842MB,四轮。
最后落地的 DISK USAGE 219MB,CONTENT SIZE 842MB 版本,体积只有首版的约 23%。
📝 Notes:镜像体积在这里不是审美问题。3.57GB 会直接把冷启动拉过超时线,这是 CI pipeline 的真实失败原因。
迁移前最近 5 次成功 PR pipeline 的耗时中位数是 1174s🤣🤣🤣(国内,没办法)。
刚开始镜像尺寸很大的时候:
Pipeline | 耗时 | 说明 |
|---|---|---|
#2702(PR #600) | 423s | 完整 pipeline |
#2704 | 569s | 完整 pipeline |
#2707 | 71s | 仅 pre-commit |
最终优化后:
这个收益基本可以归因到一件事:镜像里不再有 go、opentofu、kubectl、kustomize、docker CLI 这一堆用不上的东西,拉取时间大大减少。
一次性迁移和长期不退化是两码事。
仓库里加了 scripts/check-no-nix,两条扫描线:
git ls-files 扫文件名,命中 flake.nix、flake.lock、.envrc、run_nix_develop.sh 就报错git grep 扫内容,命中 Nix 命令、nixos/nix、nixery.dev、nixpkgs 就报错这个脚本同时挂在 pre-commit 本地 hook 上,本地提交时给反馈,CI 里做阻断。
CI 的 static-checks 现在只跑 SKIP=tofu_fmt 的其他 pre-commit,13 个 hook。要跑 tofu_fmt 就得装 opentofu,而且 terraform 几乎不会修改。
👍️ 好处:
mise run setup,版本精确到补丁位👎 代价:
迁移完成后,2026-10-31 做最终验收:本地 make filter=Tools(11 tests)、pre-commit(13 hooks)、mkdocs --strict、scripts/check-no-nix 全部通过。
这次迁移的总结如下:
感觉这篇文章可能对读者没啥参考价值(唯一有价值的点可能就是:鉴于国内网络,选择工具链首选尺寸小或国内可达的或国内有源的),可以当个乐子读~
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。