Docker在Bilibili的实战:由痛点推动的容器化

数人云上海&深圳两地“容器之Mesos/K8S/Swarm三国演义”的嘉宾精彩实录持续更新^_^今天小数带来的是Bilibili运维开发工程师吴佳兴的分享。相信不少小伙伴都是B站的粉丝,快来看看他们在业务高峰是如何利用容器技术应对各种压力的吧。

吴佳兴,Bilibili运维开发工程师 同时也是Dockone.io社区译者,在配置管理、运维自动化、Python开发、CICD及容器方面有一定经验。

今天主要讲B站在Docker的一些收获和实践经验。我叫吴佳兴,现任Bilibili运维开发工程师,同时也是dockone.io 社区翻译,过去做过Salt配置管理、基础运维,目前工作重点是容器方面的一些建设。Bilibili是一家弹幕视频网站,深耕于垂直领域,流量可观,有一亿的活跃用户,100万的活跃UP主,主要做直播、游戏、视频等。

上图是本次演讲的纲要, B站定位是一家创业型的公司,并不是为了容器化而容器化,使用容器技术是为了解决问题。B站在2015年曾做过容器的尝试,把SLB的节点容器化,当时用的版本是1.9,去年8月份重点评估了能否解决线上或者测试环境遇到的问题。

Problems:很多……

主要存在如下列出的问题。首先应用部署不够标准化,有很多历史存留的问题,有些应用是supervisord跑起来的,有些应用没有服务脚本,而且物理机上的混布非常严重,比如直播弹幕的一些消息组件在业务高峰的时候把物理机打爆,其他的应用可能会误伤掉。B站也分BU,各个业务方有调用的关系,这个调用的关系在测试环境没有一个稳定的集成环境来做集成测试,也是需要解决的。

B站经常遇到测试环境炸了的情况,这是运维一直比较头疼的问题,也是推动容器的一个出发点,即用故障或者是痛点来推动,这样的推动进程会更快一点,解决方案自然就是容器化。

解决方案:Jenkins married Mesos!

如何产出镜像,是首先要解决的问题。有两种方案,一种是运维帮忙做好镜像,可以直接用,但是代码没有办法打包进去,B站选择的方案是用Jenkins加上 Mesos来做动态可扩缩的CI基础设施,实际用到的组件核心是Mesos plugin, Jenkins-Master可以通过Mesos plugin在Mesos Master起一个Jenkins framework,framework是一个调度层,可以在Mesos Slave上进行调度和决策,用Mesos Plugin组件相当于在Slave上动态地起Jenkins Slave进行构建,主要的构建就是从Gitlab push触发第一次构建。构建用到了Jenkins2.0的Pipeline,就是Pipeline as Code,所有都可以用groovy脚本实现。我们会为每一种语言都定制一种Pipeline模版。

这是实际运行情况的截图,指定Jenkins Slave在Mesos上面起起来,并且定义环境变量,一些用来做构建的变量,调用Pipeline实现镜像的产出,通过它可以直接构建镜像。另外,Jenkins2.0也有非常多值得吸引人的特性,因为Jenkins在1.0的时候是主打是CI部分,2.0重点在CD部分有耕耘,主要是并发测试包括与Docker的结合。Jenkins Pipeline会分为几个步骤,从构建、打包、Docker build以及最终在Marathon运行起来。

B站测试环境一直面临一个问题。举例来说,一个依赖服务有一个V1的稳定版本,假如这个依赖服务需要进行迭代,发布V2版本,但在集成环境发布V2版本,其他的依赖方调用可能会有问题。B站的做法与业界没有大差异,即做一些环境的区分。如果使用容器化基础设施,环境的区分会非常的弱化,可以简单理解为在Slave上有一个环境的属性,attribute就是Env等于UAT或者FAT。B站做到了一个效果,在跑完单元测试后,根据用户的需求,去部署到FAT环境或者是UAT环境,为每一个跑起来的API对应地绑上一个DNS的域名,比如功能测试环境想访问集成环境的服务,可以通过Add-host的方式进行访问。此外,从集成环境到生产环境是有一个tag image的过程,在集成环境产出的镜像,经过测试通过的步骤,经过retag的方式,最后产出一个正式环境可以用的镜像。

