传统的集群运维方式里,运维人员通过 kubectl apply、kubectl edit 直接修改线上资源,短期看效率很高,但时间一长问题就会暴露:某个 Deployment 的副本数到底是谁改的、什么时候改的、为什么改,没人说得清;出了故障想回滚,发现没有历史版本可查。声明式配置与 GitOps 正是为了解决这类问题而生,它把整个集群的期望状态全部沉淀为 Git 仓库中的配置文件,任何变更都必须走代码评审和提交流程,集群则由自动化控制器持续向期望状态收敛。

声明式配置的核心思想:描述结果而非过程
命令式思维关注的是“怎么做”,比如先创建一个 Deployment,再执行 kubectl scale 扩容,最后手动创建 Service。声明式思维关注的则是“最终长什么样”:你在 YAML 文件里写清楚期望的副本数、镜像版本、暴露端口,至于怎么从当前状态到达期望状态,交给 Kubernetes 的控制循环去完成。这种思想带来的最大好处是配置本身就是文档,文件里写了三个副本,集群里就应该有三个副本,任何偏差都可以被自动检测和纠正。
要真正落地声明式管理,有几个前提条件需要满足。第一,所有资源都要用 YAML 或等价的声明式格式描述,不能有依赖脚本执行顺序的隐性逻辑;第二,配置文件必须纳入版本控制,且以 Git 仓库为准,而不是本地某台机器的文件;第三,变更入口要收敛,禁止绕过 Git 直接改集群。下面是一个典型的声明式应用配置示例:
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
namespace: production
spec:
replicas: 3
selector:
matchLabels:
app: web-app
template:
metadata:
labels:
app: web-app
spec:
containers:
- name: web-app
image: registry.ippipp.com/web-app:v1.2.3
ports:
- containerPort: 8080
注意这里的 image 标签用的是不可变的 v1.2.3 而不是 latest。声明式体系里,可变标签是一个大坑:同样的配置文件,今天部署的和明天部署的可能是不同的代码,声明就失去了确定性。这也是 GitOps 实践中反复强调的一点,配置中的每一个字段都应该是可预测、可重现的。
GitOps 的工作流程与工具选型
GitOps 由 Codefresh 的 CEO Alexa 先生在 2017 年提出,其核心原则可以概括为四条:第一,整套系统的声明式描述必须存在于 Git 中;第二,Git 是唯一的事实来源,集群状态与仓库不一致时以仓库为准;第三,已批准的变更可以自动应用到集群,不需要人工执行命令;第四,软件代理持续对比实际状态与期望状态,发现偏差时告警甚至自动纠正。这四条原则把“改配置”这个动作从运维人员的特权变成了任何人都可以发起的 Pull Request,权限控制和审计自然而然地落在了 Git 层面。
目前主流的 GitOps 工具是 Argo CD 和 Flux,两者定位接近但风格差异明显。Argo CD 提供了非常完善的 Web 界面,可以直观看到每个应用当前同步的 Git 提交、资源树结构以及健康状态,上手体验友好,特别适合刚起步的团队。Flux 则走纯 API 路线,界面轻量,与 Kubernetes 生态的集成更偏底层,多集群场景下通过搭配 Flamingo 或 Kustomize 组合也很灵活。选型时可以参考下表:
| 对比维度 | Argo CD | Flux |
|---|---|---|
| 用户界面 | 完善的 Web UI 与可视化资源树 | 以 CLI 和 API 为主,界面较轻 |
| 多租户 | 项目级权限管理,适合多团队 | 偏基础设施层统一管理 |
| 渲染工具 | 原生支持 Helm、Kustomize、Jsonnet | 原生支持 Helm、Kustomize |
| 社区生态 | 应用交付场景案例丰富 | CNCF 毕业项目,持续交付场景成熟 |
以 Argo CD 为例,接入一个应用的配置大致如下:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: web-app
namespace: argocd
spec:
project: default
source:
repoURL: https://git.ippipp.com/team/web-app-config.git
targetRevision: main
path: overlays/production
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: true
selfHeal: true
其中 selfHeal 开启后,一旦有人手动改了集群里的资源,Argo CD 会自动把它纠正回 Git 中定义的状态,这是防止配置漂移的关键开关。而 prune: true 表示 Git 里删掉的资源在集群里也会被同步删除,两个开关配合才能真正实现“Git 即真相”。
仓库结构设计与环境隔离实践
工具只是载体,仓库结构才是决定 GitOps 能否长期维护下去的根本。常见做法是把应用代码和配置代码分开:应用仓库存源码和 Dockerfile,镜像由 CI 构建并推送;配置仓库存部署清单,只引用镜像的不可变 tag。发布流程则是 CI 构建完镜像后,通过一个小的自动化步骤修改配置仓库中的镜像版本字段并提交,随后 Argo CD 或 Flux 检测到新提交,自动同步到集群。这种方式被称为 push 模式的镜像更新加 pull 模式的集群同步,是目前接受度最高的组合。
多环境管理推荐使用 Kustomize 的 base 加 overlay 结构。base 存放所有环境共享的基础配置,overlay 针对开发、测试、生产环境做差异化覆盖,比如不同的副本数、不同的环境变量、不同的域名:
config-repo/
├── base/
│ ├── deployment.yaml
│ ├── service.yaml
│ └── kustomization.yaml
├── overlays/
│ ├── dev/
│ │ ├── kustomization.yaml
│ │ └── patches.yaml
│ ├── staging/
│ │ └── kustomization.yaml
│ └── production/
│ ├── kustomization.yaml
│ └── patches.yaml
└── argocd/
└── application.yaml
环境隔离还有一个容易被忽视的问题:生产环境的仓库分支策略。有些团队允许直接向 main 分支提交生产变更,风险较高。更稳妥的做法是 main 分支始终对应当前生产状态,任何变更走 Pull Request,评审通过后合入并自动同步;紧急回滚则通过 Git revert 实现,回滚动作本身也有完整记录,审计时一目了然。
漂移检测、密钥管理与渐进式交付
配置漂移是集群管理中最隐蔽的风险。集群的实际状态可能被 Horizontal Pod Autoscaler 修改副本数、被突变控制器注入 sidecar,也可能被某个工程师深夜应急时手动 kubectl patch 过。GitOps 工具会持续对比实际状态和期望状态,发现差异后通过 UI 或告警通知,配合 selfHeal 可以自动恢复。但要注意区分“应该恢复”和“不应该恢复”的差异,比如 HPA 托管的副本数字段,自动纠正反而会破坏弹性伸缩,这类字段需要通过 ignoreDifferences 显式排除,这也是落地时最常见的踩坑点之一。
密钥管理是另一块硬骨头。把数据库密码明文写在 Git 仓库里显然不行,业界的标准做法是加密后再入库,代表方案是 Sealed Secrets 和 SOPS 加 age 的组合。Sealed Secrets 由控制器持有一对密钥,客户端加密后的 Secret 只有集群内控制器能解密,即使配置仓库完全公开也不泄密。SOPS 则只加密 YAML 中的 value 部分,加密后的文件依然保持可读的结构,diff 和评审体验更好。对于规模更大的团队,也可以让 GitOps 只负责部署不含密文的模板,真正的敏感数据交给 External Secrets Operator 从 Vault 等外部系统拉取。
当基础链路跑通之后,可以进一步引入渐进式交付。Argo Rollouts 和 Flagger 都能配合 GitOps 实现金丝雀发布:新版本先接收一小部分流量,指标正常再逐步放大,异常则自动回退。结合 Analysis 模板对接 Prometheus 指标,整个发布过程不需要人工盯着大盘判断,出错时回退速度也远快于人工响应。至此,从代码提交到镜像构建、配置更新、集群同步、灰度验证、自动回滚,一条完整的声明式交付闭环就建立起来了,集群管理也就真正从手工操作升级为了可持续演进的自动化体系。
GitOps声明式配置Kubernetes集群修改时间:2026-09-12 03:06:41