【架构实战】GitOps实践:让运维更优雅

【架构实战】GitOps实践:让运维更优雅

字数统计:约3600字

一、真实故事引入:一次误删引发的运维革命

2024年春天,我们团队负责维护一个拥有23个微服务的K8s生产集群,当时的运维方式还停留在"半自动化"阶段:修改ConfigMap、调整Deployment副本数、更新镜像版本等操作,都需要运维人员登录跳板机,手动执行kubectl apply -f命令。

有一次,新入职的运维同学在处理一个紧急需求时,误执行了kubectl delete deployment order-service -n prod,导致订单服务整个被删除,集群中订单相关的Pod全部消失,线上订单功能瘫痪了12分钟。虽然我们通过etcd备份快速恢复了Deployment,但这次事故让我们惊出一身冷汗------如果备份不是最新的,或者误操作的是数据库相关的资源,后果不堪设想。

事故复盘时我们意识到:所有的配置变更都不应该直接操作集群,而应该像管理代码一样管理配置,所有的变更都有记录、可回滚。于是我们引入了GitOps理念,用Argo CD作为核心工具,把所有的K8s资源配置都存储在Git仓库中,从此运维变成了"提交PR、合并代码"的简单操作,再也没出现过误删、配置不一致的问题。

二、概念原理:GitOps到底是什么?

GitOps是Weaveworks在2017年提出的一种云原生运维理念,核心思想是"把Git作为系统的唯一事实来源",所有的系统配置、应用部署、环境变更都通过Git来管理,通过自动化工具将Git中的配置同步到生产环境。

2.1 GitOps四大核心原则

  1. 声明式配置:所有的系统状态都用声明式的配置文件(如K8s的YAML)描述,而不是命令式的脚本
  2. 版本控制为唯一真相源:所有的配置都存储在Git仓库中,只有Git中的配置才是合法的,任何直接修改集群的操作都会被自动纠正
  3. 自动化同步:有专门的工具(如Argo CD、Flux)自动监听Git仓库的变更,将配置同步到目标集群
  4. 闭环自愈:当集群的实际状态和Git中的期望状态不一致时,自动化工具会自动纠正,确保状态一致

2.2 GitOps vs 传统CI/CD

很多人会混淆GitOps和传统CI/CD,两者的核心区别:

  • 传统CI/CD:聚焦"构建→测试→部署"的流程,部署是流程的终点,部署后流程结束
  • GitOps:聚焦"配置管理→自动同步→状态保持",部署只是同步的一个环节,之后会持续监控状态一致性

两者不是替代关系,而是互补:CI/CD负责构建制品,GitOps负责部署和管理制品的生命周期。

2.3 核心工具选型

目前主流的GitOps工具有两个:

  • Argo CD:Weaveworks开源,UI友好,支持多集群,可视化程度高,社区活跃
  • Flux CD:CNCF毕业项目,轻量级,和K8s原生集成更好,适合云原生深度用户

我们选择了Argo CD,主要是因为它的UI界面对非技术人员更友好,且支持多租户管理。

三、配置代码:从零搭建GitOps体系

3.1 部署Argo CD到K8s集群

bash 复制代码
# 1. 创建专用命名空间
kubectl create namespace argocd

# 2. 部署Argo CD(稳定版本)
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

# 3. 等待所有Pod就绪
kubectl wait --for=condition=ready pod -l app.kubernetes.io/name=argocd-server -n argocd --timeout=300s

# 4. 获取初始管理员密码
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d

# 5. 暴露Argo CD UI(临时用NodePort,生产建议用Ingress)
kubectl patch svc argocd-server -n argocd -p '{"spec": {"type": "NodePort"}}'

3.2 配置Git仓库与Application

我们的GitOps配置仓库结构采用base + overlays的kustomize标准结构:

复制代码
gitops-config/
├── base/
│   ├── coupon-service/
│   │   ├── deployment.yaml
│   │   ├── service.yaml
│   │   └── kustomization.yaml
│   └── order-service/
│       ├── deployment.yaml
│       ├── service.yaml
│       └── kustomization.yaml
└── overlays/
    ├── test/
    │   ├── coupon-service/
    │   │   ├── patch-replicas.yaml  # 测试环境2副本
    │   │   └── kustomization.yaml
    │   └── order-service/
    │       ├── patch-replicas.yaml
    │       └── kustomization.yaml
    └── prod/
        ├── coupon-service/
        │   ├── patch-replicas.yaml  # 生产环境5副本
        │   ├── patch-resources.yaml # 生产环境资源限制更高
        │   └── kustomization.yaml
        └── order-service/
            ├── patch-replicas.yaml
            └── kustomization.yaml

