☰
Flux (v1) 从源码构建与测试实战指南:make 构建、Docker 镜像与跨架构编译全解析
2026/10/15 18:28:59 网站建设 项目流程
  • 云原生
  • DevOps
  • 容器编排
  • 运维

【免费下载链接】flux

Successor: https://github.com/fluxcd/flux2

项目地址:https://gitcode.com/gh_mirrors/flu/flux
点击查看免费下载

导读:本文以 Flux(v1)官方构建文档 docs/contributing/building.md 为骨架,完整讲解在本地从源码产出fluxd守护进程二进制、fluxctlCLI 工具与 Docker 镜像的流程,并深入 Makefile、docker/ 与 test/e2e/ 等仓库源码,剖析make背后的完整执行链路、镜像 Tag 命名规则、跨架构(ARCH)编译原理以及单元测试与端到端测试的运行机制。读完你将能够在自己的机器上复现官方构建产物、按需切换目标架构,并正确执行与排查构建、测试过程中的各类问题。

一、文档适用范围与版本提示

先明确一点:本文描述的是 Flux v1 的构建方式。仓库文档在开头给出了明确的升级提示——Flux (v1) 已于 2022 年 11 月停止维护(reached its end-of-life),官方强烈建议读者熟悉新一代 Flux(Flux v2)并尽快迁移。因此,本文及仓库内 docs/contributing/ 目录下的构建、开发文档均只面向 legacy v1 代码库;如果你正在评估新项目,应直接参考 Flux v2 的相关资料。

对于仍然需要维护或研究 v1 源码的读者,本文以下内容完全基于当前仓库的实际状态,所有命令与配置均可直接复现。

二、环境要求:Go 环境、Docker daemon 与 GOPATH 约定

构建 Flux v1 需要两个核心前置条件:

  1. 可用的 Go 环境:文档要求 Go 版本 >= 1.11(官方发布版曾基于 1.13 构建)。需要说明的是,当前仓库的 go.mod 中声明的是go 1.16,且 pkg/install/go.mod(独立的生成子模块)声明go 1.13——以仓库实际内容为准,建议使用 Go 1.16 或更高版本进行构建,以兼容当前依赖树。
  2. Docker daemon:构建流程需要 Docker 来产出镜像。若当前用户没有 Docker 权限,Makefile 会自动探测(docker info失败时追加sudo):
SUDO := $(shell docker info > /dev/null 2> /dev/null || echo "sudo")

此外,仓库使用Go Modules管理依赖(根目录存在 go.mod 与 go.sum)。这意味着构建位置不再受$GOPATH限制——如果你显式设置了$GOPATH,请把仓库 clone 到该目录之外,避免模块路径与 GOPATH 布局产生混淆。

三、一键构建:make 的完整执行链路

克隆仓库后,在根目录直接执行:

make

这一步会同时完成 Docker 镜像构建,并把二进制安装到$GOBIN(如果你定义了该变量),否则安装到$(go env GOPATH)/bin(Makefile 中取go env GOPATH第一个路径下的bin)。

make实际命中的是默认目标all(Makefile):

all: $(GOBIN)/fluxctl build/.flux.done

它由两条链路组成:$(GOBIN)/fluxctl与build/.flux.done,下面逐一拆解。

3.1 安装 fluxctl 到 GOBIN

目标$(GOBIN)/fluxctl(Makefile)执行的是:

$(GOBIN)/fluxctl: $(FLUXCTL_DEPS) $(GENERATED_TEMPLATES_FILE) go install ./cmd/fluxctl

其中:

  • FLUXCTL_DEPS由go list -deps生成,收集./cmd/fluxctl/...的全部非标准库依赖文件,用于增量构建判断(Makefile);
  • $(GENERATED_TEMPLATES_FILE)即pkg/install/generated_templates.gogen.go,由 pkg/install/generate.go 与 pkg/install/templates/ 下的*.tmpl模板文件通过go generate生成(Makefile)。fluxctl install命令正是依赖这些内嵌模板来生成部署清单的,因此构建前必须先生成它。

3.2 构建 fluxd 与配套工具,产出 Docker 镜像

build/.flux.done是一个"哨兵文件"式目标(Makefile),依赖五项产物:

build/.flux.done: build/fluxd build/kubectl build/sops build/kustomize docker/ssh_config docker/kubeconfig docker/known_hosts.sh

各子目标的职责如下:

