作者
从2014年开始,腾讯游戏就逐步在生产环境中使用容器相关技术,到现在,代号为TenC的容器平台支撑了近200款游戏的运营。在这3年的时间里,整个平台经历了从最开始的“轻量级虚拟机”使用Docker的方式,到现在的原生容器云方式的迭代,接入的业务也由原来的在线服务扩展到现在的微服务、大数据、机器学习等类型。
2015年时,InfoQ记者曾对腾讯游戏进行过一次专访,在提到容器对于游戏业务的价值时,腾讯游戏高级工程师尹烨这样说道:“相比其他行业,游戏业务更为复杂多样,有端游、手游、页游之分,同时,还要分区和分服,甚至还要区分自研和代理。这些特性给运维和部署带来了诸多不便,而Docker统一的镜像分发方式,可以标准化程序的分发部署,提高交付效率。另外,游戏业务的生命周期长短不一,这也就需要弹性的资源管理和交付,而容器更加轻量,资源的交付和销毁更快。”
而在当时,Kubernetes刚刚发布1.0版本,尹烨也表示他们对于Kubernetes的应用还没有完全发挥其优势,接下来一段时间,他们也会探索容器平台与业务开发、运维的结合方式。那在时过境迁的两年之后,腾讯游戏在容器平台的实践方面又有哪些经验和心得?InfoQ记者再一次采访了尹烨。另外,尹烨也将会在CNUTCon全球运维技术大会上与参会者分享他们的经验教训。
InfoQ:2014年的时候腾讯游戏就开始在生产环境中使用了Docker,到现在已有3年时间。能否谈谈你们从最初的简单使用Docker到现在的容器云平台,这中间你们大致经历了哪几个阶段?
尹烨:现在我们的Docker容器平台(内部代号:TenC)主要支撑了如下三种类型的业务场景,也基本上对应了平台发展的三个阶段,每个阶段都是紧随着业务的需求在推进。
第一阶段:我们把容器当作轻量虚拟机来给业务使用,让业务程序不需要特殊修改,就可以在容器中正常运行起来,我们花了很多精力来兼容原有业务架构和使用习惯,以及保证底层运行环境的稳定运行;
第二阶段:后来在代理游戏中,出现一些微服务架构的业务,这些业务完全采用原生的Docker方式,基于Docker镜像来做分发和部署,弹性伸缩;
第三阶段: 再后来随着大数据和AI兴起,这类业务计算量非常大,资源需求要求高弹性,使用Docker容器来交付资源相对于原来物理机、虚拟机方式效率高很多。
InfoQ:目前腾讯游戏有多少的业务跑在容器云上?可否谈下你们的容器云技术栈?
尹烨:目前有过百款游戏业务都运行在容器上。在游戏业务接入容器平台前,会有一些评估要素。评估通过的话,新业务基本上会首选放到容器里。我们的平台主要基于Docker、Kubernetes(后面简称K8s)等开源组件开发的。当前Docker主要使用了1.12的版本,Kubernetes主要使用1.2/ 1.5版本。在实际的应用过程中,我们会基于我们自身的基础环境做一些二次定制开发,包括资源调度和网络部分,例如我们自己开发的SR-IOV CNI插件等。 整体结构大致如下:
其中TLinux是腾讯操作系统团队自研的服务器操作系统,操作系统团队针对Docker平台需求,进行了一系列内核特性研发和针对性改进。TLinux为游戏在Docker容器上的稳定运行奠定了基础。例如,
- cgroup高版本特性移植,如cgroup namespace, pids cgroup, cgroup支持IO隔离等;
- aufs、overlayfs特性移植;网络sysctl隔离;
- 其他诸如cgroup、overlayfs、xfs等等的bug修复。
InfoQ:记得2015年的时候你们是基于Kubernetes 0.4版本做的改造,现在Kubernetes也跟着升级了?升级之后之前哪些改动是怎么处理的?现在还有基于主干版本做定制吗?
尹烨:2014年我们开始使用Docker时,Google刚刚开源了K8s, K8s的设计非常精巧,我们就开始做了一些定制,来管理容器。我们现在还在使用那个古老的深度定制版本来管理我们的轻量级虚拟机容器,因为这类业务对编排没什么需求,为了保证平台的稳定,一直没有升级,将来也不太会。但针对微服务和离线计算这部分业务,我们没有太多侵入式的定制修改K8s,主要通过插件方式来扩展K8s,我们会根据自身的需求来跟随社区升级K8s。
在功能定制方面, 先大概介绍几点吧。比如,我们结合业务需求,和自身的基础环境,主要在调度和网络等方面进行了一些扩展。首先,在网络方面,我们开发了SRIOV CNI插件。
(1)母机上开启SRIOV功能,同时向网管系统申请子机IP资源,每个VF对应一个子机IP。
(2)Kubernetes在调度时,为每个Pod分配一个VF与子机IP。
(3)在Pod拿到VF与IP资源,进行绑定设置后,就可以像物理网卡一样使用。
同时我们也做了一些优化:比如将VF中断绑定到容器分配的CPU,并开启RPS,把网卡的软中断分到各个CPU处理,来提升网络性能。
其次,在调度方面,为了支持SRIOV插件,在容器调度中,除了K8S原生提供的CPU、Memory、GPU之外,我们还把网络(物理IP)也作为一种资源来调度,同时结合K8S提供的extender scheduler接口,我们定制了符合我们需求的调度程序(cr-arbitrator)。其结构如下:
cr-arbitrator做为extender scheduler,集成到K8S中,包括两部分内容:
(1)预选算法
在完成Kuernetes的predicates调度后,会进入到cr-arbitrator的预选调度算法,我们以网络资源为例,会根据创建的容器是否需要物理IP,从而计算符合条件的node(母机)。
(2)优选算法
在整个集群中,需要物理IP的容器与Overlay网络的容器并未严格的划分,而是采用混合部署方式,所以在调度Overlay网络的容器时,需要优化分配到没有开启SRIOV的node上,只有在资源紧张的情况下,才会分配到开启SRIOV的node上。
除了cr-arbitrator实现的调度策略外,我们还实现了CPU核绑定。容器在其生命周期内使用固定的CPU核,一方面是避免不同业务CPU抢占问题;另一方面在稳定性、性能上(结合NUMA)得到保障及提升,同时在游戏业务资源核算方面会更加的清晰。
InfoQ:内部有游戏开始使用微服务架构了?你们的容器云平台是如何支撑微服务架构的?
尹烨:腾讯游戏主要分两部分,一部分是代理的,另外一部分是自研的。对于自研的业务,经历那么多年的沉淀,有一套非常成熟的框架和运营体系。微服务架构带来的变化比较大,已有的业务架构转过来成本太高。
而代理游戏进行架构的转变,相比而言成本会低很多。所以,一些新的代理业务往往会采用微服务架构。今年开始,我们内部也有一些在线业务也在开始这方面的尝试,我想后面这种业务会越来越多的。
这些业务本身的架构使得业务很容易在容器上运行。另外,如果业务需要使用K8s的一些高级特性,比如服务发现、自动扩缩容机制等,则需要业务在架构上和实际部署时做一些简单的适配,这些适配都比较简单。
相对于轻量虚拟机,微服务的业务在网络、监控、日志等方面有较大的不同。
首先是网络部分,受限于底层物理网络,业务的容器不再每个容器一个物理IP(这会消耗大量的内网IP资源,而且管理也不方便),所以,我们使用了Overlay的网络方案,将容器的网络与底层物理网络解耦。业务的逻辑部分的容器都会跑在Overlay网络上,但是业务的数据层服务,比如MySQL,Redis之类的,仍然跑在物理网络上,Overlay与数据层之间通过NAT访问。同时,接入层通过内部LB对接外部网关,分离网关与业务服务。大致结构如下:
其次是监控与告警,对于微服务业务,无法使用原来的监控方案。而监控、告警是整个游戏运营过程中最为核心的功能之一,在游戏运行过程中,对其性能进行收集、统计与分析,来发现游戏模块是否存在问题,负载是否过高,是否需要扩缩容之类等等。在监控这一块,我们在cAdvisor基础上进行定制,其结构如下:
(1)每个母机部署cAdvisor程序,用于收集母机上容器的性能数据,比如CPU使用情况、memory、网络流量、TCP连接数等。
(2)在存储方面,目前直接写入到TenDis中,后续如果压力太大,还可以考虑在TenDis前加一层消息队列,例如Kafka集群。
(3)Docker-monitor,是基于cAdvisor收集的数据而实现的一套性能统计与告警程序。在性能统计方面,除了对每个容器的性能计算外,还可以对游戏的每个服务进行综合统计分析,一方面用于前端用户展示,另一方面可以以此来对服务进行智能扩缩容。告警方面,用户可以按业务需求,配置个性化的告警规则,docker-monitor会针对不同的告警规则进行告警。
最后,是业务日志的处理。Docker在容器日志处理这一块,目前已很丰富,除了默认的json-file之外,还提供了gcplogs、awslogs、fluentd等log driver。而在我们的日志系统中,还是简单的使用json-file,一方面容器日志并非整个方案中的关键节点,不想因为日志上的问题而影响Docker的正常服务。
另一方面,把容器日志落地到母机上,接下来只需要把日志及时采集走即可,而采集这块方案可以根据情况灵活选择,可扩展性强。我们当前选择的方案是Filebeat + Kafka + Logstash + ElasticSearch,其结构如下:
我们以DaemonSet方式部署Filebeat到集群中,收集容器的日志,并上报到Kafka,最后存储到Elasticsearch集群,整个过程还是比较简单。而这里有个关键点,在业务混合部署的集群中,通过Filebeat收集日志时怎样去区分不同的业务?而这恰恰是做日志权限管理的前提条件,我们只希望用户只能查看自己业务的日志。以下是具体的处理方案与流程:
(1)首先我们在Docker日志中,除了记录业务程序的日志外,还会记录容器的name与namespace信息。
(2)接着我们在Filebeat的Kafka输出配置中,把namespace作为topic进行上报,最终对应到Elasticsearch的index。
(3)在我们的平台中,一个namespace只属于一个业务,通过namespace,可以快速的搜索到业务对应的日志,通过容器的name,可以查看业务内每个模块的日志。
InfoQ:这么长时间的应用,有做过复盘吗?未来有什么计划?
尹烨:我们一直致力于为游戏业务提供高效的计算资源。从轻量虚拟机,到微服务,再到离线计算,我们一直紧随业务的场景往前演进。特别是弹性计算场景,相对于原来交付物理机/虚拟机的方式,现在基于容器的方式更加高效。我们希望在满足业务对计算资源需求的同时,尽可能提高资源的利用率,从而降低运营成本。我们会一直朝这个目标努力。
具体来说,整个平台也还有很多需要改进和优化的地方。比如,网络方面,我们希望简化外部网关的接入,进一步提升底层overlay网络的性能。优化资源调度策略,考虑更多的一些因素,比如任务优先级、任务运行时长等,将在线业务与离线业务混合部署等。
InfoQ:这一次的CNUTCon全球运维技术大会上,你将会为参会者分享哪些技术点?
尹烨:这次会上,我会分享腾讯游戏业务的各种应用场景,详细介绍我们的Docker容器平台(TenC)的架构和技术方案,跟大家交流一些容器的实践经验和体会。
转自 http://www.infoq.com/cn/news/2017/08/Tencent-game-container-cloud-pla