腾讯会议全量上TKEx容器平台的技术实践

原创
2020/12/26 17:00
阅读数 2.9K

自930以来,腾讯全面推进 “开源协同,自研上云”。公司各个BG的上云活动如火如荼进行了一年多了,2020年总办对自研上云提出更高的要求:要充分发挥云的优势,让应用更好地生于云长于云,基于TKE进行云原生上云的方案得到一致认可。腾讯会议经历过疫情期间的锤炼,无论是在用户规模,还是在计算资源规模方面,都是非常庞大的,因此通过云原生技术提升研发和运维效率势在必行。这里我将为大家揭秘TKEx-CSIG平台为支持腾讯会议全量云原生化上云背后的技术实践。

项目背景

自930以来,公司全面推进 “开源协同,自研上云”。公司各个BG的上云活动如火如荼进行了一年多了,2020年总办对自研上云提出更高的要求:要充分发挥云的优势,让应用更好地生于云长于云,基于TKE进行云原生上云的方案得到一致认可。腾讯会议经历过疫情期间的锤炼,无论是在用户规模,还是在计算资源规模方面,都是非常庞大的,因此通过云原生技术提升研发和运维效率势在必行。这里我将为大家揭秘TKEx-CSIG平台为支持腾讯会议全量云原生化上云背后的技术实践。

腾讯会议业务特性

腾讯会议核心模块二十多个,包括媒体代理、混音、接口机等。这些模块大多具备如下特性:

  • 使用IPC共享内存,可能有上GB的有状态数据,升级时不能丢失;
  • 单个模块最多的实例数超过1万;
  • 南京、上海等多地域部署;
  • 部分模块使用自研配置中心管理服务的路由;
  • 部分模块要求使用EIP;

这些业务特性使其在TKE管理上面临巨大挑战,既要尽量兼容这些业务特性,也要保持使用镜像发布和升级的云原生准则。TKEx-CSIG抽象出这些特性背后的需求,在灰度发布、容器网络、多地域多集群工作负载管理等方面进行了增强和优化,抽象出了通用的平台能力,其他有类似需求的业务也能适用。

如何保证有状态服务的升级只有ms级抖动

拒绝胖容器模式(把容器当虚拟机用)是TKEx-CSIG平台的底线,之前对接织云PKG包发布如此,腾讯会议容器化上云也是如此。然而会议研发要求像CVM部署一样,提供像进程重启一样的ms级业务抖动,这也是会议容器化上云最有挑战性的一点。

TKEx-CSIG平台虽然在灰度发布能力上做了持续的技术沉淀,但当前能力仍无法满足这一需求,即使是容器原地升级,仍与这目标差距甚远。腾讯会议很多模块是往共享内存写入了大量数据的,发布过程中还要求共享内存数据不能丢失,并且各个实例的共享内存key是有可能冲突的。

经过多个方案的设计和对比,最终决定了如下方案是最具通用性、发布效率最高的。

Pod里面有3个关键容器,它们的职责分别如下:

  • biz-sidecar: Sidercar容器职责很简单,提供Pod是否在升级中。通过Readyness Probe比较EmptyDir Volume中的业务发布版本文件version1和version2的内容是否相等,相等则Ready,否则notReady。

  • biz-container:容器启动脚本会将环境变量(预注入)里的一个版本号写到versionX文件中,然后开始循环等文件锁,如果成功获取文件锁则启动业务进程。文件锁是防止Pod内同时运行多个版本的业务Container的关键,用文件锁来做不同版本容器的互斥。

  • biz-pause:启动脚本会将环境变量里的一个版本号写到versionX文件里,然后就进入无限sleep状态。这个容器是备用容器,当业务升级时,它就会通过原地升级的方式切换到biz-container的角色。

升级流程概述

以业务从版本V1升级到版本V2为例,阐述升级流程。

  1. 用户第一次部署业务,如上最左边的Pod, 一共有3个容器。biz-sidecar,biz-container(配置环境变量版本号为1)以及biz-pause(配置环境变量版本号为1)。所有2个容器启动之后会分别将version1, version2文件的内容更新为1,biz-sidecar此时为Ready。

  2. 更新Pod之前的biz-pause容器为业务V2版本的镜像同时环境变量版本号为2,等该容器原地升级之后把version2文件的内容更新为2之后开始等文件锁。此时biz-sidecar探针转为notReady状态。

  3. StatefulSet-Operator Watch到biz-sidecar为notReady之后再将之前的v1版本的业务镜像替换成biz-pause镜像同时环境变量版本号为2。等pause镜像容器原地重启之后会将之前v1业务镜像占的文件锁释放,同时version1内容更新为2。此时sidecar探针为Ready, 整个升级结束。