容器化基础运行设施

为了支撑这套构建以及实际容器的运行,需要建设容器化的基础运行设施,在CI方面最终的产出物是一个镜像,如何支撑它的运行?首先是服务发现。因为Docker容器是飘动的,要做到在LB上可发现。B站使用的Consul,即Marathon的app在启动的时候会有instance出来,我们会监听Marathon的eventbus,并把这个事件记录到Consul里面,同时对应的会有一个APP-LB,在上面绑定一个consul template做动态渲染,实现服务的注册和服务发现。

容器监控,之前也有调研过Cadvisor、普罗米修斯之类。因为一些痛点,B站最终选择的方案是自研,主要是收集基础层面的还有应用层面的监控数据,应用层面可以复用现有的部分,比如代码埋点或者定期采集的数据,这里提供一个自研的monitor agent,可以通过Docker exec的方式去采集容器的监控数据,然后打到influxdb并用grafana做展示。

网络也是做容器的时候一个令人苦恼的问题,B站之前花了很多时间在网络选型方面做调研,最终选择的方案是Macvlan。调研过VXLAN、Calico,最终选择Macvlan的原因是因为VXLAN做过压力测试,发现私有云方面覆盖网络的损耗比较大。如果使用Calico的话要做一个BGP网络,当时网络工程师否决了这个建议,最终选择了Macvlan这个损耗和侵入性比较小的方式。我们自研了一个ipam plugin,因为Docker12开始就支持network plugin,可以通过ipam plugin来实现IP地址的管理,并且注册到consul。

Logging方面比较简单。Docker提供log driver,通过syslog的方式打到远端。另外APP应用层面的一些日志,直接与原有的VM一样,用UDP或者是TCP打到Flume。

Registry没有使用Harbor,目前是LVS后面挂了两台Docker Registry,registry是V2版本。也遇到一些痛点,比如镜像,Docker Registry V2版本之前许诺使可以实现镜像完全删除的,但Docker官方也说暂时还没有实现这一点,如果要完全删除一个镜像,还需要通过GC的手段,目前在考虑Habor,因为Harbor可以实现很关键的一点就是镜像权限的区分。

B站开发了一套BiliPaaS管理工具,做用户的入口或者是镜像发布的需求,包括镜像的管理,并开发了一个Web Console直接登录到容器进行操作,包括监控、告警、配置等。 Jenkins发布出来的镜像,打到集成环境之后,通过retag,retag成v5.1.3,在生产环境做一个灰度发布的界面。容器Console可以在Web上进行编辑。

Autoscale,即弹性扩缩,目前决策的依据监控数据是基础的监控数据,也做过一些尝试,发现不太理想,因为CPU跟memory飙升很可能是异常情况造成的,并不是业务的上升导致的,后期会考虑加入QPS,SLB或者CDN层面的监控数据业务层面来做这个Autoscale决策。

在容器的基础设施建设过程中,B站遇到了很多问题。我们使用的是1.12,在3.16的使用过程中发现内核CFS支持的时候会有一个crash的情况,只能升到4.4.27,但是4.4.27已经把AUFS默认的内置给取消掉了,于是只能被迫升到了overlayfs2,overlayfs2也遇到了问题,XFS与overlayfs2搭配起来后,比如镜像,会出现镜像文件的损坏,还有Docker registry删除的问题,以及Docker自身的问题、Mesos的问题,刚才提到的Jenkins拉起过程中也遇到一些坑,它会突然拉不起来了,变得不可控,因为是Mesos Plugin直接通过Jenkins Framework调用的。

后期展望

B站会通过QPS的业务层指标实现弹性扩缩,另外想引入Harbor做开发环境的即开即用,这方面开发已经提过需求,比如希望消费镜像,在开发环境做开发。B站目前实现的是web服务和无状态服务容器化,如大数据无状态服务的容器化,一些TCP应用包括Cache、MQ还没有实现容器化。B站会有短暂性的业务高峰或者是波动性的数次高峰,需要进行弹性扩缩,这方面也在调研,做混合云方面的基础建设。

分享就到这里,谢谢大家。