K8s 集群节点在线率达到 99.9% 以上,扩容效率提高 50%,咱们作了这 3 个深度改造

点击下载《不同的 双11 技术:阿里巴巴经济体云原生实践》git

file

本文节选自《不同的 双11 技术:阿里巴巴经济体云原生实践》一书,点击上方图片便可下载!github

做者 | 张振(守辰)阿里云云原生应用平台高级技术专家数据库

导读:2019 年阿里巴巴核心系统 100% 以云原生方式上云,完美地支撑了 双11 大促。此次上云的姿式很不通常,不只是拥抱了 Kubernetes,并且还以拥抱 Kubernetes 为契机进行了一系列对运维体系的深度改造。api

Kubernetes 做为云原生的最佳实践,已经成为了事实上的容器编排引擎标准,Kubernetes 在阿里巴巴集团落地主要经历了四个阶段:缓存

  • 研发和探索:2017 年下半年阿里巴巴集团开始尝试使用 Kubernetes api 来改造内部自研平台,并开始了对应用交付链路的改造,以适配 Kubernetes;
  • 初步灰度:  2018 年下半年阿里巴巴集团和蚂蚁金服共同投入 Kubernetes 技术生态的研发,力求经过 Kubernetes 替换内部自研平台,实现了小规模的验证,支撑了当年部分 双11 的流量;
  • 云化灰度:  2019 年初阿里巴巴经济体开始进行全面上云改造,阿里巴巴集团经过从新设计 Kubernetes 落地方案,适配云化环境,改造落后运维习惯,在 618 前完成了云化机房的小规模验证;
  • 规模化落地:2019 年 618 以后,阿里巴巴集团内部开始全面推进 Kubernetes 落地,在大促以前完成了所有核心应用运行在 Kubernetes 的目标,并完美支撑了 双11 大考。

在这几年的实践中,一个问题始终萦绕在各个架构师的头脑中: 在阿里巴巴这么大致量、这么复杂的业务下, 遗留了大量传统的运维习惯以及支撑这些习惯的运维体系,落地 Kubernetes 到底要坚持什么?要妥协什么?要改变什么?服务器

本文将分享阿里巴巴这几年对于这些问题的思考。答案很明显:拥抱 Kubernetes 自己并非目的,而是经过拥抱 Kubernetes 撬动业务的云原生改造,经过 Kubernetes 的能力,治理传统运维体系下的沉疴顽疾,释放云弹性的能力,为业务的应用交付解绑提速。微信

在阿里巴巴的 Kubernetes 落地实践中,关注了下面几个关键的云原生改造:架构

面向终态改造

在阿里巴巴传统的运维体系下,应用的变动都是 PaaS 经过建立操做工单,发起工做流,继而对容器平台发起一个个的变动来完成的。并发

当应用发布时, PaaS 会从数据库中查到应用全部相关的容器,并针对每一个容器,向容器平台发起修改容器镜像的变动。每个变动实际上也是一个工做流,涉及到镜像的拉取、旧容器的中止和新容器的建立。工做流中一旦发生错误或者超时,都须要 PaaS 进行重试。通常而言,为了保证工单及时的完成,重试仅会执行几回,几回重试失败后,只能依靠人工处理。less

当应用缩容时,PaaS 会根据运维人员的输入,指定容器列表进行删除,一旦其中有容器由于宿主机异常的状况下删除失败或者超时,PaaS 只能反复重试,为了保证工单的结束,在重试必定次数后只能认为容器删除成功。若是宿主机后续恢复正常,被“删除”的容器颇有可能依然运行着。

传统的面向过程的容器变动一直存在以下问题没法解决:

  • 单个变动失败没法保证最终成功

例如,一旦容器镜像变动失败,PaaS 没法保证容器镜像的最终一致;一旦删除容器失败, 也没法保证容器最后真的被删除干净。两个例子都须要经过巡检来处理不一致的容器。而巡检任务由于执行较少,其正确性和及时性都很难保证;

  • 多个变动会发生冲突

例如应用的发布和应用的扩容过程须要加锁,不然会出现新扩的容器镜像未更新的状况。而一旦对变动进行加锁,变动的效率又会大幅降低。

Kubernetes 的能力提供了解决这个问题的机会。Kubernetes 的 workload 提供了声明式的 API 来修改应用的实例数和版本,workload 的控制器能够监听 pod 的实际状况,保证应用 pod 的实例数量和版本符合终态,避免了并发扩容和发布的冲突问题。Kubernetes 的 kubelet 会依据 pod 的 spec,反复尝试启动 pod,直到 pod 符合 spec 描述的终态。重试由容器平台内部实现,再也不和应用的工单状态绑定。

