26、Git与DevOps:基础设施即代码(IaC)的版本控制、GitOps 理念与实践

聊到 DevOps,很多人第一反应是 CI/CD 流水线、自动化部署。但说实话,真正让 DevOps 落地生根的,是「基础设施即代码」这个理念。我刚开始接触这个概念时,也觉得不就是把服务器配置写成脚本嘛,有啥了不起的?直到有一次,我手动修改了生产环境的 Nginx 配置,结果忘了备份……嗯,那次事故让我彻底明白了:基础设施必须像应用代码一样,纳入版本控制

什么是基础设施即代码(IaC)?

说白了,就是用代码来定义和管理你的服务器、网络、负载均衡器这些基础设施。你想想看,以前运维同学登录服务器,敲命令改配置,全靠经验和记忆力。现在呢?我们把所有配置写成声明式文件,存在 Git 仓库里。谁改了什么,什么时候改的,一目了然。

我个人习惯把 IaC 分为两类:

  • 声明式:你告诉系统「我要什么状态」,系统自己去搞定。比如 Terraform、CloudFormation。
  • 命令式:你告诉系统「每一步怎么做」。比如 Ansible、Puppet 的某些模式。

在实际项目中,我更推荐声明式。为什么?因为声明式文件天然适合 Git 的 diff 和回滚。你改一行代码,Git 就能告诉你这次变更会影响哪些资源。

IaC 的版本控制:不只是存代码

把 Terraform 文件扔进 Git 仓库,这只是第一步。真正要做好 IaC 的版本控制,有几个坑你必须避开。

我曾经踩过的坑: 把敏感信息(比如数据库密码、API Key)直接写进了 Terraform 变量文件,还 push 到了公共仓库。虽然很快就删了,但 Git 历史里永远留下了痕迹。后来我养成了习惯:所有敏感信息必须用变量引用,变量值存在 Vault 或 CI/CD 的 Secret 里

这里我总结了几条 IaC 版本控制的最佳实践:

实践 说明
模块化 把通用的基础设施(如 VPC、数据库)拆成独立模块,方便复用
环境隔离 dev、staging、production 用不同的分支或目录管理
状态文件管理 Terraform 的 state 文件不要提交到 Git,用远程后端(如 S3)
版本锁定 锁定 provider 和模块的版本,避免「昨天还能用,今天就不行了」
代码审查 基础设施变更必须走 PR 审查流程,跟应用代码一样

GitOps:让 Git 成为唯一的真相来源

GitOps 是 IaC 的进阶玩法。它的核心理念很简单:你想要的系统状态,全部声明在 Git 仓库里。然后有个自动化工具,不断对比 Git 里的状态和实际运行的状态,发现不一致就自动修正。

我刚开始用 GitOps 时,总觉得多此一举。直到有一次,某个同事手痒,在生产服务器上临时改了防火墙规则。如果是传统方式,可能过几天就忘了这回事。但 GitOps 的自动同步机制立刻发现了差异,直接回滚了那个手动修改。嗯,那一刻我彻底服了。

GitOps 的核心工作流大概是这样的:

GitOps 核心工作流 开发者 提交变更 Git 仓库 唯一真相来源 CI/CD 流水线 构建 & 测试 GitOps Operator 持续同步 生产环境 实际运行状态 反馈 & 告警 差异检测 → 自动回滚

这个流程里,最核心的角色是 GitOps Operator(比如 Argo CD、Flux)。它就像一个尽职的保安,不停地在 Git 仓库和实际环境之间做对比。一旦发现有人偷偷改了生产环境,它立刻把状态「拉」回 Git 里定义的样子。

GitOps 的三大原则

我在团队里推行 GitOps 时,发现很多人容易忽略它的底层原则。这里我用自己的话总结一下:

  1. 声明式描述:整个系统的期望状态,必须用声明式的方式描述清楚。不是「怎么做」,而是「最终长什么样」。
  2. 版本化且不可变:所有变更都通过 Git 提交,历史可追溯。一旦部署,就不允许手动修改。
  3. 自动拉取:Operator 主动从 Git 拉取状态,而不是被动等待推送。这能确保「Git 里有什么,系统里就有什么」。
我的小建议: 刚开始实践 GitOps 时,别急着把所有环境都纳管。先挑一个非关键环境(比如 dev)试点。等流程跑顺了,再逐步推广到 staging 和 production。我见过太多团队一上来就想全量切换,结果出问题后手忙脚乱。

实际案例:用 Git 管理 Kubernetes 集群

Kubernetes 是 GitOps 最典型的应用场景。你想想看,一个 K8s 集群里可能有几十个 Deployment、Service、ConfigMap,如果全靠 kubectl apply 手动管理,迟早会出乱子。

我习惯的做法是这样的:

  • 把所有 K8s 资源定义(YAML 文件)放在一个 Git 仓库里
  • 用 Kustomize 或 Helm 做环境差异化配置
  • 部署 Argo CD 作为 GitOps Operator
  • 每次修改 YAML 文件 → 提交 PR → 合并到 main 分支 → Argo CD 自动同步到集群

这里有个简单的 Argo CD Application 定义示例:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: my-app
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/my-org/k8s-manifests.git
    targetRevision: main
    path: overlays/production
  destination:
    server: https://kubernetes.default.svc
    namespace: production
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

注意看 syncPolicy 里的 selfHeal: true,这就是 GitOps 的「自愈」能力。如果有人手动改了集群里的 Pod 副本数,Argo CD 会自动把它改回来。

避坑指南:GitOps 不是银弹

说了这么多好处,我也得泼点冷水。GitOps 在某些场景下并不适用:

  • 频繁变动的配置:比如需要实时调整的限流参数,每次改都要走 Git 提交,效率太低
  • 紧急故障恢复:有时候生产环境挂了,你等不及 PR 审查和 CI 流程,需要直接登录服务器改配置
  • 有状态应用:数据库、缓存这类有状态服务,GitOps 的自动回滚可能导致数据丢失

我曾经在一个金融项目里,就因为 GitOps 的自动同步机制,差点把生产数据库的配置回滚了。后来我们加了一条规则:有状态服务的配置变更,必须手动确认,不启用自动同步

总结一下

Git 和 DevOps 的结合,说白了就是让基础设施的管理变得像软件开发一样规范。IaC 让你能「用代码定义基础设施」,GitOps 让你能「用 Git 驱动基础设施的变更」。这两者加起来,就是 DevOps 里「持续交付」的最后一公里。

我个人觉得,未来几年 GitOps 会成为基础设施管理的标配。就像当年 Git 取代 SVN 一样,GitOps 也会逐步取代传统的运维方式。如果你还没开始尝试,不妨从一个小项目入手,感受一下「提交代码就能改变世界」的爽快感。

一句话记住: 基础设施即代码是基础,GitOps 是灵魂。没有 Git 的基础设施,就像没有刹车的跑车——跑得快,但停不下来。


公众号:蓝海资料掘金营,微信deep3321