base/coupon-service/kustomization.yaml示例

yaml 复制代码
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - deployment.yaml
  - service.yaml
commonLabels:
  app: coupon-service

overlays/prod/coupon-service/kustomization.yaml示例

yaml 复制代码
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
bases:
  - ../../../base/coupon-service
patches:
  - path: patch-replicas.yaml
  - path: patch-resources.yaml

patch-replicas.yaml示例

yaml 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: coupon-service
spec:
  replicas: 5

3.3 创建Argo CD Application

我们通过Argo CD的CRD(自定义资源)来管理每个应用的同步规则,创建coupon-service-prod.yaml

yaml 复制代码
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: coupon-service-prod
  namespace: argocd
spec:
  project: default
  # 配置源:Git仓库信息
  source:
    repoURL: https://gitlab.example.com/infra/gitops-config.git
    targetRevision: main
    path: overlays/prod/coupon-service
    # 如果用kustomize,需要指定kustomize版本
    kustomize:
      version: v1.27.0
  # 目标集群信息
  destination:
    server: https://kubernetes.default.svc  # 默认是Argo CD所在的集群,跨集群需要配置集群凭证
    namespace: prod
  # 同步策略
  syncPolicy:
    automated:
      prune: true      # 自动删除Git中不存在的资源
      selfHeal: true   # 当集群状态不一致时自动纠正
    syncOptions:
    - CreateNamespace=true  # 如果目标命名空间不存在则自动创建
    - PrunePropagationPolicy=foreground
  # 健康检查
  ignoreDifferences:
  - group: apps
    kind: Deployment
    jsonPointers:
    - /spec/replicas  # 忽略副本数的差异(如果需要手动扩缩容的话)

部署这个Application:

bash 复制代码
kubectl apply -f coupon-service-prod.yaml

四、实战案例:用GitOps管理23个微服务的完整流程

我们的生产集群有23个微服务,所有配置都存储在gitops-config仓库中,完整流程如下:

4.1 日常变更流程(以调整优惠券服务副本数为例)

  1. 运维或开发人员在gitops-config仓库中,修改overlays/prod/coupon-service/patch-replicas.yaml的副本数从5调整为8
  2. 提交PR到main分支,经过团队code review后合并
  3. Argo CD每3分钟自动检测Git仓库变更(也可配置Webhook即时触发)
  4. 检测到变更后,Argo CD对比Git中的期望状态和集群中的实际状态,发现副本数不一致
  5. Argo CD自动执行kubectl set replicas deployment/coupon-service 8 -n prod
  6. 同步完成后,Argo CD UI显示"Healthy"状态,同时发送企业微信通知

整个过程不需要登录任何服务器,从提交代码到变更生效,最快1分钟完成,且所有的变更都有Git提交记录,可审计、可回滚。

4.2 紧急回滚场景

有一次我们上线一个新版本的订单服务,发现有一个严重的bug,需要回滚到上一个版本:

  1. 在Git仓库中找到上一个版本的commit hash:a1b2c3d
  2. 执行git revert a1b2c3d或者直接git reset --hard a1b2c3d(根据团队规范)
  3. 合并到main分支,Argo CD自动同步,将订单服务回滚到上一个版本
  4. 整个过程5分钟完成,比原来的kubectl rollout undo更可追溯,因为Git中有明确的回滚记录

4.3 多环境管理

我们的配置仓库有testpre-prodprod三个环境的overlays,修改配置时只需要同步修改三个目录下的文件,或者用一个通用的base加环境特定的patch,避免配置漂移。Argo CD中可以直观看到每个环境的应用状态,一键同步某个环境的所有应用。

五、踩坑实录:GitOps落地过程中的那些坑

5.1 Git仓库权限配置错误

  • 现象 :Argo CD同步时报permission denied错误,无法拉取Git仓库
  • 原因:Argo CD使用的SSH密钥没有Git仓库的读取权限
  • 解决
    1. 在Argo CD中创建Secret存储SSH私钥:kubectl create secret generic git-creds --from-file=ssh-privatekey=~/.ssh/id_rsa -n argocd

    2. 在Application中引用这个Secret:

      yaml 复制代码
      source:
        repoURL: git@gitlab.example.com:infra/gitops-config.git
        targetRevision: main
        path: overlays/prod/coupon-service
        helm:
          # 如果是Helm的话
        kustomize:
          # 如果是kustomize的话
        # 配置凭证
        auth:
          sshPrivateKeySecret:
            name: git-creds
            key: ssh-privatekey

