Velero 开发指南:生成文件、单元测试与依赖管理实战
【免费下载链接】veleroBackup and migrate Kubernetes applications and their persistent volumes项目地址: https://gitcode.com/GitHub_Trending/ve/velero
Velero(VMware Tanzu Velero)是 Kubernetes 生态中用于备份、恢复与迁移集群应用及持久化卷的开源工具,其仓库同时托管着 CLI、server、插件 gRPC 接口与 CRD 定义等多类代码资产。本文基于 site/content/docs/v1.1.0/development.md 展开,系统梳理 Velero 开发工作流中"生成文件(Generated Files)— 单元测试 — 依赖管理"三条核心主线:何时必须重新生成代码、如何一键更新、如何用make verify校验产物一致性、如何跑通make test,以及如何正确增删改第三方依赖。读完本文,你将能快速上手 Velero 的本地开发闭环,并在提交 PR 前准确执行仓库约定的检查流程。
一、为什么 Velero 需要"生成文件"
Velero 是一个典型的 Kubernetes Go 项目,大量代码不是手写的,而是由工具从"单一事实来源"(source of truth)自动生成:
- clientset / listers / shared informers:由 Kubernetes 代码生成器(code-generator)根据
pkg/apis/velero/v1、pkg/apis/velero/v2alpha1等 API 类型定义生成,是访问 Velero 自定义资源(Backup、Restore、Schedule、BackupStorageLocation 等)的类型安全客户端; - 文档:CLI 命令帮助与站点文档中的一部分内容由源码生成;
- Protobuf / gRPC 类型:插件系统(
pkg/plugin/proto下的BackupItemAction.proto、RestoreItemAction.proto、ObjectStore.proto、VolumeSnapshotter.proto、PluginLister.proto、Shared.proto等)的消息与服务定义,通过 protoc 编译为pkg/plugin/generated下的 Go 代码。
因此,改动这些"事实来源"后,必须同步重新生成产物,否则客户端、文档与 gRPC 代码会与实际类型定义脱节。开发文档在 site/content/docs/v1.1.0/development.md 中明确给出了需要触发重新生成的三种情形。
二、何时需要运行make update
按开发文档约定,当你做出以下任意一类改动后,必须运行make update重新生成文件:
| 改动类型 | 示例 |
|---|---|
| 新增 / 修改 / 删除命令行 flag 及其帮助文本 | 为velero backup create增加一个新参数 |
| 新增 / 修改 / 删除命令或子命令 | 新增一个子命令或调整cmd/cli下的命令结构 |
| 新增 API 类型 | 在pkg/apis/velero/v1(或v2alpha1)中新增自定义资源类型及字段 |
make update内部到底做了什么
从仓库根目录 Makefile 看,update目标实际是在构建容器内执行 hack/update-all.sh:
update: ## Run all update scripts @$(MAKE) shell CMD="-c 'hack/update-all.sh'"而 hack/update-all.sh 会依次执行hack/下所有update-*.sh脚本,当前仓库包含:
- hack/update-1fmt.sh:对所有 Go 文件执行
gofmt -s,并用goimports -local github.com/vmware-tanzu/velero统一 import 分组; - hack/update-2proto.sh:调用 protoc,将
pkg/plugin/proto下的.proto定义编译到pkg/plugin/generated(含--go_out与--go-grpc_out两路输出); - hack/update-3generated-crd-code.sh:使用
controller-gen生成 v1、v2alpha1 两套 CRD 到config/crd/v1/bases、config/crd/v2alpha1/bases,并生成 RBAC(rbac:roleName=velero-perms); - hack/update-4generated-issue-template.sh:编译 hack/issue-template-gen/main.go 并生成 GitHub issue 模板。
其中 proto 脚本对工具链版本有明确要求:需要 protoc(Protocol Buffers 编译器)以及protoc-gen-go插件 v1.0.0。开发文档特别强调,只有当你"新增 / 修改 / 删除 protobuf 消息或服务定义"时,才需要走这条独立的 generate-proto.sh 流程(该脚本已被封装进update-*.sh链路)。
实用提示:仓库还提供了
make update-crd快捷目标,仅执行 hack/update-3generated-crd-code.sh,用于只改 CRD 时快速迭代(见 Makefile 中注释"for development purpose only")。
与当前源码结构的印证
从当前仓库结构看,生成产物的输入与输出清晰对应:
- 输入:API 类型定义位于 pkg/apis/velero(
v1/、v2alpha1/、shared/),插件 proto 定义位于 pkg/plugin/proto; - 输出:CRD 清单位于 config/crd(
v1/、v2alpha1/下的bases),生成代码位于 pkg/plugin/generated 等目录。
这些生成目录在 hack/update-1fmt.sh 中被显式排除(-not -path '*/generated/*' -not -name 'zz_generated*' -not -path '*/mocks/*'),说明格式化脚本只处理手写代码,生成代码保持工具输出原样,进一步印证了"生成物不得手改"的工程约定。
三、用make verify校验生成产物是否最新
如果担心本地改动后忘记重新生成,或者想检查一份补丁里生成文件是否与源码一致,开发文档给出的答案是:
make verifymake verify在构建容器内执行 hack/verify-all.sh,该脚本会运行hack/下所有verify-*.sh,当前仓库的核心校验包括:
- hack/verify-fmt.sh:以
--verify模式调用update-1fmt.sh,即gofmt -d与goimports -d做差异比对而非写入; - 对应的 CRD 一致性校验:通过重新生成后与仓库中现有产物 diff,确保 clientset、listers、shared informers、CRD 与文档全部处于最新状态。
一旦校验失败,脚本会提示Please run 'make update'(参见 hack/update-1fmt.sh 中的失败分支)。这也是 Velero CI 的守门环节之一——Makefile 中的ci目标依次执行verify-modules、verify、all、test,将生成物一致性检查放在测试之前。
四、运行单元测试:make test
开发文档给出的测试命令极其简洁:
make test但背后是一条完整、可复现的测试链路。从 Makefile 看:
test: build-dirs ## Run unit tests ifneq ($(SKIP_TESTS), 1) @$(MAKE) shell CMD="-c 'hack/test.sh $(WHAT)'" endif其中make shell会以当前用户身份(-u $$(id -u):$$(id -g))在 Velero 构建镜像中挂载仓库目录运行,隔离了宿主机 Go 工具链差异;$(WHAT)变量可传参限定测试范围。
实际执行 hack/test.sh 时:
- 设置
CGO_ENABLED=0,保证静态编译、测试环境纯净; - 默认收集
./pkg/...、./internal/...与./cmd/...下所有包,并排除pkg/builder、pkg/apis、pkg/test、pkg/generated、pkg/plugin/generated、mocks、internal/restartabletest等纯辅助/生成目录; - 执行
go test -vet="atomic,bool,buildtags,directive,errorsas,ifaceassert,nilfunc,stringintconv,tests" -installsuffix "static" -short -timeout 1200s -coverprofile=coverage.out,即短模式测试 + 1200 秒超时 + 覆盖率输出到coverage.out。
脚本注释中还记录了一个有价值的工程细节:升级 controller-runtime 后,在容器内以非 root 用户跑 envtest 会因/目录不可写而 panic,因此通过XDG_CACHE_HOME=/tmp/规避缓存目录权限问题。这解释了为什么测试必须通过构建镜像执行,而不是直接go test ./...。
本地测试变体
make test WHAT=./pkg/controller/...:把WHAT传给hack/test.sh,仅测试指定包(例如只跑 backup controller 相关测试);make test-local:不经容器、直接在宿主机调用hack/test.sh $(WHAT),适合已配置好 Go 环境的机器;make lint/make local-lint:执行 hack/lint.sh,与测试互补。
仓库中每个核心包都配有同名_test.go,例如 pkg/controller/backup_controller_test.go、pkg/backup/backup_test.go、pkg/restore 下的测试文件,覆盖了 Backup/Restore 状态机、item 收集与插件调用等核心逻辑,可作为理解"什么行为算被测试覆盖"的参考样例。
五、Vendor 依赖管理
开发文档将依赖管理单列一节,指向 v1.1.0 时代的配套文档 vendoring-dependencies.md。该文档说明当时 Velero 使用dep(golang/dep)管理 vendor 依赖:
- 新增依赖:运行
dep ensure(可加-v查看详细输出); - 更新既有依赖:运行
dep ensure -update <pkg> [<pkg> ...],可同时更新一个或多个包。
需要说明的是,这是 v1.1.0 文档所对应的历史事实。从当前仓库根目录 go.mod 与 go.sum 的存在可以推断,项目后续已迁移到 Go Modules 体系:现在由make modules(即go mod tidy)整理依赖,Makefile 中的verify-modules目标会校验go.mod、go.sum是否有未提交的变更。因此,在当前版本上开发时应优先使用 Go Modules 工作流,历史文档中的dep命令仅作版本演进参考。
六、一条完整的本地开发闭环
综合开发文档与 Makefile,一次典型的 Velero 本地开发与提交流程如下:
# 1. 修改代码(API 类型 / CLI flag / 命令 / proto 定义) # 2. 重新生成所有派生文件 make update # 3. 校验生成产物、格式与依赖是否一致 make verify make verify-modules # 4. 运行单元测试 make test # 5. (可选)在构建容器内执行完整 CI 检查 make ci这套流程与make ci(verify-modules verify all test)的顺序一一对应,保证提交前所有自动生成的文件、格式、依赖与测试均处于绿色状态。对只改了 CRD 的快速迭代,可先用make update-crd缩小范围;对只需本地快速验证格式的场景,可用make local-lint跳过容器。
七、结语
Velero 的development.md用四段话定义了生成、校验、测试与依赖四条开发纪律:make update负责把 API/CLI/proto 的改动同步到生成代码,make verify负责守门,make test提供可复现的单元测试环境,依赖管理则由dep演进为 Go Modules。理解这四条纪律背后的脚本链路(hack/update-all.sh、hack/verify-all.sh、hack/test.sh),就等于掌握了 Velero 仓库协作的"隐性约定",无论是提交新功能还是修复 Bug,都能以最小摩擦通过 CI 检查。
【免费下载链接】veleroBackup and migrate Kubernetes applications and their persistent volumes项目地址: https://gitcode.com/GitHub_Trending/ve/velero
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考