自愈能力改造

在阿里巴巴传统的运维体系下,容器平台仅生产资源,应用的启动以及服务发现是在容器启动后由 PaaS 系统来执行的,这种分层的方法给了 PaaS 系统最大的自由,也在容器化后促进了阿里巴巴第一波容器生态的繁荣。可是这种方式有一个严重的问题,即: 容器平台没法独立地去触发容器的扩缩容,须要和一个个 PaaS 来作复杂的联动,上层 PaaS 也须要作不少重复的工做。这妨碍了容器平台在宿主机发生故障、重启、容器中进程发生异常、卡住时的高效自愈修复,也让弹性扩缩容变得很是复杂。

在 Kubernetes 中经过容器的命令以及生命周期钩子,能够将 PaaS 启动应用以及检查应用启动状态的流程内置在了 pod 中;另外,经过建立 service 对象,能够将容器和对应的服务发现机制关联起来,从而实现容器、应用、服务生命周期的统一。容器平台再也不仅仅生产资源,而是交付能够直接为业务使用的服务。这极大地简化了上云以后故障自愈以及自动弹性扩缩容能力的建设, 真正地发挥了云的弹性能力。

另外,在宿主机发生故障的状况下,PaaS 传统上须要先对应用进行扩容,而后才删除宿主机上的容器。然而在大规模的集群下,咱们发现每每会卡在应用扩容这步。应用资源额度可能不够,集群内知足应用调度限制的空闲资源也可能不够,没法扩容就没法对宿主机上的容器进行驱逐,进而也没法对异常的宿主机进行送修,长此以往,整个集群很容易就陷入故障机器一大堆,想修修不了、想腾腾不动的困境之中。

在 Kubernetes 中对于故障机的处理要“简单和粗暴”得多,再也不要求对应用先扩容,而是直接把故障机上的容器进行删除,删除后才由负载控制器进行扩容。这种方案乍一听简直胆大妄为,落地 Kubernetes 的时候不少 PaaS 的同窗都很是排斥这种方法,认为这会严重影响业务的稳定性。事实上,绝大多数核心的业务应用都维护着必定的冗余容量,以便全局的流量切换或者应对突发的业务流量,临时删除必定量的容器根本不会形成业务的容量不足。

咱们所面临的关键问题是如何肯定业务的可用容量,固然这是个更难的问题,但对于自愈的场景彻底不须要准确的容量评估,只须要一个能够推进自愈运转的悲观估计就能够。在 Kubernetes 中能够经过 PodDisruptionBudget 来定量地描述对应用的可迁移量,例如能够设置对应用进行驱逐的并发数量或者比例。这个值能够参考发布时的每批数量占比来设置。假如应用发布通常分 10 批,那么能够设置 PodDisruptionBudget 中的 maxUnavailable 为 10%(对于比例,若是应用只有 10 个之内的实例,Kubernetes 仍是认为能够驱逐 1 个实例)。万一应用真的一个实例都不容许驱逐呢?那么对不起,这样的应用是须要改造以后才能享受上云的收益的。通常应用能够经过改造自身架构,或者经过 operator 来自动化应用的运维操做,从而容许实例的迁移。<

不可变基础设施改造

Docker 的出现提供了一种统一的应用交付形式,经过把应用的二进制、配置、依赖统一在构建过程当中打到了镜像中, 经过使用新的镜像建立容器,并删除掉旧容器就完成了应用的变动。Docker 在交付应用时和传统基于软件包或者脚本的交付方式有一个重大区别,就是强制了容器的不可变,想要变动容器只能经过新建立容器来完成,而每一个新容器都是从应用同一个镜像建立而来,确保了一致性,从而避免了配置漂移,或者雪花服务器的问题。

Kubernetes 进一步强化了不可变基础设施的理念,在默认的滚动升级过程当中不但不会变动容器,并且还不会变动pod。每次发布,都是经过建立新的 pod,并删除旧的 pod 来完成,这不只保证了应用的镜像统一,还保证了数据卷、资源规格以及系统参数配置都是和应用模板的 spec 保持一致。