目标职责实现要点
build/fluxd编译 fluxd 守护进程二进制CGO_ENABLED=0 GOOS=linux GOARCH=${ARCH} go build ... ./cmd/fluxd(Makefile),静态编译、目标平台固定为 linux,架构由ARCH决定
build/kubectl下载 kubectl 到镜像内从cache/linux-$(ARCH)/kubectl-$(KUBECTL_VERSION)复制,版本由 docker/kubectl.version 固定为v1.21.14,并做 SHA-512 校验
build/kustomize下载 kustomize版本由 docker/kustomize.version 固定为3.8.7(注释说明:更高版本会引入 fluxcd/flux#3500 的回归,故刻意锁低版本),做 SHA-256 校验
build/sops下载 sops版本由 docker/sops.version 固定为v3.7.3,做 SHA-256 校验
docker/ssh_config等构建输入文件分别对应 SSH 客户端配置、kubeconfig与 known hosts 生成脚本,会被 Dockerfile 拷贝进镜像

随后,通用镜像构建规则build/.%.done(Makefile)执行 Docker 构建:

$(SUDO) docker build -t docker.io/fluxcd/$* -t docker.io/fluxcd/$*:$(IMAGE_TAG) \ --build-arg VCS_REF="$(VCS_REF)" \ --build-arg BUILD_DATE="$(BUILD_DATE)" \ -f build/docker/$*/Dockerfile.$* ./build/docker/$*

也就是说,每次构建会同时打两个 Tag:

  • docker.io/fluxcd/flux:latest——固定最新;
  • docker.io/fluxcd/flux:<branch>-<commit>——带分支名与提交哈希的唯一 Tag(详见下一节)。

VCS_REF取git rev-parse HEAD,BUILD_DATE取 UTC 时间戳,两者作为--build-arg写入镜像的 OCI Label(见 docker/Dockerfile.flux)。

3.3 镜像内容:Dockerfile.flux 与 Dockerfile.fluxctl

主镜像定义在 docker/Dockerfile.flux,基于alpine:3.15,最终入口为ENTRYPOINT [ "/sbin/tini", "--", "fluxd" ](用 tini 作为 PID 1 管理进程)。其关键构成包括:

  • 运行依赖:openssh-client、ca-certificates、tini、git>=2.24.2、gnutls、glib、gnupg、gawk、socat,以及来自 Alpine edge/testing 仓库的git-secret(用于加密密钥场景);
  • git 主机密钥:通过 docker/known_hosts.sh 脚本预置知名 git 主机的 known_hosts,配合StrictHostKeyChecking使用;
  • SSH 配置:拷贝 docker/ssh_config,默认指向挂载的私钥;
  • 配套二进制:将kubectl、kustomize、sops拷入/usr/local/bin,并引入squaremo/kubeyaml:0.7.0中的 kubeyaml 文件到 PATH;
  • 网络细节:创建/etc/nsswitch.conf(内容hosts: files dns),解决 Go 静态编译(netgo)在 Alpine/musl 环境下优先走 DNS 而非/etc/hosts的已知问题(Dockerfile 注释对此有完整说明)。

而fluxctl的 CLI 镜像定义在 docker/Dockerfile.fluxctl,同样是alpine:3.15基础,额外安装openssh-client、ca-certificates、curl,仅拷贝fluxctl一个二进制,体量更小。

四、镜像 Tag 的生成规则:image-tag 脚本

镜像的<branch>-<commit>Tag 由 docker/image-tag 脚本(bash)计算,Makefile 通过IMAGE_TAG:=$(shell ./docker/image-tag)引用。其规则如下:

  1. 命中 Git Tag:若HEAD恰好指向一个 tag,直接输出该 tag 作为镜像版本(例如发布版输出1.17.0);若同时存在带v前缀与不带前缀的两个 tag(如v1.17.0与1.17.0),则去掉v前缀输出;存在多于两个 tag 时脚本报错退出;
  2. 未命中 tag:输出分支名-短commit哈希,其中分支名会做归一化处理——空格与斜杠替换为短横线、过滤非字母数字字符并转小写;
  3. 工作区不干净:若git diff HEAD显示存在未提交改动,则在 Tag 后追加-wip后缀。

例如在master分支、工作区干净时,构建会产出docker.io/fluxcd/flux:master-a86167e4这样的镜像。这一规则同时被用于fluxctl二进制中的版本号注入(-ldflags "-X main.version=$(./docker/image-tag)",见 Makefile),保证二进制版本与镜像 Tag 一致。

五、跨架构构建:ARCH 变量

文档特别提示:默认目标架构是 amd64。如需为其他架构构建 Docker 镜像与二进制,需要显式传入ARCH:

make ARCH=arm64

对应实现位于 Makefile:

ifeq ($(ARCH),) ARCH=amd64 endif

ARCH的实际作用范围包括:

  • build/fluxd的GOARCH=${ARCH}(Makefile),使守护进程二进制面向目标架构静态编译;
  • build/kubectl从cache/linux-$(ARCH)/kubectl-...取用对应架构的 kubectl(docker/kubectl.version 中为amd64、arm、arm64三个架构分别提供了 SHA-512 校验和)。

需要说明的边界(源自源码中的FIXME注释):kustomize与sops的下载 URL 目前固定为linux-amd64(Makefile),shellcheck/shfmt也固定为x86_64——也就是说,非 amd64 架构下会下载 amd64 版辅助工具进入镜像构建目录。因此在实际使用跨架构构建时,应以理解 fluxd 本身实现了目标架构编译为前提,并按需自行处理辅助工具的架构问题。

六、运行测试:单元测试与端到端测试

构建文档给出了两类测试入口,下面分别对应仓库实现展开。

6.1 单元测试:make test

make test

对应 Makefile:

test: test/bin/helm test/bin/kubectl test/bin/sops test/bin/kustomize $(GENERATED_TEMPLATES_FILE) PATH="${PWD}/bin:${PWD}/test/bin:${PATH}" go test ${TEST_FLAGS} $(shell go list $(patsubst %, %/..., $(LOCAL_GO_MODULES)) | sort -u)

执行要点:

  • 会先准备helm、kubectl、sops、kustomize测试工具到test/bin/(版本分别固定为 helm2.17.0、kubectlv1.21.14、sopsv3.7.3、kustomize3.8.7,均带校验和验证),并生成generated_templates.gogen.go;
  • 通过go list -m ... | grep收集主模块github.com/fluxcd/flux下的所有本地模块(含pkg/install子模块),对其全部包执行go test;
  • 支持通过TEST_FLAGS透传额外参数,例如make test TEST_FLAGS='-run TestImages -v'可只跑指定用例并输出详细日志。

仓库中覆盖较广的单元测试包括 pkg/git/operations_test.go、pkg/update/images_test.go、pkg/cluster/kubernetes/kubernetes_test.go、pkg/daemon/daemon_test.go 等,几乎每个核心包都配了对应的_test.go文件。

6.2 端到端测试:make e2e

make e2e

端到端测试在真实 Kubernetes 集群上验证 Flux 的完整工作流。目标定义(Makefile)为:

e2e: lint-e2e test/bin/helm test/bin/kubectl test/bin/sops test/bin/crane test/e2e/bats $(GOBIN)/fluxctl build/.flux.done PATH="${PWD}/test/bin:${PATH}" CURRENT_OS_ARCH=$(CURRENT_OS_ARCH) test/e2e/run.bash

其前置阶段包括:

  • lint-e2e(Makefile):用shfmt(2.6.4)对test/e2e/*.bats与test/e2e/lib/*做格式 diff 检查,并用shellcheck(0.7.0)做静态检查,不符合规范会直接报错;
  • test/bin/crane:go build编译 go-containerregistry 的 crane 工具;
  • test/e2e/bats:解压固定 commit(3a1c2f28)的 bats-core 测试框架(当前使用 2opremio 的 fork,Makefile 注释说明了原因)。

真正执行测试的脚本是 test/e2e/run.bash,流程如下:

  1. 探测集群:若本机kubectl version不可用,则自动下载kind(v0.11.1),用kind create cluster创建kindest/node:v1.21.1的 Kubernetes 集群(可通过E2E_KIND_CLUSTER_NUM指定并行创建多个集群,配合 GNU Parallel 并行跑测试);
  2. 加载镜像:把刚构建的docker.io/fluxcd/flux:latest镜像kind load docker-image进集群;
  3. 运行 bats 用例:在 test/e2e 目录下执行 bats,默认跑全部用例,可通过E2E_TESTS挑选,例如make e2e E2E_TESTS='11_*'只跑11_fluxctl_install相关用例。

仓库中的端到端用例覆盖面包括:10_helm_chart.bats(Helm Chart 部署)、11_fluxctl_install.bats(fluxctl install)、12_sync.bats(同步)、13_sync_gc.bats(垃圾回收)、14_release_image.bats(镜像发布)、15_fluxctl_list.bats、16_fluxctl_sync.bats、17_fluxctl_policies.bats、20_commit_signing.bats/20_commit_verification.bats(提交签名与验证)、21_ssh_key_generation.bats(SSH 密钥生成)、22_manifest_generation.bats(清单生成)等。测试夹具(fixtures)位于 test/e2e/fixtures/,包含kustom目录下按用例编号组织的 kustomize 补丁与 gitconfig 等资源。

6.3 自定义测试的实用变量

变量作用示例
TEST_FLAGS透传给go test的额外参数make test TEST_FLAGS='-v -run TestImages'
E2E_TESTS选择要执行的 bats 用例文件make e2e E2E_TESTS='14_*'
E2E_KIND_CLUSTER_NUM并行创建的 Kind 集群数量make e2e E2E_KIND_CLUSTER_NUM=3

七、其他常用构建目标

7.1 release-bins:fluxctl 跨平台交叉编译

make release-bins(Makefile)产出发布用二进制到build/目录,编译矩阵为:

  • linux/darwin/windows×amd64;
  • linux×arm/arm64。

全部使用CGO_ENABLED=0静态编译,并注入main.version版本号:

CGO_ENABLED=0 GOOS=$$os GOARCH=$$arch go build -o "build/fluxctl_"$$os"_$$arch" \ $(LDFLAGS) -ldflags "-X main.version=$(shell ./docker/image-tag)" ./cmd/fluxctl/

产物形如build/fluxctl_linux_amd64、build/fluxctl_darwin_amd64、build/fluxctl_windows_amd64(Windows 平台的扩展名在目标规则中未强制添加.exe,实际发布时需按平台约定处理)。

7.2 clean 与 realclean

  • make clean(Makefile):go clean、删除./build目录以及test/bin/下的下载工具,适合快速清理产物;
  • make realclean(Makefile):在clean基础上额外删除./cache(所有下载缓存的工具压缩包),彻底还原初始状态。

7.3 generate-deploy 与 check-generated

  • make generate-deploy(Makefile):调用刚构建的fluxctl install,以固定的参数(--git-url git@github.com:fluxcd/flux-get-started、--git-email flux@example.com、--git-user 'Flux automation'、--git-label flux-sync、--namespace flux)把部署清单输出到 deploy/ 目录,仓库当前版本已包含生成的flux-account.yaml、flux-deployment.yaml、memcache-dep.yaml等文件;
  • make check-generated(Makefile):执行生成后git diff --exit-code -- deploy/ pkg/install/,用于 CI 校验生成产物与仓库内容一致,防止手工改动或过期模板被误提交。

八、构建中的常见问题与排查要点

  1. Docker 权限:make中途docker build失败,多半是当前用户不在 docker 组。Makefile 会自动探测并尝试sudo docker,若你的环境不允许 sudo,请先自行将用户加入 docker 组或配置好 docker 权限。
  2. 网络下载失败:构建会从外部渠道下载 kubectl、helm、kustomize、sops、shellcheck、shfmt、bats 等固定版本工具(并做 SHA-256/SHA-512 校验)。网络受限环境下应先确保这些下载可达,或将产物预先放入cache/目录复用。
  3. 版本漂移:文档早期要求 Go >= 1.11,但当前 go.mod 已声明go 1.16,且依赖树通过replace固定了 Kubernetes 1.21.14、helm-operator 1.4.0、yaml.v3 等版本(部分是为了规避 CVE)。构建报 "go.mod requires go >= 1.16" 之类错误时,升级本地 Go 即可。
  4. 镜像 Tag 不更新:如果工作区没有实际改动,image-tag脚本输出与上一次相同的 Tag(git diff HEAD为空则无-wip后缀),docker build可能因缓存命中而"看起来没变化"。开发迭代时保留未提交改动并重新make,即可得到带-wip的新 Tag。
  5. e2e 依赖:make e2e需要本机能够创建 Kind 集群(或已有可用 kubectl 集群),且要求 GNU Parallel;lint-e2e阶段未通过 shfmt/shellcheck 规范会直接终止测试,可按提示先运行shfmt -w修正格式。

九、总结

从源码构建 Flux v1 的核心链路可以浓缩为一条主线:make(all)→ 生成安装模板 → 安装fluxctl到 GOBIN → 静态编译fluxd→ 下载 kubectl/kustomize/sops 等配套工具 → 通过 docker/Dockerfile.flux 与 docker/Dockerfile.fluxctl 产出docker.io/fluxcd/flux:latest与docker.io/fluxcd/flux:<branch>-<commit>两个 Tag 的镜像。随后可用make test跑单元测试、make e2e在 Kind 集群上跑端到端测试,用make ARCH=arm64切换目标架构,用make release-bins交叉编译 CLI,用make generate-deploy重新生成部署清单。理解了 Makefile 与 docker/image-tag 这些关键文件之后,任何一次构建行为都可以被精确预期与复现。

  • 云原生
  • DevOps
  • 容器编排
  • 运维

【免费下载链接】flux

Successor: https://github.com/fluxcd/flux2

项目地址:https://gitcode.com/gh_mirrors/flu/flux
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询