DockOne微信分享(八十四):Docker在B站的实施之路

本文涉及的产品
应用型负载均衡 ALB,每月750个小时 15LCU
网络型负载均衡 NLB,每月750个小时 15LCU
传统型负载均衡 CLB,每月750个小时 15LCU
简介: 本文讲的是DockOne微信分享(八十四):Docker在B站的实施之路【编者的话】B站一直在关注Docker的发展,去年成功在核心SLB(Tengine)集群上实施了Docker。今年我们对比了各种Docker实施方案后选择了Mesos。
本文讲的是DockOne微信分享(八十四):Docker在B站的实施之路【编者的话】B站一直在关注Docker的发展,去年成功在核心SLB(Tengine)集群上实施了Docker。今年我们对比了各种Docker实施方案后选择了Mesos。结合CI&CD,打通了整个业务的Docker上线流程,并实现了全自动扩缩容。这次结合我们的实施之路,分享一下遇到的重点与难点:
  1. 自研Docker网络插件的介绍;
  2. Bili PaaS平台中的CD实现与优化;
  3. 应用全自动扩缩容的实现方案;
  4. Nginx动态Upstream跟Docker的配合使用。

B站一直在关注Docker的发展,去年成功在核心SLB(Tengine)集群上实施了Docker,规模不大但访问量大、没有CI & CD的工作。随着业务量的增长,应用扩缩需求越来越多。但在没有docker标准化的情况下,应用扩容需要扩服务器,操作繁重。同时为了减少因测试、线上环境不一致导致的问题,我们计划将业务全部Docker化,并配合CI & CD,打通整个业务上线流程,达到秒级动态扩缩容。

下面是我们的实施之路,整体架构图如下:
图片1.png

为什么选择Mesos?

Kubernetes太重,功能繁多。我们主要看中Mesos的调度功能,且轻量更易维护。另外和我们选择了Macvlan的网络有关。

Docker网络选择

Docker自带的网络都不能满足我们的需求。

Bridger :Docker分配私有IP,本机通过bridge跟容器通信。不同宿主机如果要通信需要iptables映射端口。随着容器的增多,端口管理会很混乱,iptables规则也越来越多。

Host :使用宿主机的网络,不同容器不能监听相同端口。

None :Docker不给容器分配网络,手动分配。

正当我们无法选定Docker的网络方案时,发现最新的Docker 1.12版本提供了另外两种网络驱动:Overlay和Macvlan。

Overlay :在原来的TCP/IP数据包基础上再封装成UDP的数据包传输。当网络出现问题需要抓包时,会比较麻烦。而且,Overlay依靠服务器的CPU来解UDP数据包,会导致Docker网络性能非常不稳定,性能损耗比较严重,在生产环境中难以使用。

Macvlan :在交换机上配置VLAN,然后在宿主机上配置物理网卡,使其接收对应的VLAN。Docker在创建Network时driver指定Macvlan。对Docker的Macvlan网络进行压测,跑在Macvlan网络的容器比跑在host网络的容器性能损失10~15%左右,但总体性能很稳定,没有抖动。这是能接受的。

基于Macvlan,我们开发了自己的IPAM Driver Plugin—底层基于Consul。
Docker在创建Macvlan网络时,驱动指定为自己研发的Consul。Consul中会记录free和used的IP。如下图:
图片2.png

IPAM Driver在每台宿主机上都存在,通过Socket的方式暴露给Docker调用。Docker在创建容器时,IPAM Plugin会从Consul申请一个free的IP地址。删除容器时,IPAM Plugin会释放这个IP到Consul。因为所有宿主机上的IPAM Plugin连接到的是同一个Consul,就保证了所有容器的IP地址唯一性。

我们用IPAM Plugin遇到的问题:

1)  Consul IPAM Plugin在每台宿主机上都存在,通过Socket方式调用,目前使用容器启动。

当Docker daemon重启加载Network时,因为容器还未启动,会找不到Consul IPAM Plugin的Socket文件,导致Docker daemon会去重试请求IPAM,延长daemon的启动时间,报错如下:
level=warning msg="Unable to locate plugin: consul, retrying in 1s"
level=warning msg="Unable to locate plugin: consul, retrying in 2s"
level=warning msg="Unable to locate plugin: consul, retrying in 4s"
level=warning msg="Unable to locate plugin: consul, retrying in 8s"
level=warning msg="Failed to retrieve ipam driver for network \"vlan1062\"


