关注 [腾讯云原生] 公众号, 后台回复 "容器"
即可下载 KubeCon 大会演讲 PPT
王涛, 腾讯云专家工程师, 从事 Kubernetes 容器平台的研发近 6 年, 目前主要负责腾讯海量自研业务容器化上云的平台研发. 在利用云原生技术构建 DevOps,ServiceMesh,AI, 大数据平台等场景有丰富经验.
腾讯会议, 一款提供灵活协作的线上会议解决方案. 其中大量的模块是有状态服务, 在使用 Kubernetes 为其进行容器化部署时, Pod 升级需保持共享内存, 长连接服务. 升级时只容忍 ms 级抖动, 需提供大规模分批灰度发布, 业务配额控制等能力, 并同时解决集群节点负载不均衡, 上万 Pods 的 Workload 的 HPA 性能差等问题. 这里将向大家介绍 TKEx 容器平台及其在灰度发布, 资源管理, 弹性伸缩等方面的能力.
海量规模下 Kubernetes 面临的挑战
在腾讯自研业务中, 已经有几百万核跑在 Kubernetes 上, 要在如此体量的容器场景提供可靠稳定的容器服务, 无论在底层, 集群能力, 运营或运维等各个方面都面临巨大挑战.
我们怎么进行容器可靠高性能的灰度发布? 尤其是在自研业务里面, 大量的服务是有状态的服务, 原生的 Kubernetes StatefulSet 已经无法满足我们如此大规模的容器发布需求.
调度层面需要做哪些优化, 从而保证在 Pod 漂移和重调度的过程中保证业务的稳定性.
在优化资源编排性能方面, 如何在整个平台层面和业务层面做好后台管理.
在大规模的弹性伸缩方面如何提供高性能和全面的弹性伸缩能力.
TKEx 容器平台简介
TKEx 容器平台的底层基于腾讯公有云的 TKE 和 EKS 两个产品, 它是使用 Kubernetes 原生的技术手段服务于腾讯内部的业务, 包括腾讯会议, 腾讯课堂, QQ 及腾讯看点等. TKEx 在灰度发布, 服务路由, 弹性伸缩, 容器调度, 资源管理, 多集群管理, 业务容灾, 在离线混部等方面做了大量工作, 比如:
通过 Kubernetes API/Contoller/Operator 的原生方式适配腾讯内部各种系统, 比如服务路由系统, CMDB,CI, 安全平台等.
通过声明式的方式, 对所有的托管业务进行生命周期管理.
支持在线业务, 大数据, AI 等类型作业.
实现在线业务和离线业务的混合部署, 同时提升整个资源的利用率.
通过优化 Linux 的内核, 增强资源底层隔离能力.
集成 Tencent Cloud Mesh(TCM) 服务为自研业务提供 ServiceMesh 服务.
在大规模的集群里面, 对弹性伸缩的各种组件进行改造和优化, 以保证它的性能和可用性.
基于业务产品维度, 提供多租户和配额管理能力.
下面是 TKEx 平台缩略版的架构图, 仅包括本次讨论的相关能力.
底层基于 TKE 和 EKS 两个产品, 在上层服务于在线业务, AI 训练以及大数据作业.
中间这四个框主要包括在应用和路由管理, 资源编排调度, 弹性伸缩, 混部. 下面会重点介绍其中前三个部分.
高效稳定的发布能力
业务没有大规模使用 StatefulSet 的滚动更新能力, 对于有状态服务来说, 原生的滚动更新机制的发布可控性太差, 对于 multi-zone 容灾部署的业务更是很难做精细化的发布策略. 我们提供了分批灰度发布策略供有状态服务使用, 约 80% 的 Workload 都选择了这种策略.
以一个业务分两批进行发布为例, 第一批升级两个 Pod, 用户可以指定是哪两个 Pod, 也可以按照一定比例指定第一批是 10%, 由平台自动选择 10% 的 Pod 进行灰度, 剩余 Pods 在第二批进行灰度.
自动分批机制: 如果 Pod 的探针完善且能真实反映业务是否可用, 用户可以使用自动分批机制, 上一批次完成后可通过自定义的批次时间间隔和健康检查机制自动进行下一批的灰度发布或者自动回滚.
手动分批机制: 用户也可以通过手动分批机制, 在上一批次灰度完成后, 可人为在业务层面确认上一批的灰度是否成功, 来决定是否触发下一批灰度还是回滚.
分批灰度发布更安全, 更可靠, 更可控的特性, 整个发布过程更灵活. 由于单个批次内所有选中 Pods 的更新都是并发的, 因此可以应付紧急快速发布的需求.
StatefulSetPlus 是我们用来实现分批灰度发布的 CRD, 它继承了 Kubernetes 原生的 StatefulSet 的所有能力, 并在此之上新增和优化了大量特性. StatefulSetPlus 主要提供的核心特性包括自动的以及手动的分批灰度发布, 在发布异常时可以进行全量一次回滚或者分批次的回滚. Pod 更新的策略支持两种形式, 一种是 Pod 重建的方式, 另一种是 Pod 的原地升级方式. 同时我们还提供了一些高级特性, 比如:
支持 Pod 升级过程中保持 Pod 使用的共享内存数据不丢失, 这个特性非常适合于像腾讯会议这样的音视频业务.
如果升级过程中触发了 Workload 的扩容, 那么扩容的时候会使用上一个好的版本进行扩容, 而不是像原生的 StatefulSet 和 Deployment 一样, 使用最新的镜像进行扩容. 因为最新的镜像版本有可能是不可用的, 扩容出来的 Pod 可服务型存在风险.
在存储编排方面, 我们继承了 StatefulSet 的 Per Pod Per PV 的特性, 同时也支持 Per Workload Per PV 的特性, 即单个 StatefulSetPlus 下面所有的 Pod 共享一个 PV, 也就是类似 Deployment 共享 PV 的模式.
在 StatefulSet 里面, 当节点出现异常, 比如出现了 NodeLost 的情况下, 出于有状态服务的可用性考虑, 不会进行 Pod 重建. 在 StatefulSetPlus 中, 监听到 NodeLost 后, 对应的 Pod 会自动漂移. 这还不够, 我们会通过 NPD 检测, 上报事件或 Patch Condition 快速发现节点异常, 对 StatefulSetPlus Pod 进行原地重建或者漂移等决策.
StatefulSetPlus 还有一个非常重要的特性, 就是它支持 ConfigMap 的版本管理以及 ConfigMap 的分批灰度发布, 这是决定 ConfigMap 能否大规模在生产中使用的关键能力.
这里特别介绍一下, 如何支持 Pod 升级过程中保持共享内存数据不丢失, 并且在升级过程中, 单个 Pod 只有毫秒级的服务抖动. 主要的实现原理就是在 Pod 里面, 通过一个占位容器和业务容器进行文件锁的抢占动作, 来实现升级过程中两个容器的角色进行快速切换.
动态的资源调度和管理
kubernetes 的调度原生是使用静态调度的方式, 在生产环境会出现集群里面各个节点的负载不均衡的情况, 并且造成很大的资源浪费.
动态调度器是我们自研的一个调度器扩展器, 主要任务是平衡集群中各个节点真实的负载, 在调度的时候, 将各个节点的真实负载纳入考量的范畴.
动态调度器必须要解决的一个技术点是调度热点的问题. 当集群中有一批节点负载比较低, 这时用户创建大量的 Pod, 这些 Pod 会集中调度到这些低负载的节点上面, 这将导致这些低负载节点在几分钟之后又会成为高负载节点, 从而影响这批节点上 Pod 的服务质量, 这种现象尤其在集群扩容后很容易出现. 我们自研的调度热点规避算法, 极大的避免了某个节点因为低负载被动态调度器调度后成为延迟性的高负载热点, 极少数高负载节点在 de-scheduler 中会基于 Node CPU 的历史监控进行节点降热操作..
我们希望能够快速地感知集群的异常情况, 包括 kubelet 异常, docker 异常, 内核死锁以及节点是否出现文件描述符即将耗尽的情况, 从而能在第一时间去做决策, 避免问题的恶化. 其中快速发现这个动作是由 Node Problem Detector(NPD) 组件负责的, NPD 组件是基于社区的 NPD 进行了大量的策略扩展.
NPD 检测到异常后, 除了 NPD 组件本身对节点自愈的动作之外, de-scheduler 还会基于异常事件和当前集群 / Workload 现状协助进行动作决策, 比如 Pod 驱逐, Container 原地重启. 这里要重点提一下, 我们基于 Self 算法的分布式的 Ping 检测, 能够快速发现节点的网络异常情况, 由 de-scheduler 对网络异常节点上的 Pods 进行漂移.
在腾讯内部, 产品的管理是分多个层级的, 因此在配额管理方面, 我们没有使用 Kubernetes 原生的 ResourceQuota 机制, 而是研发了 DynamicQuota CRD 来实现多层级的, 动态的面向业务的 Quota 管理.
比如从业务维度, 腾讯会议是一个产品, 腾讯课堂是一个产品, 每个产品下面都会有多级业务模块, 在做资源规划和配额管理的时候, 是基于产品维度的. 在实际部署的时候, 实际上 Workload 绑定到对应的 CMDB 的最后一级模块. 所以, 这里需要自动的将产品配额下发到 CMDB 多级模块的机制, 通过 DynamicQuota 不只是做资源使用上限的控制, 更重要的是保证这个业务有这么多配额可以用, 防止被其他业务抢占了.
当然这里还有一些关键问题, 比如为了避免资源浪费, 我们需要把一些产品的空闲资源借调给其他已经超过配额控制但是需要继续使用更多资源的业务, 这样配额就有了灵活的弹性.
同时我们也利用了 DynamicQuota 控制在线业务和离线业务占用资源的比例, 主要是为了保证在线业务始终会有一定的配额可以使用, 防止离线业务无限制侵占整个平台的资源, 同时也能更好的控制集群负载.
大规模和高性能的弹性伸缩
在扩缩容方面, 这里主要介绍纵向扩缩容和横向扩缩容做的工作. 社区的 VPA 不太适合很多腾讯的自研业务, 因为扩缩容都是基于 Pod 的重建机制, 在扩容效果和对业务的感知方面, 都不是很好.
我们自研了 Vertical Workload AutoScaler (VWA) CRD 用于 Pod 的垂直扩缩容, 主要解决的问题是:
当业务出现突发流量的时候, HPA 扩容不及时, 导致下面 Pod 的资源利用率暴涨, 进而引发业务的雪崩. VWA 有更快的响应速度, 并且不需要重建 Pod, 因此比 HPA 更快更安全.
业务在使用容器规格的时候, 经常把容器规格配置得比较高, Pod 资源使用率会比较低, 通过 VWA 自动进行降配, 优化资源利用率.
当节点出现高负载的情况下, 这个节点上面跑着在线和离线业务, 我们会通过 VWA 快速地对离线业务容器进行在线降配, 从而保证在线业务的服务质量.
这里面核心的特性, 包括提供原地升级容器规格的能力, 而不需要重建 Container, 性能上做了优化, 单集群能支持上千个 VWA 对象的扩缩容. 同时也支持 VWA 的个性化配置, 比如可以配置每一个 VWA 对象的循环同步周期, 每次扩容的最大比例以及缩容的最大比例等.
最后再介绍一下在 HPA 方面我们做的工作. Kubernetes 原生的 HPA Controller 是内置在 kube-controller-manager 里面的, 它存在着以下缺陷:
它不能独立部署, 如果集群中有成千上万的 HPA 对象, 原生 HPA Controller 是很难承受的, 稳定性也直接受限于 kube-controller-manager.
另外在性能方面, 原生 HPA Controller 在一个协程里面遍历所有 HPA 对象, 所以在大规模 HPA 场景下, 同步实时性得不到保证.
我们自研了一个 HPAPlus Controller, 它兼容了原生的 HPA 对象, 然后可以独立部署, 在性能方面类似 VWA 一样做了很多性能优化, 同时丰富了每个 HPA 对象可自定义的配置, 比如同步周期, 扩容比例, 容忍度等.
HPAPlus-Controller 还实现了与 CronHPA 和 VWA 进行联动决策, 比如当 VWA 持续扩缩容达到了所属节点的上限, 无法继续扩容的时候, 这个时候会自动托管给 HPA 触发横向扩容.
总结
腾讯自研业务海量规模, 除了文中介绍到弹性伸缩, 调度和资源管理, 灰度发布等方面面临的挑战外, 我们还在多集群管理, 在离线混部, ServiceMesh, 异构计算, AI / 大数据框架支持等多方面做了大量工作. 另外, TKEx 底层正在大量使用 EKS 弹性容器服务来提供更好的容器资源隔离能力, 弹性能力, 以实现真正的零集群运维成本和高资源利用率的目标.
技术交流群
扫描二维码,
添加小助手 (微信号: TKEplatform)
拉你入技术交流群,
和更多小伙伴一起交流云原生
汇聚腾讯云原生技术
云说新品, 云研新术, 云游新活, 云赏资讯
来源: https://www.qcloud.com/developer/article/1684628