原生K8s apiserver只允许修改Pod的image等,不支持修改resource以及环境变量等,所以该方案需要改K8s apiserver的相关代码。
另外为了保证Pod request资源以及Pod qos不变,StatefulSetPlus-Operator在升级时需要对各阶段容器进行Resource调整。

StatefulSetPlus灰度发布能力再升级

支持单个StatefulSetPlus上万Pods的自动分批发布能力

TKEx-CSIG平台在原来StatefulSetPlus手动分配发布能力基础上,这次又开发了自动分批发布的特性,解决像腾讯会议这种大体量业务灰度发布的痛点。用户只要在发布时配置各个批次更新副本的百分比,比如第一批10%,第二批30%, 第三批30%,第四批30%。StatefulSetPlus-Operator会根据Readyness探针完成情况,自动进行下一批次的更新。

StatefulSetPlus Spec核心配置说明如下:

  • batchDeployConfig

    • batchNum:分几批升级

    • batchAuto:是否自动分批发布,true表示自动分批发布

    • batchIntervalMinutes:两次分批发布之间的间隔分钟数

    • podsNumToUpdate:各批次发布的pod数量,如果不设置则将pod平均到每批次发布

StatefulSetPlus对发布过程进行了精细化的监控,提供staus.batchDeployStatus查询发布详细状态,这使得通过CI Pipeline发布变得更显示和可控。

  • batchDeployStatus

    • action:当前操作,Next表示进行下一批发布,WaitToConfirm表示等待确认该批次发布是否成功,Completed表示所有批次均已确认发布成功。

    • batchDeadlineTime:本批次发布的Deadline,如果超过该时间,本批次的Pod仍然未Running & Ready,那么本批次发布失败,进入自动回滚流程

    • batchOrder:当前批次

    • batchOrdinal:本批次发布pod的Index的起点

    • batchReplicas:本批次发布的pod的数量

    • currentDeployComplete:本批次发布是否完成

    • currentOrderSuccessPer:成功升级的pod所占百分比

    • currentOrderProgress:本批次发布是否成功

    • currentRollbackProgress:本批次回滚是否成功

    • generalStatus:本批次发布状态

注:可在annotations加上:platform.stke/pause-auto-batchDeploy: "true" 暂停自动分批发布和失败自动回滚

TKEx-CSIG平台上,通过如下操作流程即可轻松完成自动分批发布。

腾讯会议最大的模块需要支持一万个Pods的灰度发布,这是前所未有的挑战。这一次,我们对StatefulSetPlus-Operator进行了优化,性能得到数倍的提升。对于一万个pod的StatefulSetPlus,分5批自动升级,单批次2000个pod,不挂载cbs盘的场景,表现如下:

  1. 非原地升级方式:单批次升级处理耗时40-45秒,单批次升级从发起升级到升级完成耗时三分半钟,升级过程中单次同步StatefulSetPlus status耗时10秒左右。
  2. 原地升级方式:单批次升级处理耗时30秒左右,单批次升级从发起升级到升级完成耗时一分十秒左右,升级过程中单次同步StatefulSetPlus status耗时10秒左右。
  3. 正常情况下(非升级过程),同步StatefulSetPlus status毫秒级。

支持ConfigMap的分批灰度发布和版本管理

Kubernetes原生的ConfigMap更新是一次性全量更新到容器内的对应的配置文件,所以通过原生的方式更新配置文件是极其危险的事情。代码通过镜像进行分批灰度发布,配置文件也应该有分批灰度发布的能力。

于是我们给StatefulSetPlus赋予了分批发布配置文件的能力,提升了云原生场景下配置文件发布的安全性,原理如下:

方案概述:

  • 用户修改ConfigMap后提交,后台自动创建一个新的ConfigMap,其中ConfigMap Name后缀是data内容的hash值,防止同样的data内容创建出多个ConfigMap,然后在Lable中添加没有data hash值的真正的ConfigMap名字,另外在lable中添加version,或者允许业务自定义一些lable以便标识ConfigMap的版本。
  • Kubernetes对Pod的修改只支持更新栏位 spec.containers[*].image, spec.containers[*].resources(if inplace resources update feature enabled), spec.initContainers[*].image, spec.activeDeadlineSeconds or spec.tolerations(only additions to existing tolerations),因此需要修改kube-apiserver代码,使得允许update/patch volumes。
  • 通过StatefulSetPlus的分批灰度发布能力,逐个批次的对Pods引用的ConfigMap进行修改,由kubelet volumemanager自动reload configmap,因此ConfigMap的更新不需要重建Pods。