解决方案 :Docker识别Plugin的方式有三种:
  1. sock files are UNIX domain sockets.
  2. spec files are text files containing a URL, such as unix:///other.sock or tcp://localhost:8080.
  3. json files are text files containing a full json specification for the plugin.

最早我们是通过.sock的方式识别IPAM Plugin。现在通过.spec文件的方式调用非本地的IPAM Plugin。这样Docker daemon在重启时就不受IPAM Plugin的影响。

2)  在通过Docker network rm 删除用Consul IPAM创建的网络时,会把网关地址释放给Consul,下次创建容器申请IP时会获取到网关的IP,导致网关IP地址冲突。

解决方案 :在删除容器释放IP时,检测下IP地址,如果是网关IP,则不允许添加到Consul的free列表。

基于以上背景,我们刚开始选型的时候,测试过Docker 1.11 + Swarm 和Docker 1.12集成的SwarmKit。Docker 1.11 + Swarm网络没有Macvlan驱动,而Docker 1.12集成的SwarmKit只能使用Overlay网络,Overlay的性能太差。最终我们采用了Docker 1.12 + Mesos。

CI & CD

对于CI,我们采用了目前公司中正在大量使用的Jenkins。 Jenkins通过Pipeline分为多个step,step 1 build出要构建war包。Step 2 build Docker 镜像并push到仓库中。

第一步: build出想要的war,并把war包保存到固定的目录。第二步:build docker镜像,会自动发现前面build出的war包,并通过写好的Dockerfile build镜像,镜像名即为应用名。镜像构建成功后会push到我们的私有仓库。每次镜像构建都会打上一个tag,tag即为发布版本号。后续我们计划把CI从jenkins独立出来,通过自建的Paas平台来build war包和镜像。
图片3.png

我们自研了基于Docker的PaaS平台(持续开发中)。该平台的功能主要包括信息录入、应用部署、监控、容器管理、应用扩缩等。CD就在Paa上。
图片4.png

当要部署一个新的业务系统时,要先在Paas系统上录入应用相关信息,比如基础镜像地址、容器资源配置、容器数量、网络、健康检查等
图片5.png

CD时,需要选择镜像的版本号,即上文提到的tag
图片6.png

我们同时支持控制迭代速度,即迭代比例的设置
图片7.png

这个设置是指,每次迭代20%的容器,同时存活的容器不能低于迭代前的100%。

我们遇到的问题: 控制迭代比例。

Marathon有两个参数控制迭代比例:
  • minimumHealthCapacity(Optional. Default: 1.0)处于health状态的最少容器比例;
  • maximumOverCapacity(Optional. Default: 1.0)可同时迭代的容器比例。

假如有个Java应用通过Tomcat部署,分配了四个容器,默认配置下迭代,Marathon可以同时启动四个新的容器,启动成功后删除四个老的容器。四个新的Tomcat容器在对外提供服务的瞬间,因为请求量太大,需要立即扩线程数预热,导致刚进来的请求处理时间延长甚至超时(B站因为请求量大,请求设置的超时时间很短,在这种情况下,请求会504超时)。

解决方法:

对于请求量很大需要预热的应用,严格控制迭代比例,比如设置maximumOverCapacity为0.1,则迭代时只能同时新建10%的容器,这10%的容器启动成功并删除对应老的容器后才会再新建10%的容器继续迭代。

对于请求量不大的应用,可适当调大maximumOverCapacity,加快迭代速度。

动态扩缩容

节假日或做活动时,为了应对临时飙高的QPS,需要对应用临时扩容。或者当监控到某个业务的平均资源使用率超过一定限制时,自动扩容。我们的扩容方式有两种:1、手动扩容;2、制定一定的规则,当触发到规则时,自动扩容。我们的Bili PaaS平台同时提供了这两种方式,底层是基于Marathon的Scale API。这里着重讲解下基于规则的自动扩缩容。

自动扩缩容依赖总架构图中的几个组件:Monitoring Agent、Nginx+UpSync+Consul、Marathon Hook、Bili PaaS。

