第57节 提案 sealer 构建工程设计
❤️💕💕记录sealos开源项目的学习过程。k8s,docker和云原生的学习。Myblog:http://nsddd.top
[TOC]
[中文] sealer 构建工程设计
🔥 Questions THAT can BE SOLVED WITH DOCUMENTATION and SEARCH, DON'T ASK !!!
sealer 的 Makefile 设计过于单一和简陋,构建脚本(build.sh) 过于陈旧和厚重,我们可以通过一些设计方案来对 Makefile 和 build.sh 进行设计以及改进,让它们看上去很友好。
Makefile 的重构设计到很多的改变,包括一些模块的微调和 CICD actions 的变化,这些都会涉及到,也会慢慢设计,为此,之前我提过一个 RFC,移步到 → https://github.com/sealerio/sealer/issues/2148
Notion 文档:
案例
这是有的,在网易的 horizoncd 社区中,我成功设计了一套完整的 Makefile 流程并且可以使用。并且帮助他们改进了贡献者文档。在它们的项目中,我们能找到一套已经实现的方案,并且提出了设计文稿:https://github.com/horizoncd/horizon/issues/100:
🎯 相比较 horizon,sealer 的设计有哪些危险信号:
- sealer 支持多二进制编译,需要很好的扩展性,并且正确的通过 并行编译 提高编译速度。
- sealer 有些
cgo\c
代码涉及到containers_image_openpgp exclude_graphdriver_devicemapper exclude_graphdriver_btrfs
进行编译。
image/README.md at ed2844ccc615a447b98344d1bbefca61b3cb7749 · mtrmac/image
这样提高了编译和测试的难度,经过调研,我选择的测试方案是 junit-report
,在本地使用 tmp
临时目录作为缓存,提高覆盖率测试速度。
模块方案
迁移目录 version/version.go → pkg/version/version.go
将 hack/
改名为 scripts/
这些文件的作用如下:
- LICENSE_TEMPLATE:包含许可证的文本模板。
- boilerplate.go.txt:生成新 Go 文件时使用的文本模板(不再使用)。
- build.sh:新的构建脚本
coverage.awk
:用于从 Go 测试文件中提取覆盖率数据的 AWK 脚本。make-rules/
:包含 Makefile 规则的目录。- common.mk:包含通用变量和规则的 Makefile,所有 mk 通用。
- copyright.mk:用于生成代码中的版权信息的 Makefile。
- dependencies.mk:包含依赖关系图和生成依赖关系的 Makefile 规则。
- gen.mk:用于生成代码的 Makefile。
- golang.mk:包含与 Go 编译器和工具链相关的 Makefile 规则。
- image.mk:包含与 Docker 镜像生成相关的 Makefile 规则。
- tools.mk:包含构建与测试工具的 Makefile 规则。
🔥 分为三个模块,分别是新扩展的 Makefile 演示、脚本改进的演示,以及 CICD 流的改进:
makefile
最常用的帮助信息,放入到 Makefile/
❯ make help
Usage: make <TARGETS> <OPTIONS> ...
Targets:
build Build binaries by default
tidy tidy go.mod
vendor vendor go.mod
fmt Run go fmt against code.
vet Run go vet against code.
lint Check syntax and styling of go sources.
style code style -> fmt,vet,lint
linux Build the all with a build script
linux.% Build binaries for Linux (make linux.amd64 OR make linux.arm64)
format Gofmt (reformat) package sources (exclude vendor dir if existed).
test Run unit test.
cover Run unit test and get test coverage.
updates Check for updates to go.mod dependencies
imports task to automatically handle import packages in Go files using goimports tool
clean Remove all files that are created by building.
tools Install dependent tools.
build-in-docker sealer should be compiled in linux platform, otherwise there will be GraphDriver problem.
gen Generate all necessary files.
verify-copyright Verify the license headers for all files.
add-copyright Add copyright ensure source code files have license headers.
help Show this help info.
all-help Show all help details info.
Options:
DEBUG Whether or not to generate debug symbols. Default is 0.
BINS Binaries to build. Default is all binaries under cmd.
This option is available when using: make {build}(.multiarch)
Example: make build BINS="sealer sealctl"
PLATFORMS Platform to build for. Default is linux_arm64 and linux_amd64.
This option is available when using: make {build}.multiarch
Example: make build.multiarch PLATFORMS="linux_arm64 linux_amd64"
V Set to 1 enable verbose build. Default is 0.
能解决更多问题,更加细致的 Makefile
❯ make help-all
go.build.verify Verify that a suitable version of Go exists
go.bin.% Verify binary for specific platform
go.build.% Build binary for specific platform
go.build Build binaries
go.build.multiarch Build multi-arch binaries
go.linux-a Build the project with a build script, use
go.linux-p
go.linux.% Build linux_amd64 OR linux_arm64 binaries
go.lint Run golangci to lint source codes
go.test Run unit test
go.test.junit-report Run unit test
go.test.cover Run unit test with coverage
go.format Run unit test and format codes
imports task to automatically handle import packages in Go files using goimports tool
go.updates Check for updates to go.mod dependencies
go.clean Clean all builds directories and files
copyright.help Show copyright help
---------------------------------------------------------------------------------
copyright.verify Validate boilerplate headers for assign files
copyright.add Add the boilerplate headers for all files
copyright.help Show copyright help
---------------------------------------------------------------------------------
tools.install Install a must tools
tools.install-all Install all tools
tools.install.% Install a single tool in $GOBIN/
tools.install-all.% Parallelism install a single tool in ./tools/*
tools.verify.% Check if a tool is installed and install it
install.golangci-lint Install golangci-lint
install.goimports Install goimports, used to format go source files
install.addlicense Install addlicense, used to add license header to source files
install.deepcopy-gen Install deepcopy-gen, used to generate deep copy functions
install.conversion-gen Install conversion-gen, used to generate conversion functions
install.ginkgo Install ginkgo to run a single test or set of tests
install.go-junit-report Install go-junit-report, used to convert go test output to junit xml
install.kube-score Install kube-score, used to check kubernetes yaml files
install.kubeconform Install kubeconform, used to check kubernetes yaml files
Install go-gitlint Install go-gitlint, used to check git commit message
install.gsemver Install gsemver, used to generate semver
install.git-chglog Install git-chglog, used to generate changelog
install.github-release Install github-release, used to create github release
install.gvm Install gvm, gvm is a Go version manager, built on top of the official go tool.
install.golines Install golines, used to format long lines
install.go-mod-outdated Install go-mod-outdated, used to check outdated dependencies
install.mockgen Install mockgen, used to generate mock functions
install.gotests Install gotests, used to generate test functions
install.protoc-gen-go Install protoc-gen-go, used to generate go source files from protobuf files
install.cfssl Install cfssl, used to generate certificates
install.depth Install depth, used to check dependency tree
install.go-callvis Install go-callvis, used to visualize call graph
install.gothanks Install gothanks, used to thank go dependencies
install.richgo Install richgo
install.rts Install rts
install.codegen Install code generator, used to generate code
tools.help Display help information about the tools package
---------------------------------------------------------------------------------
image.verify Verify docker version
image.daemon.verify Verify docker daemon experimental features
image.build Build docker images
image.build.multiarch Build docker images for all platforms
image.build.% Build docker image for a specific platform
image.push Push docker images
image.push.multiarch Push docker images for all platforms
image.push.% Push docker image for a specific platform
image.manifest.push Push manifest list for multi-arch images
image.manifest.push.% Push manifest list for multi-arch images for a specific platform
image.manifest.remove.% Remove local manifest list
image.manifest.push.multiarch Push manifest list for multi-arch images for all platforms
image.manifest.push.multiarch.% Push manifest list for multi-arch images for all platforms for a specific image
image.help Print help for image targets
---------------------------------------------------------------------------------
Usage: make <TARGETS> <OPTIONS> ...
Targets:
build Build binaries by default
tidy tidy go.mod
vendor vendor go.mod
fmt Run go fmt against code.
vet Run go vet against code.
lint Check syntax and styling of go sources.
style code style -> fmt,vet,lint
linux Build the all with a build script
linux.% Build binaries for Linux (make linux.amd64 OR make linux.arm64)
format Gofmt (reformat) package sources (exclude vendor dir if existed).
test Run unit test.
cover Run unit test and get test coverage.
updates Check for updates to go.mod dependencies
imports task to automatically handle import packages in Go files using goimports tool
clean Remove all files that are created by building.
tools Install dependent tools.
build-in-docker sealer should be compiled in linux platform, otherwise there will be GraphDriver problem.
gen Generate all necessary files.
verify-copyright Verify the license headers for all files.
add-copyright Add copyright ensure source code files have license headers.
help Show this help info.
all-help Show all help details info.
Options:
DEBUG Whether or not to generate debug symbols. Default is 0.
BINS Binaries to build. Default is all binaries under cmd.
This option is available when using: make {build}(.multiarch)
Example: make build BINS="sealer sealctl"
PLATFORMS Platform to build for. Default is linux_arm64 and linux_amd64.
This option is available when using: make {build}.multiarch
Example: make build.multiarch PLATFORMS="linux_arm64 linux_amd64"
V Set to 1 enable verbose build. Default is 0.
Make example:
# make build BINS=sealer Only a single sealer binary is built.
# make -j all Run tidy gen add-copyright format lint cover build concurrently.
# make gen Generate all necessary files.
# make linux.arm64 sealer is compiled on arm64 platform.
# make verify-copyright Verify the license headers for all files.
# make install-deepcopy-gen Install deepcopy-gen tools if the license is missing.
# make build BINS=sealer V=1 DEBUG=1 Build debug binaries for only sealer.
# make build.multiarch PLATFORMS="linux_arm64 linux_amd64" V=1 Build binaries for both platforms.
Ariables:
DEBUG: 0
BINS: sealer seautil
PLATFORMS: linux_amd64 linux_arm64
V:
可观测的编译信息
❯ make build
===========> Verify that a suitable version of Go exists, current version: go version go1.20 linux/amd64
COMMAND=sealer
PLATFORM=linux_amd64
BIN_DIR=/root/workspaces/sealer/_output/bin
===========> Building binary sealer v0.9.3.dirty for linux_amd64
COMMAND=seautil
PLATFORM=linux_amd64
BIN_DIR=/root/workspaces/sealer/_output/bin
===========> Building binary seautil v0.9.3.dirty for linux_amd64
===========> Building binary sealer seautil v0.9.3.dirty for linux_amd64
❯ sealer version #-o yaml
sealerVersion:
major: ""
minor: ""
gitversion: untagged
gitcommit: 7c086967e1ee44d33e095780639b0ee006edf6ad
gittreestate: dirty
builddate: "2023-05-07T11:43:30Z"
goversion: go1.20
compiler: gc
platform: linux/amd64
❯ sealer version -o json
{"sealerVersion":{"gitVersion":"untagged","gitCommit":"7c086967e1ee44d33e095780639b0ee006edf6ad","gitTreeState":"dirty","buildDate":"2023-05-07T11:43:30Z","goVersion":"go1.20","compiler":"gc","platform":"linux/amd64"}}
很方便的打印出当前编译状态,甚至是编译的环境,以及通过 v0.9.3.dirty
判断 git 是否干净。
在 sealer 的 cmd 中,优化了可观测性代码部分。
工具包
本工具包使用 Makefile 实现了一些 CICD 动作,包括代码分析、代码生成、测试、版本控制和实用工具。这些工具的安装方式如下:
- 安装 golangci-lint: 用于代码分析
- 安装 goimports: 用于格式化 Go 源文件
- 安装 addlicense: 用于为源文件添加许可证头
- 安装 deepcopy-gen: 用于生成深度复制函数
- 安装 conversion-gen: 用于生成转换函数
- 安装 ginkgo: 用于运行单个测试或测试集
- 安装 go-junit-report: 用于将 Go 测试输出转换为 junit xml 格式
- 安装 kube-score: 用于检查 Kubernetes yaml 文件
- 安装 kubeconform: 用于检查 Kubernetes yaml 文件
- 安装 go-gitlint: 用于检查 git 提交信息
- 安装 gsemver: 用于生成 semver
- 安装 git-chglog: 用于生成 changelog
- 安装 github-release: 用于创建 Github Release
- 安装 golines: 用于格式化长行
- 安装 go-mod-outdated: 用于检查过时的依赖关系
- 安装 mockgen: 用于生成模拟函数
- 安装 gotests: 用于生成测试函数
- 安装 protoc-gen-go: 用于从 protobuf 文件生成 Go 源文件
- 安装 cfssl: 用于生成证书
- 安装 depth: 用于检查依赖树
- 安装 go-callvis: 用于可视化调用图
- 安装 gothanks: 用于感谢 Go 依赖项
- 安装 richgo: 用于丰富的测试输出
- 安装 rts: 用于查找 Go 类型定义
- 安装 codegen: 用于代码生成
这些工具的安装路径为 $GOBIN 或 $TOOLS_DIR。有些工具需要从 Github 或私有源代码仓库进行安装,有些工具需要进行编译,需要一些特定的参数来安装。
这些工具的使用需要在 Makefile 中调用特定的目标,如下:
- tools.install: 用于安装必须的工具
- tools.install-all: 用于安装所有工具
- tools.install.%: 用于安装单个工具
- tools.install-all.%: 用于并行安装单个工具
- tools.verify.%: 用于检查工具是否已安装并安装它
工具说明
下面是每个工具的详细说明:
- golangci-lint: 用于对 Go 代码进行快速检查的工具,它可以检查常见的错误和潜在的错误,比如:代码风格、不安全的代码、空指针引用、性能问题等。
- goimports: 用于格式化 Go 代码的工具,它可以自动添加或删除未使用的导入,将导入分组,并将包名按字典序排序。
- addlicense: 用于自动为源文件添加许可证头的工具,可以设置多种类型的许可证。
- deepcopy-gen: 用于为 Go 结构体生成深度复制函数的代码生成器。
- conversion-gen: 用于为 Go 结构体生成转换函数的代码生成器。
- ginkgo: 用于运行单个测试或测试集的测试框架,可以使用 Gomega 断言库。
- go-junit-report: 用于将 Go 测试输出转换为 junit xml 格式的工具,用于与其他测试工具或 CICD 流程集成。
- kube-score: 用于检查 Kubernetes yaml 文件的工具,它可以检查文件中的最佳实践和安全问题。
- kubeconform: 用于检查 Kubernetes yaml 文件的工具,它可以检查文件中的最佳实践和安全问题。
- ……
设计技巧
这里有一个巧妙的设计,我们新增了一个 tools
目录。不是所有工具都安装在 GOPATH/bin
目录下,而是将 tools.install
安装逻辑放入了 GOPATH/bin
,将 tools.verify.%
逻辑都放在了 tools
的管理之下。其他的 targer
对象是通过 tools.verify.%
调用的。这对于后期维护非常方便,尤其是在使用工具下的 gvm
管理 Go 语言版本时。
存在的问题
因为 cgo 的原因,单元测试和测试覆盖率依旧很难保证顺利运行
使用 go.build.multiarch
编译的时候,可以保证 amd64
顺利通过,但是不能保证 arm64
编译。
报错信息
cgo: C compiler "aarch64-linux-gnu-gcc" not found: exec: "aarch64-linux-gnu-gcc": executable file not found in $PATH
需要优化一些关于版本的代码
构建脚本优化
一样的,通过帮助信息,可以很清晰的了解:
❯ ./scripts/build.sh -h
Usage: ./scripts/build.sh [-h] [-p PLATFORMS] [-a] [-b BINARIES]
Build Sealer binaries for one or more platforms.
DOTO: I recommend using a Makefile for a more immersive experience
-h, --help display this help and exit
-p, --platform build binaries for the specified platform(s), e.g. linux/amd64 or linux/arm64.
Multiple platforms should be separated by comma, e.g. linux/amd64,linux/arm64.
-a, --all build binaries for all supported platforms
-b, --binary build the specified binary/binaries, e.g. sealer or seautil.
Multiple binaries should be separated by comma, e.g. sealer,seautil.
(note: currently only supported in Makefile)
+ exit 0
- 构建脚本
build.sh
支持多种选项,包括构建指定 binary/binaries(仅在 Makefile 中支持)、构建指定 platform(s) 和构建所有支持的 platform(s),不过目前不支持~
CICD actions 的改进策略
Makefile 的改进,可能导致部分 actions 没办法顺利通过。后面我将会继续优化 CICD 流程。
……
END 链接
✴️版权声明 © :本书所有内容遵循CC-BY-SA 3.0协议(署名-相同方式共享)©