用 updatecli 驱动 Rancher 依赖版本自动化:定时工作流、Manifest 结构与本地验证实践
【免费下载链接】rancherComplete container management platform项目地址: https://gitcode.com/GitHub_Trending/ra/rancher
Rancher 作为一套完整的容器管理平台,其仓库中维护着 Kubernetes、k3s、Rancher Machine、Harvester Docker Machine Driver、Wins、System Agent 等大量上游组件的版本依赖,且这些版本往往同时散落在go.mod/go.sum、Dockerfile.runtime、package/Dockerfile、pkg/settings/setting.go等多处文件中。本指南以仓库根目录下的 updatecli/README.md 为主线,讲解 Rancher 如何借助 updatecli 以"每天一次的定时工作流 + 可扩展的 Manifest 管道"自动完成安全相关更新与版本号提升。读完本文,你将理解 updatecli 的sources/conditions/targets三阶段模型,掌握仓库中 5 个真实更新工作流的写法,并能在本地用updatecli diff安全地预演改动后再提交 PR。
为什么 Rancher 选择 updatecli 而不是 Dependabot 或 Renovate
Rancher 官方文档明确指出,之所以选择 updatecli 而不是 Dependabot 或 Renovate,是因为updatecli 的可扩展性以及多插件资源(multiple plugins resources),可以在编排"一系列条件式更新步骤"时提供更大的灵活性。
这一设计理念在仓库的实际工作流中体现得非常直观:一次版本升级往往不是简单改一行版本号,而是需要"先读取当前版本 → 查询上游最新版本 → 校验镜像/校验和 → 同步改写多个文件"的链式操作。例如在 update-machine.yaml 中,一次 Machine 版本更新要同时处理go.mod、go.sum(模块哈希与 go.mod 哈希)、Dockerfile.runtime、package/Dockerfile(含 amd64/arm64 校验和)、pkg/settings/setting.go(machine 驱动镜像)共 9 个 target,这种多文件联动场景正是条件化、可组合管道擅长的领域。
说明:updatecli 的详细使用方式以其官方文档为准(原 README 以链接形式给出),本文聚焦 Rancher 仓库内已经落地的真实 Manifest 与工作流配置。
定时工作流:每天一次自动扫描,可手动触发
自动化通过 GitHub Actions 的scheduled workflow 每天运行一次,同时支持在需要时手动触发单个或全部管道。其完整定义位于 .github/workflows/updatecli.yml,关键配置如下:
name: "updatecli" on: schedule: # Runs daily at 12:00 UTC. - cron: '0 12 * * *' workflow_dispatch: inputs: tag: description: 'Optional Rancher Machine tag; used only by the machine update.' required: false type: string target: description: 'Select which updatecli workflow to run or `all` to run all updates.' required: true default: 'all' type: choice options: - 'all' - 'k3s' - 'k8s' - 'harvester-docker-machine' - 'machine' - 'wins-system-agent'几点值得注意的实现细节:
- 手动触发支持按目标定向执行:
workflow_dispatch的target输入可指定k3s、k8s、harvester-docker-machine、machine、wins-system-agent或all。脚本根据事件类型决定执行范围:schedule事件或workflow_dispatch且target=all时对updatecli/updatecli.d/全量执行;指定目标时只执行对应子目录:updatecli apply --clean --values updatecli/values.d/values.yaml \ --config "updatecli/updatecli.d/update-${{ inputs.target }}/" - Machine 更新可指定发布标签:
tag输入会透传为环境变量MACHINE_RELEASE_TAG,供 Machine 工作流在"手动指定版本"与"自动取最新版"两种模式间切换。 - 令牌安全:工作流通过 GitHub App 创建短期 token(而非长期 PAT)并注入
UPDATECLI_GITHUB_ACTOR与UPDATECLI_GITHUB_TOKEN环境变量。脚本中有明确注释:永远不要使用--debug或manifest show选项,因为它们会泄漏 GH token。 - 遗留分支清理:正式执行前会先对比已关闭与已打开的
updatecli_前缀 PR 分支,删除残留的远端分支,避免每次运行积累垃圾分支。 - 触发条件:整个 Job 仅在
main分支上运行(if: github.ref == 'refs/heads/main')。
项目组织:一个工作流一个子目录,Manifest 三阶段模型
Rancher 在updatecli/目录下维护全部自动化配置。按 README 给出的目录结构,实际仓库当前布局如下:
updatecli/ ├── README.md ├── updatecli.d/ # 更新相关的工作流(Manifest) │ ├── update-k3s/ # K3s 补丁版本更新 │ ├── update-k8s/ # K8s 补丁版本更新 │ ├── update-harvester-docker-machine/ # Harvester Docker Machine Driver 更新 │ ├── update-machine/ # Rancher Machine 更新 │ └── update-wins-system-agent/ # Wins 与 System Agent 更新 └── values.d/ └── values.yaml # 变量相关配置文件(含 scm 与 repos 配置)README 强调:Manifest 文件必须放在与其主要用途对应的目录路径下,这是仓库的强制约定,便于按目标定向运行(如上文--config "updatecli/updatecli.d/update-${{ inputs.target }}/")。
三阶段管道模型:sources / conditions / targets
每个 Manifest(即一条 pipeline)由三个阶段组成,共同定义更新策略:
sources(源):定义"从哪里发现新版本"。常见kind包括:golang/gomod:读取go.mod中的模块版本;githubrelease:查询上游 GitHub 仓库的最新 Release;file:从仓库内文件(如go.mod、package/Dockerfile)正则匹配当前版本;shell:执行 shell 命令(如wget/curl拉取产物并计算 sha256)。
conditions(条件):在执行更新前校验前置条件是否满足,例如"镜像rancher/k3s:<新版本>是否已发布""Dockerfile 中是否存在待更新的 ENV 指令"。条件不满足时管道停止,不会产生错误提交。targets(目标):定义"把新版本写到哪里、如何替换",例如把package/Dockerfile中的ENV CATTLE_K3S_VERSION更新为{{ source "k3s-release" }}。
源之间可以通过dependson串联,target 可以通过sourceid明确引用某个 source 的输出;disablesourceinput: true表示该阶段不消费默认 source 输入,常用于条件/目标阶段。
全局变量:values.yaml
共享配置集中在 updatecli/values.d/values.yaml,Manifest 内以{{ .scm.xxx }}、{{ .repos.xxx }}方式引用,避免在多个 YAML 中重复定义。核心内容分为两块:
scm(源码管理配置):定义提交人与 PR 行为,例如:scm: user: 'github-actions[bot]' email: '41898282+github-actions[bot]@users.noreply.github.com' username: 'UPDATECLI_GITHUB_ACTOR' token: 'UPDATECLI_GITHUB_TOKEN' owner: 'rancher' repo: 'rancher' branch: 'main' # commitusingapi: false 表示不用 GraphQL API 提交,以便支持 squash commitusingapi: false commitmessage: squash: true mergemethod: 'squash'其中
commitusingapi: false有一处专门注释:该选项本可让提交获得"已验证(verified)"签名,但 GraphQL API 不允许 squash 提交;鉴于更新产生的提交量很大,Rancher 选择牺牲签名换取 squash 以减少噪音。repos(上游仓库清单):集中登记所有需要跟踪的上游仓库,包括harvester/docker-machine-driver-harvester、rancher/machine、k3s-io/k3s、kubernetes/kubernetes、rancher/system-agent、rancher/wins。
此外values.yaml还为每个工作流定义了manifest(管道名称)、pipelineid(幂等标识)与commitmessage的type/scope。pipelineid的作用是保证每次运行针对同一更新生成/复用一个分支与 PR,而不是不断新建。
SCM 与 Action 复用:以下划线开头的部分文件
update-k8s/_scm.yaml是一个典型的复用文件(README 提到的目录结构中的辅助做法)。updatecli 约定以下划线_开头的文件为"部分文件",不会独立执行,而是被其他 Manifest 合并引用。它把scms.default(github 类型 SCM)和actions.rancher-pr(github/pullrequest 类型 Action,携带dependencies标签、reviewers、squash 合并策略)集中定义,供同目录下其他文件复用。update-k3s/_scm.yaml同样承担此角色。
实战拆解:仓库中 5 条真实更新管道
1. K8s 补丁版本更新(update-k8s)
该子目录由三个相互依赖的文件组成,完整呈现了"发现 → 校验 → 回写 → 再生成"的复杂管道:
- autodiscovery-k8s.yaml:使用 updatecli 的autodiscovery(自动发现)能力,通过
golangcrawler 扫描go.mod中所有k8s.io/*模块,按 semver 的patch模式筛选补丁版本,同时显式ignore掉k8s.io/client-go、k8s.io/gengo、k8s.io/helm、k8s.io/legacy-cloud-providers、k8s.io/kube-openapi、k8s.io/klog.*、k8s.io/utils等不需要随主版本联动的模块,groupby: all将发现归并为单一 PR(actionid: 'rancher-pr')。 - go-generate.yaml:依赖上面的
bump-k8s-version。其conditions阶段执行go generate ./... && git diff --exit-code,通过changedif(exitcode类型,warning=0 / success=1)判断代码生成后工作区是否有差异;targets阶段再次运行go generate ./... && git diff生成待提交的改动。这确保了 K8s 依赖升级后所有生成代码同步刷新。 - update-kubectl.yaml:专门更新 kubectl 版本,依赖
go-generate。它先用golang/gomod从go.mod提取 K8s 主次版本(find: 'v\d+\.\d+'变换出major.minor),再用githubrelease按 semver 模式~<major>.<minor>取最新补丁版本;随后两个shellsource 分别wget下载 amd64 与 arm64 的 kubectl 并计算 sha256(sha256sum kubectl)。条件阶段校验package/Dockerfile、tests/validation/Dockerfile.rke、tests/validation/Dockerfile.v3api中的ENV|ARG KUBECTL_VERSION及测试脚本tests/validation/tests/rke/scripts/build.sh、tests/validation/tests/v3_api/scripts/build.sh中的KUBECTL_VERSION变量;目标阶段则把版本号与两个架构的KUBECTL_CHECKSUM_amd64/KUBECTL_CHECKSUM_arm64一并更新。
2. K3s 补丁版本更新(update-k3s)
update-k3s.yaml 是"跨工具链约束"的典型例子:K3s 的版本号必须与 Rancher 当前依赖的 Kubernetes 版本绑定。其实现方式是先读go.mod中的k8s.io/kubernetes版本,再以正则'^{{ source "rancher-go-mod-k8s" }}\+k3s[0-9]+$'在 k3s 的 GitHub Release 中匹配形如<k8s版本>+k3s<序号>的 tag。由于镜像 tag 不允许出现+,另一个shellsource 通过replacer变换器把+替换为-得到rancher/k3s镜像版本。条件阶段用dockerimage类型确认rancher/k3s:<新版本>镜像真实可用,并用file类型校验Dockerfile.runtime与package/Dockerfile中确实存在ENV CATTLE_K3S_VERSION和COPY --from=rancher/k3s:...;目标阶段同步改写这两处:
targets: update-dockerfile-k3s-cattle-version: kind: file spec: files: - 'Dockerfile.runtime' - 'package/Dockerfile' matchpattern: 'ENV[\s\t]+CATTLE_K3S_VERSION[=\s]+\S+' replacepattern: 'ENV CATTLE_K3S_VERSION={{ source "k3s-release" }}'3. Rancher Machine 更新(update-machine)
update-machine.yaml 展示了 updatecli 最完整的多文件联动更新。它从go.mod中读取当前github.com/rancher/machine版本,并通过一个shellsource 实现"指定版本优先、否则取最新"的双模式逻辑:
if [ -n "${MACHINE_RELEASE_TAG}" ]; then if ! git check-ref-format --allow-onelevel "refs/tags/${MACHINE_RELEASE_TAG}"; then echo "Invalid Rancher Machine tag: ${MACHINE_RELEASE_TAG}" >&2 exit 1 fi git ls-remote --exit-code --tags https://github.com/{{ .repos.machine.owner }}/{{ .repos.machine.repo }}.git "refs/tags/${MACHINE_RELEASE_TAG}" > /dev/null || { echo "Rancher Machine tag does not exist: ${MACHINE_RELEASE_TAG}" >&2; exit 1; } printf '%s\n' "${MACHINE_RELEASE_TAG}" else git ls-remote --tags https://github.com/{{ .repos.machine.owner }}/{{ .repos.machine.repo }}.git | cut -f2 | sed -E "s#refs/tags/##; s/\^\{\}$//" | sort -u | grep -E "^v[0-9]+\.[0-9]+\.[0-9]+-rancher[0-9]+(\.[0-9]+)?$" | sort -V | tail -n1 fi该管道共 9 个 target,覆盖:go.mod版本、go.sum中的模块哈希(通过go mod download -json提取"Sum")与 go.mod 哈希(提取"GoModSum")、Dockerfile.runtime与package/Dockerfile中的ENV CATTLE_MACHINE_VERSION、amd64/arm64 的CATTLE_MACHINE_CHECKSUM_amd64/CATTLE_MACHINE_CHECKSUM_arm64(由curl ... | sha256sum计算),以及pkg/settings/setting.go中的rancher/machine:v<版本>镜像。对应.github/workflows/updatecli.yml中的tag手动输入正是为此设计。
4. Harvester Docker Machine Driver 更新(update-harvester-docker-machine)
update-harvester-docker-machine.yaml 的独特之处在于,它同时涉及Dockerfile 指令级更新与Go 源码级更新:
- 从
package/Dockerfile读取当前ENV DOCKER_MACHINE_HARVESTER_VERSION,按 semver 模式~<当前版本>取同主次下的最新补丁版; - 分别计算 amd64/arm64 二进制当前版与新版的 sha256(4 个 checksum source);
- 目标阶段使用
kind: dockerfile按指令keyword: ENV+matcher: DOCKER_MACHINE_HARVESTER_VERSION精确定位并更新 Dockerfile; - 同时用
kind: file更新pkg/data/management/machinedriver_data.go中的harvesterDriverVersion常量及"amd64"/"arm64"哈希映射; - 最后通过
go fmt pkg/data/management/machinedriver_data.go保证修改后的 Go 源码格式合规,并以changedif(file/checksum类型)判断是否真正产生了文件差异。
5. Wins 与 System Agent 更新(update-wins-system-agent)
update-wins-system-agent.yaml 处理 Windows 节点相关组件。它从package/Dockerfile提取基础版本(去掉预发布后缀),再以 semver 模式~<base>-0跟踪带预发布后缀(-0等)的最新版本(typefilter同时开启release: true与prerelease: true)。校验和阶段从上游 Release 的sha256.txt/sha256sum.txt中分别提取wins.exe、install.ps1、uninstall.ps1、rancher-system-agent-amd64、rancher-system-agent-arm64、install.sh、system-agent-uninstall.sh的哈希。除更新package/Dockerfile中的一系列CATTLE_WINS_AGENT_*与CATTLE_SYSTEM_AGENT_*变量外,还同步更新pkg/settings/setting.go中 Wins 的install.ps1下载地址与 System Agent 的install.sh下载地址。
本地测试:用 diff 模式预演,绝不直接 apply
README 给出了严格的本地测试要求:
- 准备 updatecli 二进制:从 updatecli 官方 Releases 下载,且只使用最新稳定版进行测试。
- 准备 GitHub Personal Access Token(fine-grained):出于安全考虑,避免在 shell 历史或环境中泄露 PAT,必须将其导出为本地环境变量:
export UPDATECLI_GITHUB_TOKEN="your GH token"- 本地永远使用
diff命令:它会展示将发生的改动而不会真正应用。README 给出的标准命令为:
updatecli diff --clean --values updatecli/values.d/values.yaml --values <other values files> --config updatecli/updatecli.d/<your workflow>以本仓库为例,针对 K8s 工作流可执行:
updatecli diff --clean \ --values updatecli/values.d/values.yaml \ --config updatecli/updatecli.d/update-k8s/注意--clean选项会让 updatecli 在运行前清理tmp与旧分支缓存,保证结果可复现;--values可以多次指定以叠加变量文件。
本地测试时的变量来源
由于 Manifest 中大量使用了{{ requiredEnv .scm.token }}与{{ requiredEnv .scm.username }},本地执行diff时同样需要这两个环境变量。GitHub Actions 中由工作流注入(见 .github/workflows/updatecli.yml 的Apply updatecli步骤),本地则可对照设置:
export UPDATECLI_GITHUB_ACTOR="<你的 GitHub 用户名>" export UPDATECLI_GITHUB_TOKEN="<你的 GH token>" updatecli diff --clean --values updatecli/values.d/values.yaml --config updatecli/updatecli.d/update-k3s/此外,若需手动指定 Machine 版本进行预演,可同时导出MACHINE_RELEASE_TAG环境变量。
贡献指南:给 Rancher 新增一个更新管道
README 的 Contributing 部分要求贡献者:
- 遵循本文(README)中的全部约定:新建 Manifest 时按上述三阶段模型编写,并放入与其用途对应的
updatecli/updatecli.d/<purpose>/子目录;需要辅助脚本时放入updatecli/scripts/;共享变量放入updatecli/values.d/。 - 先本地测试再提交:使用上文
updatecli diff命令在本地验证改动符合预期。 - 在 fork 上自测:正式提 PR 前,先在自己的 fork 上运行测试,确保管道在真实仓库环境下行为正确。
新增管道时可参考现有文件的成熟模式:借用_scm.yaml的部分文件复用 SCM 与 PR Action;用values.yaml登记上游repos并定义manifest/pipelineid;在 CI 工作流target的options列表中追加新的可定向执行目标。
小结:从 README 到工作流的完整证据链
本文所有配置均可在当前仓库中直接核对:概念约定见 updatecli/README.md,全局变量见 updatecli/values.d/values.yaml,5 条管道分别位于 updatecli/updatecli.d/update-k3s/、updatecli/updatecli.d/update-k8s/、updatecli/updatecli.d/update-harvester-docker-machine/、updatecli/updatecli.d/update-machine/、updatecli/updatecli.d/update-wins-system-agent/,定时调度与手动触发逻辑见 .github/workflows/updatecli.yml。这套体系既保证了上游补丁(尤其是安全相关更新)能按天快速跟进,又通过diff预演、条件校验、校验和追踪、squash 合并等手段把自动化升级的风险控制在可审查、可回滚的范围内。若你要在 Rancher 生态中引入或扩展类似的依赖自动更新能力,上述模式可作为直接复用的蓝本。
【免费下载链接】rancherComplete container management platform项目地址: https://gitcode.com/GitHub_Trending/ra/rancher
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考