Monitor Agent: 我们自研了Docker的监控Agent,封装成容器,部署在每台Docker宿主机上,通过docker stats的接口获取容器的CPU、内存、IO等信息,信息录入InfluxDB,并在Grafana展示。

Bili PaaS: 应用在录入PaaS平台时可以选择扩缩容的规则,比如:平均CPU > 300% OR MEM > 4G。PaaS平台定时轮询判断应用的负载情况,如果达到扩容规则,就按一定的比例增加节点。本质上是调用Marathon的API进行扩缩。

Marathon Hook: 通过Marathon提供的/v2/events接口监听Marathon的事件流。当在Bili PaaS平台手动扩容或触发规则自动扩容时,Bili Paas平台会调用Marathon的API。Marathon的每个操作都会产生事件,通过/v2/events接口暴露出来。Marathon Hook程序会把所有容器的信息注册到Consul中。当Marathon删除或创建容器时,Marathon Hook就会更新Consul中的Docker容器信息,保证Consul中的信息和Marathon中的信息是一致的,并且是最新的。

Nginx+UpSync+Consul: 当Marathon扩容完成时,新容器的IP:PORT一定要加到SLB(Tengine/Nginx)的Upstream中,并reload SLB后才能对外提供服务。但Tengine/Nginx reload时性能会下降。为了避免频繁reload SLB导致的性能损耗,我们使用了动态Upstream:Nginx + UpSync + Consul。Upsync是Weibo开源的一个模块,使用Consul保存Upstream的server信息。Nginx启动时会从Consul获取最新的Upstream server信息,同时Nginx会建立一个TCP连接hook到Consul,当Consul里的数据有变更时会立即通知到Nginx,Nginx的worker进程更新自己的Upstream server信息。整个过程不需要reload nginx。注意:UpSync的功能是动态更新upstream server,当有vhost的变更时,还是需要reload nginx。

我们遇到的问题:

1)  Nginx + UpSync 在reload时会产生shutting down。因为Nginx Hook到Consul的链接不能及时断开。曾在GitHub上因这个问题提过issue,作者回复已解决。个人测试发现shuttding down还是存在。并且UpSync和Tengine的http upstream check模块不能同时编译。

解决方案:Tengine + Dyups。我们正在尝试把Nginx + Dyups替换为Tengine + Dyups。Dyups的弊端就是Upstream信息是保存在内存里的。Reload/Restart Tengine时就会丢失。需要自己同步Upstream信息到磁盘中。基于此,我们对Tengine + Dyups做了封装,由一个代理进程Hook Consul,发现有更时则主动更新Tengine,并提供了Web管理界面。目前正在内部测试中。

2) Docker Hook —> Marathon Hook,最早我们是去Hook Docker的events。这需要在每台宿主机上起一个Hook服务。当应用迭代时,Docker会立即产生一个create container的事件。Hook程序监控到后去更新Consul,然后Consul通知Nginx去更新。导致问题就是:容器里的服务还没启动成功(比如Tomcat),就已经对外提供服务了。这会导致很多请求失败,产生重启请求。

解决方案: Marathon Hook。Marathon中有一个health check的配置。如下图
图片8.png

我们规定所有的Web服务必须提供一个Health Check接口,这个接口随着服务一同起来,这个接口任何非200的http code都代表应用异常。Marathon刚启动容器时,显示此容器的Health状态是uknow。当Health Check成功时,Marathon显示此容器的Health状态Healthy,并会产生一个事件。Marathon Hook程序通过Hook这个事件,就能准确捕获容器中应用启动成功的时间,并更新Consul,同步Nginx,对外提供服务。

3) Marathon Failover后会丢失command health check,通过Marathon给容器添加Health Check时,有三种方式可以选择:HTTP TCP COMMAND
图片9.png

当使用HTTP TCP时,Check是由Marathon发起的,无法选择Check时的端口,Marathon会用自己分配的PORT进行Check。实际上我们并未使用marathon映射的端口。我们选择了COMMAND方式,在容器内部发起curl请求来判断容器里的应用状态。当Marathon发生failover后,会丢失COMMAND health check,所有容器状态都显示unknow。需要重启或者迭代应用才能恢复。

Q&A

