【架构实战】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四大核心原则声明式配置所有的系统状态都用声明式的配置文件如K8s的YAML描述而不是命令式的脚本版本控制为唯一真相源所有的配置都存储在Git仓库中只有Git中的配置才是合法的任何直接修改集群的操作都会被自动纠正自动化同步有专门的工具如Argo CD、Flux自动监听Git仓库的变更将配置同步到目标集群闭环自愈当集群的实际状态和Git中的期望状态不一致时自动化工具会自动纠正确保状态一致2.2 GitOps vs 传统CI/CD很多人会混淆GitOps和传统CI/CD两者的核心区别传统CI/CD聚焦构建→测试→部署的流程部署是流程的终点部署后流程结束GitOps聚焦配置管理→自动同步→状态保持部署只是同步的一个环节之后会持续监控状态一致性两者不是替代关系而是互补CI/CD负责构建制品GitOps负责部署和管理制品的生命周期。2.3 核心工具选型目前主流的GitOps工具有两个Argo CDWeaveworks开源UI友好支持多集群可视化程度高社区活跃Flux CDCNCF毕业项目轻量级和K8s原生集成更好适合云原生深度用户我们选择了Argo CD主要是因为它的UI界面对非技术人员更友好且支持多租户管理。三、配置代码从零搭建GitOps体系3.1 部署Argo CD到K8s集群# 1. 创建专用命名空间kubectl create namespace argocd# 2. 部署Argo CD稳定版本kubectl apply-nargocd-fhttps://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml# 3. 等待所有Pod就绪kubectlwait--forconditionready pod-lapp.kubernetes.io/nameargocd-server-nargocd--timeout300s# 4. 获取初始管理员密码kubectl-nargocd get secret argocd-initial-admin-secret-ojsonpath{.data.password}|base64-d# 5. 暴露Argo CD UI临时用NodePort生产建议用Ingresskubectl patch svc argocd-server-nargocd-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.yamlbase/coupon-service/kustomization.yaml示例apiVersion:kustomize.config.k8s.io/v1beta1kind:Kustomizationresources:-deployment.yaml-service.yamlcommonLabels:app:coupon-serviceoverlays/prod/coupon-service/kustomization.yaml示例apiVersion:kustomize.config.k8s.io/v1beta1kind:Kustomizationbases:-../../../base/coupon-servicepatches:-path:patch-replicas.yaml-path:patch-resources.yamlpatch-replicas.yaml示例apiVersion:apps/v1kind:Deploymentmetadata:name:coupon-servicespec:replicas:53.3 创建Argo CD Application我们通过Argo CD的CRD自定义资源来管理每个应用的同步规则创建coupon-service-prod.yamlapiVersion:argoproj.io/v1alpha1kind:Applicationmetadata:name:coupon-service-prodnamespace:argocdspec:project:default# 配置源Git仓库信息source:repoURL:https://gitlab.example.com/infra/gitops-config.gittargetRevision:mainpath: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:-CreateNamespacetrue# 如果目标命名空间不存在则自动创建-PrunePropagationPolicyforeground# 健康检查ignoreDifferences:-group:appskind:DeploymentjsonPointers:-/spec/replicas# 忽略副本数的差异如果需要手动扩缩容的话部署这个Applicationkubectl apply-fcoupon-service-prod.yaml四、实战案例用GitOps管理23个微服务的完整流程我们的生产集群有23个微服务所有配置都存储在gitops-config仓库中完整流程如下4.1 日常变更流程以调整优惠券服务副本数为例运维或开发人员在gitops-config仓库中修改overlays/prod/coupon-service/patch-replicas.yaml的副本数从5调整为8提交PR到main分支经过团队code review后合并Argo CD每3分钟自动检测Git仓库变更也可配置Webhook即时触发检测到变更后Argo CD对比Git中的期望状态和集群中的实际状态发现副本数不一致Argo CD自动执行kubectl set replicas deployment/coupon-service 8 -n prod同步完成后Argo CD UI显示Healthy状态同时发送企业微信通知整个过程不需要登录任何服务器从提交代码到变更生效最快1分钟完成且所有的变更都有Git提交记录可审计、可回滚。4.2 紧急回滚场景有一次我们上线一个新版本的订单服务发现有一个严重的bug需要回滚到上一个版本在Git仓库中找到上一个版本的commit hasha1b2c3d执行git revert a1b2c3d或者直接git reset --hard a1b2c3d根据团队规范合并到main分支Argo CD自动同步将订单服务回滚到上一个版本整个过程5分钟完成比原来的kubectl rollout undo更可追溯因为Git中有明确的回滚记录4.3 多环境管理我们的配置仓库有test、pre-prod、prod三个环境的overlays修改配置时只需要同步修改三个目录下的文件或者用一个通用的base加环境特定的patch避免配置漂移。Argo CD中可以直观看到每个环境的应用状态一键同步某个环境的所有应用。五、踩坑实录GitOps落地过程中的那些坑5.1 Git仓库权限配置错误现象Argo CD同步时报permission denied错误无法拉取Git仓库原因Argo CD使用的SSH密钥没有Git仓库的读取权限解决在Argo CD中创建Secret存储SSH私钥kubectl create secret generic git-creds --from-filessh-privatekey~/.ssh/id_rsa -n argocd在Application中引用这个Secretsource:repoURL:gitgitlab.example.com:infra/gitops-config.gittargetRevision:mainpath:overlays/prod/coupon-servicehelm:# 如果是Helm的话kustomize:# 如果是kustomize的话# 配置凭证auth:sshPrivateKeySecret:name:git-credskey:ssh-privatekey5.2 同步时资源冲突现象同步时报object is being deleted错误无法更新资源原因之前手动删除了某个资源Argo CD还在处理删除流程新的同步请求冲突解决等待删除流程完成或者手动删除Argo CD中的资源缓存argocd app terminate-op coupon-service-prod5.3 镜像版本漂移问题现象有时候发现集群中的镜像版本和Git中的不一致Argo CD没有自动纠正原因我们在Application中配置了ignoreDifferences忽略了镜像版本的差异导致Argo CD不检测镜像变化解决去掉不必要的ignoreDifferences配置只忽略确实需要手动调整的部分如副本数5.4 Secret管理难题现象K8s的Secret是base64编码不是加密不能直接存在Git中解决引入Bitnami SealedSecrets将加密后的Secret存在Git中Argo CD同步时SealedSecrets控制器自动解密成正常的Secret# 安装SealedSecrets控制器kubectl apply-fhttps://github.com/bitnami-labs/sealed-secrets/releases/download/v0.24.0/controller.yaml# 加密Secretkubectl create secret generic db-secret --from-literalusernameadmin --from-literalpassword123456--dry-runclient-oyaml|kubeseal-oyamlsealed-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 思考题GitOps适合所有场景吗比如有状态服务数据库、消息队列的配置是否适合用GitOps管理如果Git仓库被恶意篡改如何防止错误的配置同步到生产环境提示签名验证、分支保护规则GitOps和IaC基础设施即代码是什么关系如何结合使用6.3 个人观点GitOps不是什么高深的技术而是一种把运维当代码管的理念它让运维变得更优雅、更可控。但落地GitOps也不是一蹴而就的需要团队转变理念开发人员要学习写K8s YAML不能再只关注代码运维人员要从执行命令的人变成维护Git配置和自动化工具的人团队要建立完善的Git workflow比如分支保护、PR review、自动化测试另外GitOps工具不是万能的Argo CD和Flux各有优劣选择适合自己团队的才是最好的。对于小团队如果只有几个服务用Flux更轻量对于中大型团队Argo CD的UI和多租户能力更有优势。