为防止ConfigMap累积过多,影响etcd集群的性能,我们在自研组件TKEx-GC-Controller增加ConfigMap的回收逻辑,只保留最近10个版本的ConfigMap。

用户只要在更新Workload页面,选择手动分批或者自动分批更新,在数据卷选项重新选择新版本的ConfigMap即可。注意,可以在更新业务镜像的同时也更新ConfigMap配置文件,或者只更新ConfigMap配置文件。

ConfigMap配置文件更新,需要容器内业务进程能watch到配置文件的变更进行重启加载或者热加载。然而很多业务当前并没有这个能力,因此TKEx-CSIG后续会在ConfigMap发布的入口允许用户输入重启pod中相关进程的命令,由TKEx-CSIG调用用户指定的命令触发配置文件reload。

Coding OA已对接TKEx-CSIG进行自动分批发布

我们在第一时间和Coding OA进行了对接,Coding OA研发了对应的TKEx-CSIG更新镜像部署插件,支持通过TKEx-CSIG发布时使用StatefulSetPlus自动分批发布和状态查询, 腾讯会议部分模块已经在使用了,也欢迎大家使用,需要帮助可以找willionpan。

多地域部署和升级,变得更简单

业务部署时都会尽量进行多地域的容灾部署,TKEx-CSIG提供了便捷的多地域多集群业务部署和业务升级能力。

  • 支持一次性部署到多个地域多个集群,实现容灾部署。

  • 提供多个地域的容器统一视图。

  • 支持多个地域的Workload统一升级。

平台资源管理能力增强

腾讯会议全量上TKEx-CSIG完成之后,平台的规模至少要翻倍,资源量暴涨对平台的资源管理能力提出了更高的自动化要求。平台没有独立的预算池和资源池,这是一个很头疼的问题,会导致经常性的集群资源不足引起业务无法正常扩容等问题。

预算转移自动生成产品Quota

这次平台申请独立的子账号,业务通过公司OBS平台进行业务预算转移到TKEx-CSIG平台对应的子账号,具体的操作请参考TKEx CSIG 预算转移指南。完成预算转移后,平台将自动根据OBS的转账记录为业务所属运营产品增加对应的产品配额,用户可以在TKEx-CSIG监控面板查看归属产品的Cpu配额,配额不足时尽快进行预算转移操作。

业务核算自动化和可视化

TKEx-CSIG会以**核*时**为业务使用资源的计量粒度进行成本核算,并按照OBS平台要求进行上报,这样就完成了各个运营产品的核算。用户可以在TKEx-CSIG监控面板中查看具体的各个业务的详细资源使用情况。

扩容集群更高效

平台通过这种预算核算管理方式,就能建设平台大资源池,后面就能做更灵活的资源调度和管理的能力。解决了预算和核算的问题,还有一个关键问题就是做K8s集群的自动扩缩容能力。这需要云梯提供资源申请自动过单的能力,去除人工审批的环节,当然自动过单是要满足一定条件才允许的,比如集群负载是否达标、预算是否足够、是否在13周资源预测计划内等,具体的接口云梯正在研发,TKEx-CSIG将在第一时间进行对接,为自研业务提供底层资源的弹性能力。

上面只是对预算->生产资源->核算自动化流程的简单描述,具体实现还涉及很多细节问题,下面是完整的流程图。

容器网络和调度能力增强

容器网络支持固定EIP

TKEx-CSIG之前提供的VPC+ENI的Underlay网络方案,使得容器网络和CVM网络、IDC网络在同一网络平面,并且支持容器固定IP,极大地方便自研业务上云。

TEKx-CSIG平台的容器网络支持能力再升级,支持容器分配固定EIP的能力,腾讯会议接口机模块上TKE的痛点得到很好的解决。在安全合规的前提下 ,这个特性为那些需要为外网提供服务并且按外网IP进行鉴权的业务,提供了极大的便利。这解决了当前以NAT对外网暴露服务的方式,基于IP鉴权变的更透明,防止自研公共NAT集群扩容带来的IP变更无法及时通知业务。当然,我们也计划了将NAT IP提供在TKEx-CSIG监控面板中供业务查询。