Q:你好 问下贵公司的自动扩容是针对应用的吧 有没有针对Mesos资源池监控并做Mesos Agent的扩容?
A:目前的自动扩容是针对应用的。Mesos Agent扩容时,先把物理机信息录入PaaS平台,手动在PaaS平台点击扩容,后台会调用Ansible,分钟快速级扩Mesos Agent。
Q:现在是确定Nginx+UpSync+Upsteam check是无法一起用的么?贵公司的Nginx版本是多少哇?
A:测试过Nginx 1.8和1.10,确认无法一同编译。我们用的最多的Nginx(SLB)是Tengine 2.1.1,部署在Docker上。
Q:既然是封装, 那底层用Mesos比Kubernets并没有太大的灵活性吧?
A:对于PaaS平台,目前我们希望的只需要资源调度这个功能,其他功能我们还是希望可以自己实现,而Mesos是专注于调度资源,而且已经历经了大量级的考验。而Kubernetes目前提供的很多服务,我们并不需要,所以选择了Mesos。
Q:容器是采用Monitor Agent监控,那容器内的呢?也还是内部埋点?还是EFK吗?监控是采用Prometheus吗?
A:Prometheus没有使用,我们是用自己的监控Agent -> InfluxDB。容器内有多种监控方式。有用ELK,也有其他埋点,比如StatsD,基于Dapper论文实现的全链路追踪。
Q:网络选型这块,还调研过其他网络方案吗?譬如Calico、Weave等,为什么会选用Macvlan?
A:我们的选型第一步是先选择标准的,要从CoreOS主导的cni还是Docker官方主导cnm里面选择,目前由于我们容器方案还是走的Docker,所以选择了cnm,那从cnm的标准里面的选择基本是:1. 基于XVLAN的Overlay;2. 基于三层路由的Calico;3. 基于二层隔离的Macvlan,实际以上的方案我们都调研使用过,基于希望尽量简单的原则最终选型还是Macvlan。
Q:Bili PaaS平台,自动扩容和手动扩容,应用多的是哪种方式?自动扩容后,资源会重调度么?是否会中断已有业务呢?
A:用的更多的是根据制定好的策略,自动扩容。通过Nginx 动态Upstream对外提供服务,不会中断业务。
Q:关于日志收集每个容器里都跑一个Logstash吗?好像ELK不能搜索展示上下文的啊?
A:容器里面没有跑Logstash。目前是在远端的Logstash集群上监听一个UDP端口,应用直接把日志推送到Logstash的UDP端口,然后Logstash把日志推送到Kafka,Kafka的消费者有两个,一个是Elasticsearch,一个是HDFS。一般用ELK足以。需要详细日志时,由运维通过HDFS查询。
Q:我想请教下Nginx的一些动态配置文件是封装在容器内部了?还是通过volume的方式挂载了?有没有配置中心类似的服务?这块想了解下是怎么实现的?
A:Nginx的Upstream是从Consul动态获取生成在本地的,通过Volume挂载,持久化到宿主机。有配置中心。业务Docker化时,就会推动业务配置接配置中心,Docker中不在保存业务依赖的配置。

以上内容根据2016年9月27日晚微信群分享内容整理。分享人武安闯,Bilibili 运维工程师,目前主要负责B站运维和业务Docker化的实施。一直关注于Docker的发展,Docker与Mesos结合的容器平台实施 。DockOne每周都会组织定向的技术分享,欢迎感兴趣的同学加微信:liyingjiesz,进群参与,您有想听的话题或者想分享的话题都可以给我们留言。

原文发布时间为:2016-09-29

本文作者:武安闯

本文来自云栖社区合作伙伴Dockerone.io,了解相关信息可以关注Dockerone.io。

原文标题:DockOne微信分享(八十四):Docker在B站的实施之路

