Argo CD 内部 Fork 维护实战:从自建镜像到自定义版本发布
【免费下载链接】argo-cdDeclarative Continuous Deployment for Kubernetes项目地址: https://gitcode.com/GitHub_Trending/ar/argo-cd
本文面向需要从自维护 fork 发布自定义 Argo CD 镜像乃至自定义版本的团队,以及希望在本仓库之外验证发布流程的维护者。文章以 maintaining-internal-argo-cd-forks.md 为骨架,结合仓库内真实工作流源码,完整讲解上游镜像的发布拓扑、fork 所需的 GitHub Actions 变量与 Secrets 配置、fork 版本发布的启用条件,以及触发发布时的关键避坑点。读完本文,你将能够把 fork 构建产物定向推送到自有镜像仓库,并在不污染上游的前提下跑通自定义版本的完整发布链路。
前置说明:绝大多数 Argo CD 贡献者并不需要本节内容,常规开发与贡献流程请直接参考常规开发者指南。本节面向两类场景:需要发布自定义镜像或自定义版本的团队,以及需要在测试环境演练发布流程的 Argo CD 维护者。
一、理解上游镜像的发布拓扑:双注册表模型
在动手配置 fork 之前,先明确 Argo CD 上游镜像"发布到哪里、以什么标签发布"。从仓库中的 image.yaml 与 release.yaml 两个工作流可以还原出完整的发布拓扑:
| 构建来源 | 推送目标 | 标签形态 | 用途 |
|---|---|---|---|
官方 release 标签(vX.Y.Z*) | quay.io/argoproj/argocd(主注册表,fork 可用IMAGE_*变量改写) | v<MAJOR>.<MINOR>.<PATCH>或-rc<X>预发布 | 正式发布版本镜像 + 对应的 provenance 证明 |
| 上游 master 分支 push | 主注册表quay.io/argoproj/argocd | latest | 持续刷新最新标签 |
| 上游 master 分支 push | ghcr.io/argoproj/argo-cd/argocd | <VERSION>-<commit SHA8>(提交标签) | 供cd.apps.argoproj.io固定精确 SHA 使用,同时附带 provenance |
也就是说,上游采用"Quay 主镜像 + GHCR 提交级镜像"双通道:Quay 承载latest与 release 标签,GHCR 承载按提交哈希打标的镜像与签名证明,避免用大量提交标签污染 Quay。
fork 的关键区别在于:
- fork 继承完全相同的发布行为,但所有目标指向你自定义的 registry/namespace;
- fork 构建不会部署到
cd.apps.argoproj.io(该部署 job 在 image.yaml 中显式以github.repository == 'argoproj/argo-cd'为条件); - GHCR 的推送目标默认就是 fork 自己的 GitHub 仓库 Packages 命名空间。
二、从 fork 的 master 分支发布自定义镜像
fork 的每次 master push 都会触发Image工作流(见 image.yaml 的on.push触发条件)。要让构建产物进入你的私有仓库,只需把工作流变量从argoproj指到你的 registry/namespace——其中IMAGE_NAMESPACE是必改项,因为它把工作流从"上游模式"切换到"fork 模式"。
2.1 配置 GitHub Actions Variables(仓库级变量)
在 fork 仓库的Settings → Secrets and variables → Actions → Variables中配置下表变量:
| 变量名 | 默认值 | 是否需要覆盖 | 说明 |
|---|---|---|---|
IMAGE_NAMESPACE | argoproj | 必须覆盖 | Quay 主镜像的命名空间;覆盖它即切换到 fork 模式 |
IMAGE_REPOSITORY | argocd | 视需要 | Quay 主镜像的仓库名 |
GHCR_NAMESPACE | ${{ github.repository }}(即<你的GitHub用户名>/<fork仓库名>) | 极少需要覆盖 | GHCR 镜像的命名空间 |
GHCR_REPOSITORY | argocd | 视需要 | GHCR 镜像的仓库名 |
这些变量在 image.yaml 的set-varsjob 中通过${VAR:-default}语法读取,最终推导出的完整镜像名为:
quay.io/$IMAGE_NAMESPACE/$IMAGE_REPOSITORY ghcr.io/$GHCR_NAMESPACE/$GHCR_REPOSITORY一个值得注意的源码细节:set-vars中还有一层 GHCR 发布护栏——只有当GITHUB_REPOSITORY == 'argoproj/argo-cd',或者GHCR_NAMESPACE不以argoproj/开头时,才允许向 GHCR 推送(image.yaml)。这意味着 fork 若把GHCR_NAMESPACE误设成argoproj/xxx,工作流会拒绝推送并打印提示。这正是文档要求"fork 需覆盖 GHCR_* 或保持默认"的原因:默认值指向 fork 自身仓库,天然满足护栏条件。
2.2 完整示例:推到 Quay 个人命名空间
假设你的 GitHub 账号是my-user,fork 仓库名为my-argo-cd-fork,希望 release 镜像推到quay.io/my-quay-user/argocd,那么只需配置一个变量:
IMAGE_NAMESPACE = my-quay-user效果:
- master 构建镜像发布到
quay.io/my-quay-user/argocd:latest; - 提交级标签镜像及其 attestation 发布到 fork 仓库的 GitHub Packages(GHCR)下,即
ghcr.io/my-user/my-argo-cd-fork/argocd:<VERSION>-<SHA8>。
2.3 fork 模式下的构建平台与推送条件
Image工作流对构建平台做了区分(image.yaml):
- 对
master分支的 push:构建linux/amd64, linux/arm64, linux/s390x, linux/ppc64le四平台多架构镜像; - 对 PR:默认仅构建
linux/amd64(除非 PR 带有test-multi-image标签)。
同时,build-only与build-and-publish两个 job 都以(github.repository == 'argoproj/argo-cd' || image_namespace != 'argoproj')作为执行条件(image.yaml、image.yaml)——这再次印证:fork 只要覆盖IMAGE_NAMESPACE即可正常触发构建与推送,且 push 事件走build-and-publish,PR 事件走build-only。
2.4 配置 GitHub Actions Secrets(凭据)
仅配置变量还不够,工作流还需要主注册表的推送凭据。在 fork 仓库的Settings → Secrets and variables → Actions → Secrets中配置:
| Secret 名称 | 用途 |
|---|---|
RELEASE_QUAY_USERNAME | 推送到 Quay 的账号 |
RELEASE_QUAY_TOKEN | 推送到 Quay 的令牌(具有仓库写入权限) |
在 image.yaml 中,这两个 Secret 被透传给可复用的 image-reuse.yaml,后者负责docker login quay.io、Buildx 多平台构建、推送以及 cosign 签名(image-reuse.yaml)。GHCR 一侧则无需额外配置——它复用secrets.GITHUB_TOKEN与github.actor即可完成认证。
提示:若 fork 只想构建不推送(例如仅做 CI 校验),
build-onlyjob 不需要任何推送凭据;但 master push 触发的build-and-publish必须备齐上述 Quay 凭据。
三、启用 fork 版本发布(自定义 release)
发布自定义版本比发布 master 镜像多一个开关:在 fork 仓库的 Actions 变量中设置:
ENABLE_FORK_RELEASES: true3.1 源码层面的启用条件
release.yaml 的setup-variablesjob 中,allow_fork_release需要同时满足四个条件才会置为true:
GITHUB_REPOSITORY_OWNER != "argoproj" # 仓库 owner 不是 argoproj ENABLE_FORK_RELEASES == "true" # 显式开启 fork 发布 IMAGE_NAMESPACE != "argoproj" # 镜像命名空间已指向自定义目标 GITHUB_REF == refs/tags/* # 由推送 tag 触发而整个Publish ArgoCD Release工作流的各 job(镜像构建、provenance、GoReleaser、SBOM、post-release 等)都统一以github.repository == 'argoproj/argo-cd' || allow_fork_release == 'true'作为执行门槛(如 release.yaml、release.yaml、release.yaml)。因此"仅设ENABLE_FORK_RELEASES: true但IMAGE_NAMESPACE仍为argoproj"不会生效。
同时注意setup-variablesjob 的顶层门槛(release.yaml):
if: github.repository == 'argoproj/argo-cd' || (github.repository_owner != 'argoproj' && vars.ENABLE_FORK_RELEASES == 'true' && vars.IMAGE_NAMESPACE && vars.IMAGE_NAMESPACE != 'argoproj')即:fork 场景下IMAGE_NAMESPACE必须已设置且不等于argoproj,否则连变量计算都不会执行。
3.2 为什么必须拉取全部上游标签
setup-variablesjob 的第一步就是执行git fetch --prune --tags --force(release.yaml),GoReleaser job 也执行git fetch --force --tags(release.yaml)。原因是:
- 发布工具需要历史标签来计算 changelog diff 与"上一个版本"(
GORELEASER_PREVIOUS_TAG,见 release.yaml,由 hack/get-previous-release 计算); - 需要判断当前 tag 是否为最新发布(
is_latest_release),决定是否移动stable标签(release.yaml)。
因此文档强调:启用 fork 发布时务必确保所有上游标签都被拉取。实践上建议 fork 时不要浅克隆,或定期同步上游 tags。
3.3 复用镜像变量与 Secrets
fork 发布完全复用第一节中的镜像变量(IMAGE_NAMESPACE、IMAGE_REPOSITORY)与 Secrets(RELEASE_QUAY_USERNAME、RELEASE_QUAY_TOKEN)。从 release.yaml 可见,release 镜像名直接拼接为quay.io/$IMAGE_NAMESPACE/$IMAGE_REPOSITORY:${GITHUB_REF_NAME}(即以版本 tag 为镜像标签),provenance 则指向去掉 tag 后的仓库地址。
3.4 触发发布:务必指向 fork remote
启用 fork 发布后,其余步骤与标准发布流程完全一致,但有一处关键调整:
[!WARNING] 调用
hack/trigger-release.sh时,第二参数必须指向你的 fork remote(通常是origin),不能指向 upstream,否则脚本可能向官方仓库推送正式 tag。
./hack/trigger-release.sh v2.7.2 origin这一点在 trigger-release.sh 源码中有双重保护逻辑:
- 脚本首先校验参数与 tag 格式:必须形如
v<MAJOR>.<MINOR>.<PATCH>或v<MAJOR>.<MINOR>.<PATCH>-rc<X>(trigger-release.sh); - 校验当前分支必须是推导出的
release-<MAJOR>.<MINOR>分支(trigger-release.sh); - 若检测到目标 remote 的 URL 包含
argoproj/argo-cd,会打印大段警告并强制要求 30 秒内输入y确认,否则中止(trigger-release.sh); - 随后确保 release 分支与远程同步、检查本地与远程均不存在同名 tag,最后创建 tag 并 push 到指定 remote(trigger-release.sh)。
推送 tag 成功后,Publish ArgoCD Release工作流即被触发,可在 Actions 页跟踪执行。
3.5 fork 发布流程全景(对应标准发布步骤)
将以上配置串起来,fork 完成一次自定义发布共四步:
- 更新版本与 manifest:运行 init-release.yaml(手动触发),填写
TARGET_BRANCH与TARGET_VERSION(不带v前缀),该工作流会更新VERSION文件、通过make manifests-local重新生成 manifests(此时同样读取IMAGE_REGISTRY/IMAGE_NAMESPACE/IMAGE_REPOSITORY变量,见 init-release.yaml),并自动创建 PR; - 合并 PR,确保
CHANGELOG.md与goreleaser.yaml等发布前置内容已就绪(参见发布流程); - 在 release 分支上执行
./hack/trigger-release.sh <vX.Y.Z> origin; - 验证产物:检查工作流状态、GitHub Release 附件、Quay 上的镜像与 provenance 是否如预期落在自定义命名空间。
fork 场景下,发布工作流的post-releasejob 中更新stable标签、创建gitops-engine/前缀 tag、在 master 分支 bumpVERSION等行为同样以github.repository == 'argoproj/argo-cd'或allow_fork_release为门槛(release.yaml),因此 fork 发布是完整闭环的,产物全部归属 fork 自身仓库。
四、与发布流程相关的关键文件索引
无论是排查 fork 发布问题,还是进一步研读,以下文件是必查清单:
| 文件 | 作用 |
|---|---|
| docs/developer-guide/releasing.md | 标准发布流程(fork 发布在此基础上只改 remote 指向) |
| .github/workflows/image.yaml | master 镜像构建/发布工作流,IMAGE_*/GHCR_*变量的读取处 |
| .github/workflows/image-reuse.yaml | 可复用镜像构建、推送、cosign 签名工作流 |
| .github/workflows/release.yaml | 版本发布工作流,ENABLE_FORK_RELEASES与allow_fork_release的计算处 |
| .github/workflows/init-release.yaml | 版本号与 manifests 初始化工作流 |
| hack/trigger-release.sh | 发布触发脚本,含官方仓库防误推保护 |
实用提示:发布失败时不要删除重建同名 tag——Argo CD 的一次发布会同时产出 GitHub Release、stable 标签、Go 依赖包、镜像与 SBOM 等多类产物,删除重建不安全。正确做法是修复问题后发布下一个补丁版本(如3.2.4失败则发布3.2.5),并将失败版本标记为无效(详见 releasing.md 的 "If something went wrong" 一节)。此外,手动发布流程不被支持——镜像签名与 provenance 必须由 GitHub Actions 生成,这保证了 fork 与上游发布的供应链证明能力一致。
【免费下载链接】argo-cdDeclarative Continuous Deployment for Kubernetes项目地址: https://gitcode.com/GitHub_Trending/ar/argo-cd
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考