2026年8月2日 1 分钟阅读

不要把镜像 tag 当发布流程:Kargo 如何用 Freight、验证门和 Git 提交治理 Kubernetes 多环境提升

tinyash 0 条评论

在 Kubernetes 的 GitOps 实践里,CI 构建镜像、Argo CD 同步集群、允许一批工件进入生产,常被混成一件事。它们其实对应三个不同问题:构建系统负责产出工件;持续交付控制器负责让声明状态落到集群;而跨环境发布治理要回答的是:这一组彼此匹配的镜像、Chart 和配置修订,是否已经通过了应有的验证,可以从测试环境进入下一站?

Kargo 是一个 Apache-2.0 许可的开源应用生命周期编排器,专注解决第三个问题。它不替换镜像仓库、CI 或 GitOps 同步器,而是在它们之间引入可追溯的发布单元和提升规则。对服务数量增长、环境不止一个的团队,这能避免“把某个镜像 tag 改到 production”成为唯一发布流程。

先把工件组合固定下来:Warehouse 与 Freight

Kargo 的三个核心对象很适合用发布流水线来理解。

  • Warehouse:订阅并发现候选工件,例如容器镜像、Git 仓库提交或 Helm Chart;
  • Freight:引用一组工件的元工件,可视为一次可移动、可审计的“发布货单”;
  • Stage:一个环境或交付阶段,定义它接受哪些 Freight、怎样提升以及如何验证。

关键不在于给镜像换一个名字,而在于把多个组件的版本关系显式保存下来。假设一个服务由 API 镜像、Web 镜像和 GitOps 配置仓库共同组成;只记录 api:1.8.0,无法说明它应搭配哪个 Web 版本和哪份配置。Freight 将这些引用组合为一次提升的候选,后续测试、审批与生产记录都能围绕同一个对象展开。

这也使“当前生产运行什么”不只是读某个 tag。你可以追溯某个 Freight 经过了哪些 Stage、由哪些工件组成、在何处被验证或被人工批准。对于需要排障、回滚或复盘的多服务变更,这比散落在多个 CI 日志里的版本字符串更容易对齐。

Stage 不是目录名,而是进入下一环境的规则

很多仓库会有 devtestprod 目录;目录划分本身并不会约束工件如何流动。Kargo 的 Stage 可以要求下游只接收已在上游 Stage 验证过的 Freight。来源策略既可以使用默认的 OneOf,也可以使用 All:后者适用于一个发布候选必须同时满足多个上游验证来源的场景。

这让团队能够将环境准入写成可检查的声明,而不是依赖口头约定。例如:测试环境可以接收 Warehouse 新发现的候选;预发布环境只接收已通过测试验证的 Freight;生产环境则要求预发布结果与额外批准条件。具体要设多少关取决于风险,不应把更多 Stage 误当成更安全;每一关都应该对应能实际执行、能给出结果的验证或决策。

Kargo 的 promotion steps 可以更新并提交 Git 配置,之后由 Argo CD 同步到目标集群。因此 Git 历史记录的是“哪组工件被提升到哪里”的变更,而不是仅记录部署控制器某次碰巧拉到了哪个 tag。Kargo 与 Argo CD、Argo Rollouts 的组合很常见;其中,使用 Argo Rollouts 的 AnalysisTemplateAnalysisRun 做验证是可选整合,并非应用采用 Kargo 的前提。

一个可复现的最小操作:先观察,再提升

基础安装前,集群需要已有 cert-manager;官方基础安装页以 Helm v3.13.1 为示例。默认安装适合本地或受控试用,生产环境还应按照组织的认证、网络暴露、密钥管理与最小权限要求配置,不应把默认管理员账户配置直接暴露到公网。

下面的命令来自官方基础安装流程。它生成管理账户密码哈希与 token 签名密钥,再通过 OCI Chart 安装 Kargo:

pass=$(openssl rand -base64 48 | tr -d "=+/" | head -c 32)
hashed_pass=$(htpasswd -bnBC 10 "" "$pass" | tr -d ':\n')
signing_key=$(openssl rand -base64 48 | tr -d "=+/" | head -c 32)

helm install kargo \
  oci://ghcr.io/akuity/kargo-charts/kargo \
  --namespace kargo \
  --create-namespace \
  --set api.adminAccount.passwordHash="$hashed_pass" \
  --set api.adminAccount.tokenSigningKey="$signing_key" \
  --wait