5.2 同步时资源冲突

  • 现象 :同步时报object is being deleted错误,无法更新资源
  • 原因:之前手动删除了某个资源,Argo CD还在处理删除流程,新的同步请求冲突
  • 解决 :等待删除流程完成,或者手动删除Argo CD中的资源缓存:argocd app terminate-op coupon-service-prod

5.3 镜像版本漂移问题

  • 现象:有时候发现集群中的镜像版本和Git中的不一致,Argo CD没有自动纠正
  • 原因 :我们在Application中配置了ignoreDifferences忽略了镜像版本的差异,导致Argo CD不检测镜像变化
  • 解决 :去掉不必要的ignoreDifferences配置,只忽略确实需要手动调整的部分(如副本数)

5.4 Secret管理难题

  • 现象:K8s的Secret是base64编码,不是加密,不能直接存在Git中

  • 解决 :引入Bitnami SealedSecrets,将加密后的Secret存在Git中,Argo CD同步时,SealedSecrets控制器自动解密成正常的Secret:

    bash 复制代码
    # 安装SealedSecrets控制器
    kubectl apply -f https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.24.0/controller.yaml
    
    # 加密Secret
    kubectl create secret generic db-secret --from-literal=username=admin --from-literal=password=123456 --dry-run=client -o yaml | kubeseal -o yaml > sealed-db-secret.yaml

    sealed-db-secret.yaml存在Git中即可,安全且可追溯。

5.5 跨集群同步问题

  • 现象:Argo CD部署在集群A,要同步配置到集群B,报连接超时
  • 原因:集群B的API Server地址是内网地址,Argo CD所在的集群A无法访问
  • 解决:在Argo CD中配置集群B的kubeconfig,或者给集群B的API Server配置公网访问(生产不建议),或者用VPC对等连接打通两个集群的网络。

六、总结与思考

6.1 核心总结

GitOps让我们实现了"运维即代码",核心价值:

  • 可追溯:所有变更都有Git提交记录,谁改了什么、什么时候改的、为什么改,一目了然
  • 可回滚 :改错了只需要git revert,不需要手动操作集群,回滚时间从原来的30分钟缩短到5分钟
  • 减少人为错误:杜绝直接操作集群的行为,所有变更都经过code review和自动化同步
  • 环境一致性:测试、预发、生产环境的配置都来自同一个base,避免配置漂移

6.2 思考题

  1. GitOps适合所有场景吗?比如有状态服务(数据库、消息队列)的配置是否适合用GitOps管理?
  2. 如果Git仓库被恶意篡改,如何防止错误的配置同步到生产环境?(提示:签名验证、分支保护规则)
  3. GitOps和IaC(基础设施即代码)是什么关系?如何结合使用?

6.3 个人观点

GitOps不是什么高深的技术,而是一种"把运维当代码管"的理念,它让运维变得更优雅、更可控。但落地GitOps也不是一蹴而就的,需要团队转变理念:

  • 开发人员要学习写K8s YAML,不能再只关注代码
  • 运维人员要从"执行命令的人"变成"维护Git配置和自动化工具的人"
  • 团队要建立完善的Git workflow,比如分支保护、PR review、自动化测试

另外,GitOps工具不是万能的,Argo CD和Flux各有优劣,选择适合自己团队的才是最好的。对于小团队,如果只有几个服务,用Flux更轻量;对于中大型团队,Argo CD的UI和多租户能力更有优势。

相关推荐
执笔论英雄6 小时前
GPU内存架构-DSMEM与L2
java·spring·架构
ting94520006 小时前
专用 ASIC 推理云平台:面向通用计算场景的 GPU 训练架构替代方案深度技术解析
人工智能·架构
modelmd6 小时前
虚拟机与容器的区别:从架构到应用场景的深度解析
架构
2601_957879336 小时前
自媒体内容矩阵的团队协作架构:从权限隔离到素材流转的工程化实践
矩阵·架构·媒体
终端行者6 小时前
企业级Jenkins Pipeline 实战 Docker构建+Ansible发布
ci/cd·docker·ansible·jenkins
Joy T6 小时前
【Web3】Hardhat工程架构中Solidity与TypeChain的协作机制
git·架构·typescript·web3·智能合约·hardhat·typechain
Traving Yu6 小时前
多租户SaaS架构
架构
运维瓦工7 小时前
DevOps 生态介绍(四):Sonarqube&jacoco 与jenkins集成使用
运维·jenkins·devops