相关实践学习
小试牛刀,一键部署电商商城
SAE 仅需一键,极速部署一个微服务电商商城,体验 Serverless 带给您的全托管体验,一起来部署吧!
负载均衡入门与产品使用指南
负载均衡(Server Load Balancer)是对多台云服务器进行流量分发的负载均衡服务,可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性。 本课程主要介绍负载均衡的相关技术以及阿里云负载均衡产品的使用方法。
相关文章
|
Kubernetes 物联网 数据中心
DockOne微信分享( 九十五):树莓派上的Docker集群管理
本文讲的是DockOne微信分享( 九十五):树莓派上的Docker集群管理【编者的话】随着IOT市场的火热发展,Docker天然的轻量级以及帮助业务快速重构的特性,将会在IOT领域迎来巨大发展潜力,甚至有可能会比它在云端的潜力更大。
3473 0
|
运维 Devops 测试技术
DockOne微信分享(六十四):基于Docker实现DevOps的一些探索
本文讲的是DockOne微信分享(六十四):基于Docker实现DevOps的一些探索【编者的话】本次分享从DevOps介绍;Docker介绍;基于Docker实现DevOps的优势;Docker化DevOps流水线实例分享等四方面展开。
1025 0
|
监控 测试技术 API
DockOne微信分享(八十二):基于Docker技术的CI&CD实践
本文讲的是DockOne微信分享(八十二):基于Docker技术的CI&CD实践【编者的话】Docker技术应用广泛,可以将软件与其依赖环境打包起来,以镜像方式交付,让软件运行在“标准环境”中。这一特性可以应用到持续集成中,实现原生支持容器云平台持续交付。
2115 0
|
关系型数据库 UED 开发者
DockOne微信分享(八十七):基于Docker的开发云提高资源利用率的实践
本文讲的是DockOne微信分享(八十七):基于Docker的开发云提高资源利用率的实践【编者的话】Docker的出现,为更简便、更细粒度地对云资源的调控提供了一个强有力的支撑,WeX5开发者云基于Rancher+Docker,在如何提高物理资源利用率的课题上做了一些探索和研究,在保障用户体验良好的前提下,大大提高了物理资源的利用率,有效地降低了运营成本。
2182 0
|
存储 测试技术 数据库
DockOne微信分享( 八十八):PPTV聚力传媒的Docker与DevOps
本文讲的是DockOne微信分享( 八十八):PPTV聚力传媒的Docker与DevOps【编者的话】DevOps是2009年前后提出的一个概念,提倡开发(Development)和运维(Operations)这两个领域的高度协同。
2171 0
|
存储 监控 Docker
DockOne微信分享(一一零):Docker在沪江落地的实践
本文讲的是DockOne微信分享(一一零):Docker在沪江落地的实践【编者的话】容器化是很多公司技术层向往又惧怕的一项热门技术,它的高效性,封装性能给开发、运维带来许多便利,但其本身也需要较强的技术能力去控制,否则会变成一个无法落地的概念。
2616 0
|
负载均衡 网络协议 测试技术
DockOne微信分享(七十一):基于Docker的负载均衡和服务发现
本文讲的是DockOne微信分享(七十一):基于Docker的负载均衡和服务发现【编者的话】Docker已经成为时下热门的容器技术,各大公司,中小创业者,都选择采用Docker技术架构其下一代的系统和应用。
2383 0
|
Java 分布式数据库 数据库
DockOne微信分享(九十七):现有系统实施微服务架构改进经验分享
本文讲的是DockOne微信分享(九十七):现有系统实施微服务架构改进经验分享【编者的话】微服务是最近非常热门的话题了,它带来的好处吸引不少互联网公司对现有项目进行微服务架构改进。 本次分享是博主根据自身的项目经验,介绍如何对现有架构进行调整,总结这过程中的相关技术选型,以及如何实施技改,并分享最终取得的非常让人意外的成果。
1741 0
|
存储 监控 应用服务中间件
DockOne微信分享(一二七):Docker的另类用法,就是这么简单粗暴
本文讲的是DockOne微信分享(一二七):Docker的另类用法,就是这么简单粗暴【编者的话】现在业内一提到Docker就必然说到Kubernetes、Mesos。然后就提到重写Kubernetes、Mesos,优化Ubuntu内核等等。
1427 0
|
存储 应用服务中间件 测试技术
DockOne微信分享(一三二):58 赶集基于 Docker 的自动化部署实践
本文讲的是DockOne微信分享(一三二):58 赶集基于 Docker 的自动化部署实践【编者的话】随着 58 业务的发展,机器和服务数量也日益庞大,在多环境下,服务的管理和依赖难以维护。基于 Docker 带来的技术红利,我们借助 Docker 和 Kubernetes 提供了镜像的自动打包,单一镜像在测试-沙箱-生产-稳定四个环境的流转,以及测试环境统一的 Nginx 入口。
2292 0

热门文章

最新文章