安装并完成项目、Warehouse 与 Stage 的声明后,不要立刻把“最新”送去生产。先查看项目发现的 Freight:

kargo get freight --project kargo-demo

在测试 Stage 中,按 Warehouse 选择候选执行提升:

kargo promote \
  --project my-project \
  --stage test \
  --warehouse my-warehouse

命令只是触发点,不是验证本身。实际流程应在提升后等待 GitOps 同步完成,并让测试、合约检查或分析任务把结论写回对应的 Stage。只有确认 Freight 的工件组合、目标配置和验证结果都符合预期,才考虑下一环境。

自动提升需要治理,人工介入也不能被自动化覆盖

自动提升很容易被误解为“只要有最新构建就一路发布”。Kargo 将自动提升作为项目级能力,避免只有 Stage 编辑权限的成员自行开启。它提供 NewestFreightMatchUpstream 等策略,用于指定自动化应选择什么候选;选择策略仍应和团队的分支策略、测试时长及发布窗口一起设计。

更实用的一点是人工覆盖的保护。当操作员有意把非自动候选的 Freight 提升到某个 Stage,例如处理 hotfix、暂时冻结版本或回退验证,Kargo 会建立 hold,阻止自动化立刻把环境改回它认为的“最新候选”。只有后续提升当前自动候选,hold 才会解除。这样人工决策不再只是短暂改写一个文件、随后被机器人覆盖。

生产前的显式批准同样可以通过 CLI 表达:

kargo approve \
  --project kargo-demo \
  --freight  \
  --stage prod

批准不是绕过一切约束。它可以绕过该 Stage 的验证条件,但 Freight 仍必须符合该 Stage 请求的工件来源。换言之,批准是一个被记录的风险决策,不应被设计成任意把无关构建塞进生产的后门。

把可观测性接到发布决策,而非只接到事故响应

验证门最容易流于形式:部署完成后只等几分钟,没有明确指标、时间窗口和失败处置,最终仍是在“看起来没问题”时继续提升。更稳妥的做法是让每个 Stage 的验证回答可复查的问题,例如新版本在固定观察窗口内是否完成就绪、错误率与延迟是否越过团队阈值、关键合成事务是否成功。验证的输入应绑定到这次 Freight 和目标 Stage,输出要能让下一位值班者看懂为什么通过或失败。

这并不要求一次性引入复杂的自动化分析。第一版可以只把现有的 smoke test 或部署后健康检查接入测试 Stage;等团队能稳定处理失败结果,再逐步接入更严格的指标分析。重要的是定义失败路径:验证失败后 Freight 停在哪个 Stage、谁来判断重试或修复、如何避免相同候选反复消耗环境。Kargo 提供的是将提升与验证编排在一起的边界,阈值、查询质量和告警归因仍由应用与平台团队负责。

版本不可变并不等于可以跳过回滚设计

即使 Freight 记录了工件组合,也不应把它理解为自动回滚承诺。数据库迁移、外部接口变更、特征开关和消息格式都可能让“重新部署旧镜像”不足以恢复服务。使用 Kargo 前,先为每类变更明确回退策略:纯应用变更能否重新提升已知良好的 Freight;向后兼容迁移如何与应用版本配合;不可逆操作是否必须走独立审批。这样,Git 历史与 Freight 才能在故障时成为决策证据,而不是事后才发现缺少上下文的记录。

从一个窄场景开始,而不是重写交付体系

Kargo 适合的起点不是“迁移所有部署”,而是选一条已有 GitOps 基础、又确实受多环境版本协调困扰的服务链路:

  1. 先定义一个 Warehouse,明确要追踪哪些镜像、Git revision 或 Helm Chart;
  2. 把 API、前端和配置等需要共同移动的工件固定进 Freight;
  3. 在测试 Stage 接入已有的部署后检查、冒烟测试或分析任务;
  4. 再让预发布、生产 Stage 只接受已验证的候选,并保留需要的审批;
  5. 演练一次失败提升、一次人工 hold 和一次恢复,确认审计记录与团队预期一致。

如果你的应用只有一个镜像、一个环境,且每次部署都能被简单可靠地验证,额外的发布编排可能只会增加复杂度。但当“构建成功”已不等于“这一组工件可安全进入下一环境”,把 Freight、验证门、Git 提交和人工例外放入同一条可追溯链路,能让发布状态从隐含约定变成可验证的工程对象。

相关链接

发表评论

你的邮箱地址不会被公开,带 * 的为必填项。