自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为例,阐述升级流程。
-
用户第一次部署业务,如上最左边的Pod, 一共有3个容器。biz-sidecar,biz-container(配置环境变量版本号为1)以及biz-pause(配置环境变量版本号为1)。所有2个容器启动之后会分别将version1, version2文件的内容更新为1,biz-sidecar此时为Ready。
-
更新Pod之前的biz-pause容器为业务V2版本的镜像同时环境变量版本号为2,等该容器原地升级之后把version2文件的内容更新为2之后开始等文件锁。此时biz-sidecar探针转为notReady状态。
-
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盘的场景,表现如下:
- 非原地升级方式:单批次升级处理耗时40-45秒,单批次升级从发起升级到升级完成耗时三分半钟,升级过程中单次同步StatefulSetPlus status耗时10秒左右。
- 原地升级方式:单批次升级处理耗时30秒左右,单批次升级从发起升级到升级完成耗时一分十秒左右,升级过程中单次同步StatefulSetPlus status耗时10秒左右。
- 正常情况下(非升级过程),同步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-0049
和3.10.107-1-tlinux2_kvm_guest-0051
两个版本提供了补丁进行了修复。
总结
简短的一篇文章,还不足以全面总结TKEx-CSIG为了支持腾讯会议全量容器化上云过程中一个多月的日月兼程!上云的征程还未结束,我们还需继续和会议研发、运维的同学们一起深耕计算存储分离、核心模块能按需弹性伸缩等课题,让腾讯会议更云原生!研发运营效率更高!这才是我们的终极目标。