3. Git作为单一事实源

在 GitOps 模型中,Git 仓库不仅是代码的版本控制工具,更是整个系统的单一事实源(Single Source of Truth)。所有环境(开发、测试、预发布、生产)的期望状态都必须以声明式清单的形式存储在 Git 中。本章将深入剖析仓库结构设计、分支策略选择以及配置与代码分离原则,帮助你在实际项目中构建健壮的 GitOps 工作流。

3.1 仓库结构设计:单仓库 vs. 多仓库

选择仓库结构是 GitOps 落地的第一步。常见的模式有两种:单仓库(Monorepo)和多仓库(Multi-Repo)。下表从多个维度对比了两种模式的适用场景与优劣:

维度 单仓库(Monorepo) 多仓库(Multi-Repo)
管理复杂度 较低,所有配置集中管理,权限统一 较高,需跨仓库协调,权限粒度细
原子性回滚 支持,一次提交可同时更新应用和基础设施 不支持,需在多个仓库中分别回滚
CI/CD 触发 需精细路径过滤,避免全量触发 天然隔离,变更只触发对应仓库
团队协作 适合中小团队,跨服务协作方便 适合大型团队,服务边界清晰
推荐场景 微服务数量 < 20,或基础设施与应用紧密耦合 微服务数量 > 50,或团队组织按服务划分
实践建议:对于大多数中大型项目,推荐采用混合模式:一个独立的 gitops-config 仓库存放所有环境的 Kubernetes 清单和 Helm values,而应用代码则按服务分散在各自的仓库中。这样既保持了配置的单一事实源,又避免了单仓库过大带来的性能问题。

3.2 分支策略:GitFlow vs. Trunk-Based

分支策略决定了变更如何流入 Git 仓库,并最终影响环境状态。在 GitOps 中,分支策略直接决定了环境一致性和发布节奏。以下是两种主流策略的对比:

特性 GitFlow Trunk-Based Development
分支数量 多(master, develop, feature, release, hotfix) 少(main + 短期 feature 分支)
发布频率 低(按版本发布,通常每周/每月) 高(每日多次,甚至持续发布)
环境映射 develop → 开发环境;release → 预发布;master → 生产 main → 生产;短分支 → 开发/测试环境
回滚复杂度 较高,需在多个分支间协调 较低,直接 revert main 上的提交
GitOps 适配度 中等,适合传统版本发布 高,天然匹配声明式持续同步

下图展示了 Trunk-Based 分支策略在 GitOps 中的典型工作流:

Trunk-Based GitOps 分支策略与同步流程 Trunk-Based 分支策略与 GitOps 同步流程 main(生产) feature/xxx bugfix/xxx release/xxx GitOps Operator 持续同步(ArgoCD / Flux) 开发环境 预发布环境 生产环境 说明:只有 main 分支的变更会触发生产环境同步;短分支仅用于开发和测试环境
关键原则:在 GitOps 中,main 分支始终代表生产环境的期望状态。任何对 main 的提交都应触发 GitOps Operator 自动同步到生产集群。Trunk-Based 策略通过缩短分支生命周期,减少了环境漂移的风险,是 GitOps 社区推荐的首选方案。

3.3 配置与代码分离原则

将配置与代码分离是 GitOps 的核心实践之一。配置包括环境变量、数据库连接串、功能开关、资源配额等;代码则指应用二进制、Docker 镜像、Helm Chart 模板等。分离的好处在于:

  • 安全隔离:敏感配置(如密钥)可以加密存储,不与代码一起暴露。
  • 环境独立:同一份代码可以通过不同的配置部署到开发、测试、生产环境。
  • 审计追溯:配置变更独立记录,便于合规审计和问题排查。

下图展示了配置与代码分离后的典型仓库结构:

配置与代码分离的仓库结构 配置与代码分离的仓库结构 应用代码仓库(app-repo) src/(源代码) Dockerfile .gitignore Makefile / CI 脚本 ⚠ 不包含环境配置 配置仓库(gitops-config) environments/dev/ environments/staging/ environments/prod/ secrets/(加密密钥) helm-values/(values 文件) CI 构建后 引用配置

3.4 配置分层与覆盖策略

在实际项目中,配置通常按环境和服务两个维度进行分层管理。以下是一个推荐的目录结构示例:

gitops-config/
├── environments/
│   ├── dev/
│   │   ├── namespace.yaml
│   │   ├── deployment.yaml
│   │   └── configmap.yaml
│   ├── staging/
│   │   ├── namespace.yaml
│   │   ├── deployment.yaml
│   │   └── configmap.yaml
│   └── prod/
│       ├── namespace.yaml
│       ├── deployment.yaml
│       └── configmap.yaml
├── helm-values/
│   ├── common.yaml          # 所有环境共享的默认值
│   ├── dev.yaml             # 开发环境覆盖
│   ├── staging.yaml         # 预发布环境覆盖
│   └── prod.yaml            # 生产环境覆盖
├── secrets/
│   ├── dev.enc.yaml         # 使用 SOPS 加密
│   ├── staging.enc.yaml
│   └── prod.enc.yaml
└── kustomization.yaml       # 顶层 Kustomize 入口
避坑指南:不要将数据库密码、等敏感信息以明文形式存储在 Git 仓库中。务必使用 SOPS、Sealed Secrets 或 External Secrets Operator 等工具进行加密管理。同时,确保 .gitignore 排除了所有未加密的敏感文件。

3.5 分支策略与配置分离的协同

将分支策略与配置分离结合,可以形成强大的 GitOps 工作流。以下是一个典型的协同流程:

  1. 开发阶段:开发者从 main 创建短分支(如 feature/add-logging),修改应用代码仓库中的源代码,同时修改配置仓库中 environments/dev/ 下的配置。
  2. CI 构建:CI 流水线构建 Docker 镜像,并将镜像标签写入配置仓库的 environments/dev/deployment.yaml 中。
  3. 自动同步:GitOps Operator 检测到配置仓库的 dev 目录变更,自动将新配置同步到开发集群。
  4. 预发布验证:通过 PR 将配置从 dev 合并到 staging 目录,触发预发布环境同步。
  5. 生产发布:PR 合并到 main 分支后,配置仓库的 environments/prod/ 被更新,GitOps Operator 自动将变更应用到生产集群。
核心收益:通过这种协同,每一次环境变更都有对应的 Git 提交记录,实现了完整的变更审计链。同时,由于配置与代码分离,运维团队可以独立管理配置,而无需接触应用源代码,降低了误操作风险。

3.6 本章小结