另外,很多应用都有比较复杂的结构,一个应用实例可能同时包含多个团队独立开发的组件。 好比一个应用可能包括了业务相关的应用程序服务器,也包括了基础设施团队开发的日志采集进程,甚至还包括了第三方的中间件组件。这些进程、组件若是想要独立发布就不能放在一个应用镜像中,为此 Kubernetes 提供了多容器 pod 的能力,能够在一个 pod 中编排多个容器,想要发布单个组件,只须要修改对应容器的镜像便可。

不过,阿里巴巴传统的容器形态是富容器,即应用程序服务器,以及日志采集进程等相关的组件都部署在一个大的系统容器中,这形成了日志采集等组件的资源消耗没法单独限制,也没法方便地进行独立升级。所以,在阿里巴巴此次上云中,开始把系统容器中除业务应用外的其余组件都拆分到独立的 sidecar 容器,咱们称之为轻量化容器改造。改造后,一个 pod 内会包括一个运行业务的主容器、一个运行着各类基础设施 agent 的运维容器,以及服务网格等的sidecar容器。轻量化容器以后, 业务的主容器就能以比较低的开销运行业务服务,从而更方便进行 serverless 的相关改造。

不过,Kubernetes 默认的滚动升级过程过于僵硬地执行了不可变基础设施的理念,致使对多容器 pod 的能力支持有严重的缺失。虽然能够在一个 pod 中编排多个容器,但若是要发布 pod 中的一个容器,在实际执行发布时,不只会重建待发布的容器,还会把整个 pod 都删除,然后重调度、再重建。这意味着假如要升级基础设施的日志采集组件,会致使其余组件,特别是业务的应用服务器被一块儿删除重启,从而干扰到正常的业务运行。所以,多个组件的变动依然没有解耦。

对业务而言,假如 pod 中有本地缓存的组件,而每次业务的发布都会重启缓存进程,这会致使业务发布期间缓存的命中率大幅降低,影响性能甚至用户的体验;另外,若是基础设施、中间件等团队的组件升级都和业务的组件升级绑定在一块儿,这会给技术的迭代更新带来巨大的阻碍。假设负责中间件的团队推出了新的 service mesh 版本, 而为了升级 mesh 还须要央求一个个业务发布才能更新 mesh 组件,那么中间件的技术升级就会大大减速。

所以,相比 pod 层次的不可变,咱们认为坚持容器级别的不可变原则,更能发挥 Kubernetes 多容器 pod 的技术优点。为此,咱们建设了支持应用发布时只原地修改 pod 中部分容器的能力,特别地建设了支持容器原地升级的工做负载控制器,并替换 Kubernetes 默认的 deployment 和 statefulset 控制器做为内部的主要工做负载。

另外,还建设了支持跨应用进行 sidecar 容器升级的 sidecarset, 方便进行基础设施以及中间件组件的升级。此外,经过支持原地升级还带来了集群分布肯定性、加速镜像下载等的额外优点。这部分能力,咱们已经经过 OpenKruise 项目开源出来。OpenKruise 中的 Kruise 是 cruise的谐音,'K' for Kubernetes, 寓意 Kubernetes 上应用的自动巡航,满载着阿里巴巴多年应用部署管理经验和阿里巴巴经济体云原生化历程的最佳实践。目前,OpenKruise 正在计划发布更多的 Controller 来覆盖更多的场景和功能,好比丰富的发布策略、金丝雀发布、蓝绿发布、分批发布等等。

总结

今年咱们实现了 Kubernetes 的规模化落地,经受了 双11 大促真实场景的考验。像阿里巴巴这样有着大量存量应用的场景,落地 K8s 并无捷径,咱们经受住了快速规模化落地的诱惑,没有选择兼容和妥协落后的运维习惯,而是选择深蹲打好基础、选择深挖云原生价值。接下来,咱们将继续推进更多应用的云原生改造,特别是有状态应用的改造,让有状态应用的部署和运维更加高效;另外,还将推进整个应用交付链路的云原生改造,让应用交付更加高效和标准化。

file

本书亮点

  • 双11 超大规模 K8s 集群实践中,遇到的问题及解决方法详述
  • 云原生化最佳组合:Kubernetes+容器+神龙,实现核心系统 100% 上云的技术细节
  • 双 11 Service Mesh 超大规模落地解决方案

“ 阿里巴巴云原生微信公众号(ID:Alicloudnative)关注微服务、Serverless、容器、Service Mesh等技术领域、聚焦云原生流行技术趋势、云原生大规模的落地实践,作最懂云原生开发者的技术公众号。”

更多相关信息,关注“阿里巴巴云原生”

相关文章
相关标签/搜索