ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Kubernetes自动化运维实战:从集群部署到GitOps与故障自愈

Kubernetes自动化运维实战:从集群部署到GitOps与故障自愈 干了这么多年集群运维我一直觉得Kubernetes本身的设计哲学和自动化运维是天然绑定的。控制器循环、声明式API、控制器比对期望状态和实际状态这套机制本质上就是一个自动化的闭环。但真正把集群跑起来之后你会发现单靠Kubernetes内置的这套自愈能力远达不到自动化运维的完整要求。部署、升级、扩容、备份、告警、故障转移每一个环节都有大量的重复劳动和人工介入这些才是自动化运维真正要解决的问题。这篇东西不打算讲Kubernetes基础概念相关教程和《Kubernetes权威指南》这类书里都有。我想聊的是另一个角度当你的集群从个位数节点扩张到几十上百个节点当你开始同时维护开发、测试、生产多套环境当你的业务方频繁要求帮我扩一下这个服务怎么又挂了的时候自动化运维的边界在哪里、优先做什么、每一步怎么落地。这些内容适合已经有一定Kubernetes使用经验、想往平台化方向走的同学参考也适合正在被重复性运维工作折磨的同行做一个对照。1. 先想清楚自动化运维解决的是重复不是复杂很多人一上来就急着写脚本、上平台结果工具堆了一堆运维反而更累了。我自己的经验是动手之前先盘清楚手头的工作里哪些是高频重复、规则明确的哪些是低频复杂、需要人判断的。自动化只适合前者后者强上自动化就是在给自己挖坑。1.1 我盘点自动化场景时用的三个标准判断一个运维操作是否适合自动化我一般看三条第一这个操作是不是周期性重复发生的比如每天的备份巡检、每次发布都要执行的镜像替换第二操作步骤是否能够标准化就是说不依赖执行者个人经验的那些操作例如给节点打污点、驱逐Pod、拉出集群维护这类操作走固定流程就行第三执行失败时是否能被明确感知自动化脚本如果失败了必须有清晰的告警和日志兜底否则就是黑盒操作出了问题比手工操作更可怕。按照这三个标准去盘点日常的运维工作很快就能分清主次。比如集群组件的版本升级步骤非常固定——先备份etcd、再逐节点封锁、排空、升级、恢复调度完全适合自动化。又比如某个应用出现了OOMKill这时候就直接定位内存limit设置、查看监控曲线再决定怎么调这就是需要人判断的场景不应该一上来就写个自动重启的脚本掩盖问题。1.2 明确自动化的红线在哪里还有一个必须守住的边界涉及到不可逆数据操作、或者故障根因未定位时的尝试性恢复手动操作反而更安全。我见过有团队把kubectl delete pod做成了自动告警处理的一个环节Pod一异常就自动删掉重建表面上看集群很稳定实际上掩盖了真正的根因——往往是配置错了或者资源不够。这种自动化是负资产。真正合理的自动化运维体系在我看来是分层的底层是Kubernetes自身控制器的自愈能力中间层是部署、发布、扩缩容、备份这些可标准化流程的流水线化顶层才是告警分析、容量规划这类需要人和系统协同决策的部分。自动化不是要替代运维工程师而是把运维工程师从重复劳动里解放出来把精力放到架构优化和故障预防上。2. 从零到可用集群部署与节点纳管的自动化编排先说最基础也最容易被忽视的一块——集群本身的自动化部署。如果你的集群还是靠人对着文档敲命令搭起来的节点信息散落在Excel里那后面所有自动化都无从谈起。环境的一致性是一切自动化的地基。2.1 基础设施层用IaC统一管控我在实践里会把基础设施即代码作为第一步不管底层是物理机、虚拟机还是云主机用Terraform这一类IaC工具去统一纳管。节点规格、操作系统版本、磁盘配置、网络信息全部以代码形式保存在Git仓库里这样就保证了每次创建出来的节点无论是配置还是环境都完全一致。节点扩容的时候只需要修改节点数量的参数再执行一次流水线新的Worker节点就会自动加进来不会再出现那种上次装了个新内核导致节点加入集群后行为不一样的奇怪问题。对于多集群环境我更推荐用Git仓库来管理每个集群的声明配置。生产、预发、测试各有一套配置分目录存放拉分支改配置、合并主干触发应用。后来我在做节点模板时顺便会把/etc/hosts、内核参数、docker或containerd的配置都纳入进来避免新节点加入时因为配置漂移带来各种玄学问题。2.2 高可用控制平面的自动化构建控制平面的高可用是集群稳定性的基石这块我一般用Kubeadm配合负载均衡器来实现。Kubeadm天然支持多控制平面节点的部署方式配合Keepalived或者云厂商的负载均衡服务把API Server的访问入口统一起来。搭建过程做成脚本之后整个流程大概是这样的安装容器运行时和Kubeadm、Kubelet、Kubectl这几个核心组件在第一个控制平面节点上执行kubeadm init生成集群证书和配置文件这一步会输出后续节点加入所需的Token和证书哈希把生成的admin.conf、证书文件安全分发到其他控制平面节点其他控制平面节点通过kubeadm join --control-plane加入etcd会随之组成集群最后部署CNI网络插件比如Calico或Cilium并把Worker节点的加入命令模板化通过一个简单的交互式脚本或参数化脚本完成纳管。这套流程里有一个容易踩的坑etcd集群的成员信息。当你用脚本批量加入控制平面节点的时候一定要在每步之间检查etcd集群的健康状态etcdctl endpoint health跑一遍确认所有节点都healthy了再继续否则可能在一个节点加入失败后继续往下走导致整个集群不可用。我在脚本里加了一步等待和健康检查的循环宁可让它执行慢一点也不能在失败的情况下继续推进。2.3 GPU集群与异构节点的自动化纳管如果你的集群里有GPU节点自动化纳管时要做的工作会更多一些。GPU节点需要安装NVIDIA驱动和Container Toolkit还需要部署对应的Device Plugin才能让Pod调度到GPU资源上。我的做法是在节点初始化脚本里通过环境变量区分节点类型——普通计算节点和GPU节点走不同的初始化链路GPU节点额外做驱动安装和验证。所有GPU节点在加入集群后自动打上专用标签和污点比如gpu-typenvidia-a10和gputrue:NoSchedule需要GPU的工作负载通过nodeSelector或者节点亲和性来调度同时普通工作负载不会被调度到GPU节点上。这套逻辑做自动化之后业务方申请GPU资源就不再需要经过运维手动加节点了只需要提需求平台側把硬件准备好初始化脚本会自动把节点纳管进集群。3. 发布流程自动化GitOps落地的关键细节与回滚设计集群本身稳定了接下来最频繁的操作就是应用发布。这一块如果还停留在运维帮开发手动更新镜像的阶段效率太低而且容易出人为事故。我强烈建议把应用发布改造为GitOps模式这也是我实践下来收益最明显的一个自动化方向。3.1 Git仓库作为发布的唯一事实来源GitOps的核心思想很朴素Git仓库里存放的是集群期望状态的完整描述所有对集群的变更都通过修改Git仓库来发起集群中运行的operator负责把实际状态向期望状态收敛。这样做的好处是每个变更都有记录、有评审、可回滚而且环境和配置完全可审计。我使用的工具是ArgoCD它和Kubernetes的适配最自然。部署好ArgoCD之后为每个应用创建一个Application资源指定Git仓库路径和目标集群命名空间比如apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: order-service namespace: argocd spec: project: default source: repoURL: https://git.example.com/team-a/order-service-manifests.git targetRevision: main path: overlays/prod destination: server: https://kubernetes.default.svc namespace: prod syncPolicy: automated: prune: true selfHeal: true syncOptions: - CreateNamespacetrueautomated.prune和selfHeal这两个参数要特别注意。prune表示当Git仓库里删除了某个资源时集群里对应的资源也会被删除这保证了集群状态和Git仓库完全一致selfHeal表示当有人在集群里手动改了配置和Git仓库不一致时ArgoCD会自动把配置改回来。这两个参数是保证Git仓库作为唯一事实来源的关键但同时也意味着不能有人在集群里随手改东西否则会被强行纠正。3.2 CI与CD的流水线划分很多团队把CI和CD混在一条流水线里直接在构建镜像之后就执行kubectl set image这种做法在自动化运维视角下不是最佳实践。我习惯把它们拆开CI阶段只负责代码构建、单元测试、镜像扫描、镜像构建并推送镜像仓库CD阶段做的事情是更新Git仓库中的部署清单更新镜像tag之后交给ArgoCD自动同步。这样拆开之后的好处是镜像构建的失败不会影响正在运行的业务发布决定也变成了一个显式的改Git动作。代码合并进主干触发CICI完成后用自动化脚本提交一个新的commit把order-service的镜像tag从v1.2.0更新为v1.3.0ArgoCD检测到Git仓库变化后自动完成集群内的更新。整个过程发布的时间点、触发人、具体改动全部记录在Git历史里回溯问题非常方便。3.3 回滚策略一定要提前演练自动发布做得越顺畅回滚能力就越重要。因为你发布频率上去了出问题的概率也跟着上升这是正常的。我在ArgoCD的配置里会为每个应用设置syncPolicy中的自动回滚策略但更关键的是平时要演练回滚流程。GitOps模式下回滚操作非常轻量只需要把Git仓库里的镜像tag改回上一个稳定版本提交后等ArgoCD自动同步就行整个回滚过程不超过两分钟。但要注意的是如果应用在发布过程中修改了数据库结构直接回滚镜像可能是不够的需要结合业务的兼容性设计来决定是回滚还是向前修复。这是自动化救不了的问题需要架构层面做兼容设计比如数据库变更向前兼容、旧版本代码能识别新字段等。对于灰度发布我在生产环境用的是Argo Rollouts它支持金丝雀发布和蓝绿发布并且能够把Prometheus的指标接入发布决策——如果金丝雀版本的错误率超过阈值自动中止发布并回滚不需要人工干预。这块配置相对复杂但一旦跑通发布的安全性会有明显提升。4. 监控告警与故障自愈把半夜被叫醒变成告警自己处理自动化运维另一个大块是监控告警和故障自愈。一个集群如果没有完善的监控体系自动化运维就是盲人摸象。而Kubernetes本身的状态同步机制又决定了它非常适合做故障自愈——很多常见的故障其实是可以通过自动手段恢复的不需要运维半夜爬起来打个kubectl delete pod。4.1 监控数据的自动化采集与整合监控这套体系里我基本采用的是Prometheus技术栈通过kube-prometheus-stack一键部署涵盖了指标采集、告警规则、可视化面板和告警通知这几大组件。部署的时候有几个细节需要注意指标采集要覆盖三个层面节点层CPU、内存、磁盘、网络、Kubernetes资源层Pod、Deployment、Service、HPA等、应用层通过Pod注解自动发现采集端点kube-state-metrics这个组件单独部署一份它负责从Kubernetes API获取资源对象的状态很多关键告警都依赖它比如Pod反复重启、Deployment副本数不达标采集端的资源限制要提前规划节点越多Prometheus的内存占用涨得越快后面我会用Thanos或VictoriaMetrics做长期存储和横向扩展但初期单实例Prometheus配好落盘保留窗口也能顶住。告警规则我是从Grafana的开源告警规则库起步再根据实际情况调整比如节点内存使用率、磁盘即将写满、Pod长时间Pending、API Server延迟变高。规则不是越多越好关键是要保证告警准确率。宁愿少一点也不要每天告警轰炸到大家麻木否则真正的告警反而没人响应。4.2 告警通知的分级与路由告警做得好不好很大程度体现在谁在什么时间收到什么告警。我在Alertmanager里配置了多级路由严重级别比如节点NotReady、etcd故障、API Server不可用会同时发给值班人员、技术负责人并触发自动创建工单警告级别比如Pod重启次数超过阈值、磁盘使用率超过80%只发给当班同事工作时间内进行处理信息级别比如HPA扩缩容事件只记录到日志或对接消息平台不打扰人。这样配置之后告警疲劳大幅降低。关键告警走短信或电话通知普通告警只在值班群里出现运维人员不用时刻盯着屏幕。4.3 Kubernetes自愈机制与故障转移Kubernetes自身的自愈能力是自动化运维最基础的一环。它做的事情包括Pod异常退出后由ReplicaSet按期望副本数重建、节点失联超过阈值后自动驱逐节点上的Pod并调度到其他正常节点、Deployment滚动更新失败时自动暂停。这些机制不需要额外部署组件但需要你理解它们的触发条件。一个实践中的经验是不要随意调整节点故障相关的参数。比如--node-monitor-grace-period默认是40秒--pod-eviction-timeout是5分钟这些参数的调整会影响故障转移的灵敏度。调得太短网络抖动会导致大量Pod被驱逐调得太长故障恢复时间会变长。针对一般的内部集群默认参数基本是合理的除非你的网络环境出现过频繁的瞬时波动再视情况优化。对于节点级别的故障转移我补充一个常用的姿势当节点被判定为NotReady时用一条自动化脚本或一个CronJob定期检查超过阈值后自动给节点打上node.kubernetes.io/out-of-service污点触发云厂商的节点池自动替换。这个操作在裸金属机房同样适用可以把故障节点自动移出调度同时通知硬件维护同事处理。整个过程不需要人通过跳板机登录节点敲命令故障转移的时间能从小时级压缩到分钟级。5. 弹性伸缩与资源治理让集群的大小自动匹配业务集群的负载不可能一成不变业务高峰和低谷的资源需求差异极大。自动化运维要做到的是根据业务负载自动调整应用副本数和集群节点数让资源用量和业务需求实时匹配同时避免资源浪费。5.1 工作负载层面的HPA与VPAHPAHorizontal Pod Autoscaler是应用层弹性伸缩的主要手段原理是持续采集Pod的CPU、内存或自定义指标计算当前指标值相对目标值的比例再调整Deployment的副本数。targetReplicas ceil(currentReplicas * currentMetricValue / desiredMetricValue)这是HPA的计算逻辑我实际使用时会配合两个注意点。一个是为关键应用设置minReplicas和maxReplicas的合理范围不能因为指标短暂波动就无限扩容也不能收缩到连基础流量都扛不住。另一个是给HPA设置扩缩容的冷却和稳定窗口比如behavior里配置scaleDown的stabilizationWindowSeconds避免Pod数量在几分钟内来回抖动。VPAVertical Pod Autoscaler在实践中的应用场景相对有限因为调整CPU和内存request需要重建Pod对在线业务有中断风险。一般我建议只在开发环境或离线任务中使用VPA生产环境的关键在线业务HPA加上节点级自动伸缩已经能解决大部分问题。5.2 节点层面的cluster-autoscalerHPA解决了Pod副本数的问题但节点资源总量是有限的。如果集群里的Pod都因为节点资源不足而Pending这时就需要节点级的自动扩缩容。以云环境为例cluster-autoscaler会周期检查所有不可调度的Pod根据它们的资源需求触发节点池扩容同时在节点利用率持续低于阈值时触发缩容。配置cluster-autoscaler时有几个关键参数我直接说结论--scale-down-delay-after-add设置扩容之后等待多久才允许缩容避免刚加的节点立刻被缩掉我一般设成10到15分钟--scale-down-utilization-threshold节点利用率低于这个阈值才可能被缩容我一般设0.5左右--max-nodes-total单个节点池的最大节点数这个一定要设防止异常流量导致集群无限扩容账单爆炸的时候真的会睡不着。这里给一个简单示例调度一个扩容事件自动产生当一个Pod因为CPU资源不足而Pending时kube-scheduler输出0/5 nodes are available: 5 Insufficient cpucluster-autoscaler捕捉到这种状态后触发扩容。整个过程用户无感知业务自动恢复。5.3 保证关键业务在伸缩过程中不受影响自动扩缩容虽然方便但过程中要保证优先级的设计。我使用Pod优先级PriorityClass配合资源配额来区分关键业务和普通任务。例如支付网关这类核心链路的Pod优先级设置为高离线批处理任务优先级设置为低这样在资源紧张时scheduler会先驱逐低优先级Pod把节点资源让给高优先级业务。GPU集群的资源治理也类似但更敏感。GPU节点成本高且大部分GPU工作负载是不可中断的训练任务不能直接用简单的HPA去伸缩。我的做法是给GPU节点单独建节点池配合节点池级别的自动伸缩在训练任务提交时按需扩容GPU节点任务结束后缩容。训练任务的调度则使用Volcano这类批量调度组件它支持队列、优先级和资源预留在GPU场景下比默认调度器稳重得多。6. 日常运维事务自动化升级、备份、证书与配置漂移最后聊一聊日常运维事务的自动化。这部分内容看起来不如发布和弹性伸缩那么带感但在长期稳定性上影响很大。很多集群事故都发生在低频但高危的操作上比如版本升级、证书更新、备份恢复而这些恰恰是自动化能发挥大作用的地方。6.1 集群升级流程的流水线化Kubernetes的版本升级是一个典型的高危操作控制平面和节点分别有升级路径。我之前手工升级一个集群需要整整一个窗口期而且每次都提心吊胆。后来把升级流程沉淀成了自动化的流水线事前备份etcd快照和关键资源清单备份文件存到对象存储或远端而不是留在本地节点升级第一个控制平面节点验证集群核心功能正常这一步是金丝雀任何异常都需要停下来继续升级剩余控制平面节点逐节点执行kubeadm upgrade、kubeadm upgrade node等操作并确认节点Ready升级Worker节点采用逐节点cordon、drain、升级、uncordon的方式确保每个节点上的工作负载无感迁移到其他节点全部完成后运行自动化巡检脚本检查所有组件版本、节点状态、核心工作负载副本数是否正常。整个升级流水线在Jenkins或GitHub Actions里执行人工要做的只是选定目标版本并启动流水线。这里有个经验升级前一定要把etcd备份独立验证一下我当时有一次备份文件损坏没发现全靠演练时提前暴露了问题。备份只有在恢复演练验证过之后才算真正有效。6.2 备份恢复自动化与定时演练集群备份是自动化运维中防患于未然的典型场景。etcd是整个集群状态的核心必须定期备份应用数据可以结合Velero做整体备份包括Kubernetes资源对象和PV里的数据。Velero配合CronJob实现定时备份备份任务在指定时间触发完成后自动上传到对象存储。恢复演练我是每季度做一次专门启一个临时集群从备份数据里完整恢复一套环境出来验证可用性。手工做一次全量恢复可能需要大半天但因为是自动化流程整个演练耗时大幅缩短而且每次都把关键步骤记录下来不断优化恢复脚本。自动化备份本身并不复杂复杂的是恢复后怎么验证业务可用这个验证步骤一定也要自动化否则演练就只是跑了一个流程而已。另外证书管理的自动化也是一个容易忽略但一旦出错就很严重的事项。集群组件间的TLS证书通常有效期一年如果到期没更新kubelet与API Server的通信会全部中断。我用cert-manager管理所有TLS证书包括ingress证书和集群内部证书到期前自动续期。同时配了证书到期时间的告警提前30天、7天各触发一次防止cert-manager自动续期失效时无人察觉。6.3 配置漂移巡检与治理工具自动化运维做到后面你会发现最需要警惕的不是某一项操作没做而是环境在不知不觉中变了。配置漂移是分布式系统运维的老问题某个节点上手动改了一个配置文件、某个Secret被某个人手动更新了、某个RBAC权限被临时放宽了这些漂移如果不被发现积累到一定程度就会造成难以排查的故障。对配置漂移的治理我采用自动巡检加GitOps收敛的双重机制。ArgoCD的selfHeal会负责应用层配置的一致性而对于节点层的配置漂移我用Ansible的ad-hoc命令批量巡检所有节点的关键配置并和基线比对发现差异自动修复或告警。另外我还会用polaris这类工具定期扫描集群里的工作负载配置检查有没有违反最佳实践的地方比如没有设置资源limit、没有配置健康检查探针、使用了latest镜像tag等。这些巡检工具集成到定时任务里报告输出到一个专门的频道架构和运维的同学定期review。结尾的一点实际体会自动化运维这个方向看起来是工具和代码的问题实际上更像是一个持续抽象和收敛的过程。回头看看我自己的实践路径——从最早的集群部署自动化到发布流程GitOps化再到监控自愈和资源治理最后到日常运维事务的全面自动化每一步都是在解决一个具体的痛点上沉淀下来的。从来没有一个最佳实践能一步到位你可以先把最高频、最折磨人的操作自动化起来跑顺了再去覆盖下一个场景。一个很重要的心得是自动化之后故障演练要同步跟上尤其要把备份恢复、回滚、节点故障转移这些保命操作当成常态化演练来运行。自动化不代表系统万无一失它只是让操作更规范、更快、更少受人为因素影响。我见过太多环境是自动化跑得很欢但从来没有人验证过这些自动化脚本在灾难面前真的管用。最后分享一个小技巧自动化运维的所有脚本和配置文件我都要求团队里至少两个人都能讲清楚每一行的作用不能出现这个脚本只有某某人会改的情况。自动化本身是为了摆脱对个人的依赖如果最终变成依赖某个人维护的自动化脚本那就又绕回去了。
返回列表