第57节 提案 sealer 构建工程设计


❤️💕💕记录sealosopen in new window开源项目的学习过程。k8s,docker和云原生的学习open in new window。Myblog:http://nsddd.topopen in new window


[TOC]

[中文] sealer 构建工程设计

🔥 Questions THAT can BE SOLVED WITH DOCUMENTATION and SEARCH, DON'T ASK !!!

sealer 的 Makefile 设计过于单一和简陋,构建脚本(build.shopen in new window) 过于陈旧和厚重,我们可以通过一些设计方案来对 Makefile 和 build.shopen in new window 进行设计以及改进,让它们看上去很友好。

Makefile 的重构设计到很多的改变,包括一些模块的微调和 CICD actions 的变化,这些都会涉及到,也会慢慢设计,为此,之前我提过一个 RFC,移步到 → https://github.com/sealerio/sealer/issues/2148

Notion 文档:

案例

这是有的,在网易的 horizoncdopen in new window 社区中,我成功设计了一套完整的 Makefile 流程并且可以使用。并且帮助他们改进了贡献者文档open in new window。在它们的项目中,我们能找到一套已经实现的方案,并且提出了设计文稿:https://github.com/horizoncd/horizon/issues/100:

GitHub - horizoncd/horizon: Production-Grade GitOps CD PlatForm For CloudNative Applications, MiddleWares, etc.open in new window

🎯 相比较 horizon,sealer 的设计有哪些危险信号:

  • sealer 支持多二进制编译,需要很好的扩展性,并且正确的通过 并行编译 提高编译速度。
  • sealer 有些 cgo\c 代码涉及到 containers_image_openpgp exclude_graphdriver_devicemapper exclude_graphdriver_btrfs 进行编译。

image/README.md at ed2844ccc615a447b98344d1bbefca61b3cb7749 · mtrmac/imageopen in new window

这样提高了编译和测试的难度,经过调研,我选择的测试方案是 junit-report ,在本地使用 tmp 临时目录作为缓存,提高覆盖率测试速度。

模块方案

迁移目录 version/version.go → pkg/version/version.goopen in new window

hack/ 改名为 scripts/

这些文件的作用如下:


🔥 分为三个模块,分别是新扩展的 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 链接