调度优化

当后端集群资源池耗尽,会有大量的待调度的pending pods,此时使用任何类型的Workload进行镜像更新时都会出现升级失败的情况,为了解决这个问题,提升业务升级的稳定性,我们优化了Kubernetes Scheduler Cache的逻辑,给StatefulSet/StatefulSetPlus升级时提供了资源预抢占的调度能力,很好的保证了在不新增资源的情况下StatefulSet/StatefulSetPlus能正常升级成功。

注意:如果集群资源不足时,使用Deployment部署的业务仍可能面临升级失败的问题。再次强烈推荐大家使用StatefulSetPlus。

更多详细内容请参考:k8s调度优化之解决statefulset升级时资源被抢占的问题

稳定性

随着CVM上容器的部署密度越来越高,一些稳定性问题开始显现,为此TKEx-CSIG针对节点稳定性做了如下优化:

  • 主动探测dockerd的可用性,异常时主动重启dockerd,防止dockerd hung住导致Node上Pods自动销毁重建,

  • 主动监控kubelet的可用性,异常时主动重启kubelet,防止kubelet hung住导致Pods大量漂移重建。

  • 因为Kubernetes在pids.max, file-max等内核参数隔离机制不完善,在kubernetes 1.14中虽然支持了对Pods内Pids numbers的限制,但实际落地时很难为业务指定默认的pids limit。集群偶尔会出现因为节点Pids和file-max耗尽导致同一节点上其他业务容器受影响的问题。对此,我们在Node-Problem-Detector(简称NPD)组件中增加了节点pids,file-max的监控,达到相关资源使用水位线时,会自动驱逐节点,主动触发Pods漂移。

以上几项能力都在NPD组件中实现,负责监控节点的工作状态,包括内核死锁、OOM、系统线程数压力、系统文件描述符压力等指标,通过Node Condition和Event的形式上报给Apiserver。目前节点的自愈都是由Node-Problem-Detector自身完成的,未来我们将联动de-scheduler组件,根据NPD检测并上报的信息,提供更全面的重调度策略,比如考虑Workload的高可用等。

当前NPD组件会在节点中增加如下特定的Conditions:

Condition Type 默认值 描述
ReadonlyFilesystem False 文件系统是否只读
FDPressure False 查看主机的文件描述符数量是否达到最大值的80%
FrequentKubeletRestart False Kubelet是否在20Min内重启超过5次
CorruptDockerOverlay2 False DockerImage 是否存在问题
KubeletProblem False Kubelet service是否Running
KernelDeadlock False 内核是否存在死锁
FrequentDockerRestart False Docker是否在20Min内重启超过5次
FrequentContainerdRestart False Containerd是否在20Min内重启超过5次
DockerdProblem False Docker service是否Running(若节点运行时为Containerd,则一直为False)
ContainerdProblem False Containerd service是否Running(若节点运行时为Docker,则一直为False
ThreadPressure
False 系统目前线程数是否达到最大值的90%
NetworkUnavailable False NTP service是否Running
  • 当Node上频繁出现cgroup oom频繁时,可能触发tlinux进程无法获取spin_lock锁,出现mutex死锁,导致节点重启,该Bug在tlinux 3.10.107-1-tlinux2_kvm_guest-0049修复了,不过最好还是对Node cgroup oom做好统计监控。

  • tlinux 3.10.107-1-tlinux2_kvm_guest-0051版本在ext3/ext4+overlay文件系统中,会存在slab kmalloc-64内存耗尽问题,导致cvm挂死的问题,使用xfs+overlay的节点未出现此问题。

  • 我们使用的tlinux2版本存在dcache rename_lock死锁的问题,这会导致CVM被watchdog重启,最后tlinux为3.10.107-1-tlinux2_kvm_guest-00493.10.107-1-tlinux2_kvm_guest-0051两个版本提供了补丁进行了修复。需要补丁包的同学可以联系tlinux内核同学newtongao。

总结

简短的一篇文章,还不足以全面总结TKEx-CSIG为了支持腾讯会议全量容器化上云过程中一个多月的日月兼程!上云的征程还未结束,我们还需继续和会议研发、运维的同学们一起深耕计算存储分离、核心模块能按需弹性伸缩等课题,让腾讯会议更云原生!研发运营效率更高!这才是我们的终极目标。

展开阅读全文
打赏
0
0 收藏
分享
加载中
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部